1<?php 2 3namespace OAuth\Common\Http\Uri; 4 5use RuntimeException; 6 7/** 8 * Factory class for uniform resource indicators 9 */ 10class UriFactory implements UriFactoryInterface 11{ 12 /** 13 * Factory method to build a URI from a super-global $_SERVER array. 14 * 15 * @param array $_server 16 * 17 * @return UriInterface 18 */ 19 public function createFromSuperGlobalArray(array $_server) 20 { 21 if ($uri = $this->attemptProxyStyleParse($_server)) { 22 return $uri; 23 } 24 25 $scheme = $this->detectScheme($_server); 26 $host = $this->detectHost($_server); 27 $port = $this->detectPort($_server); 28 $path = $this->detectPath($_server); 29 $query = $this->detectQuery($_server); 30 31 return $this->createFromParts($scheme, '', $host, $port, $path, $query); 32 } 33 34 /** 35 * @param string $absoluteUri 36 * 37 * @return UriInterface 38 */ 39 public function createFromAbsolute($absoluteUri) 40 { 41 return new Uri($absoluteUri); 42 } 43 44 /** 45 * Factory method to build a URI from parts 46 * 47 * @param string $scheme 48 * @param string $userInfo 49 * @param string $host 50 * @param string $port 51 * @param string $path 52 * @param string $query 53 * @param string $fragment 54 * 55 * @return UriInterface 56 */ 57 public function createFromParts($scheme, $userInfo, $host, $port, $path = '', $query = '', $fragment = '') 58 { 59 $uri = new Uri(); 60 $uri->setScheme($scheme); 61 $uri->setUserInfo($userInfo); 62 $uri->setHost($host); 63 $uri->setPort($port); 64 $uri->setPath($path); 65 $uri->setQuery($query); 66 $uri->setFragment($fragment); 67 68 return $uri; 69 } 70 71 /** 72 * @param array $_server 73 * 74 * @return UriInterface|null 75 */ 76 private function attemptProxyStyleParse($_server) 77 { 78 // If the raw HTTP request message arrives with a proxy-style absolute URI in the 79 // initial request line, the absolute URI is stored in $_SERVER['REQUEST_URI'] and 80 // we only need to parse that. 81 if (isset($_server['REQUEST_URI']) && parse_url($_server['REQUEST_URI'], PHP_URL_SCHEME)) { 82 return new Uri($_server['REQUEST_URI']); 83 } 84 85 return null; 86 } 87 88 /** 89 * @param array $_server 90 * 91 * @return string 92 * 93 * @throws RuntimeException 94 */ 95 private function detectPath($_server) 96 { 97 if (isset($_server['REQUEST_URI'])) { 98 $uri = $_server['REQUEST_URI']; 99 } elseif (isset($_server['REDIRECT_URL'])) { 100 $uri = $_server['REDIRECT_URL']; 101 } else { 102 throw new RuntimeException('Could not detect URI path from superglobal'); 103 } 104 105 $queryStr = strpos($uri, '?'); 106 if ($queryStr !== false) { 107 $uri = substr($uri, 0, $queryStr); 108 } 109 110 return $uri; 111 } 112 113 /** 114 * @param array $_server 115 * 116 * @return string 117 */ 118 private function detectHost(array $_server) 119 { 120 $host = isset($_server['HTTP_HOST']) ? $_server['HTTP_HOST'] : ''; 121 122 if (strstr($host, ':')) { 123 $host = parse_url($host, PHP_URL_HOST); 124 } 125 126 return $host; 127 } 128 129 /** 130 * @param array $_server 131 * 132 * @return string 133 */ 134 private function detectPort(array $_server) 135 { 136 return isset($_server['SERVER_PORT']) ? $_server['SERVER_PORT'] : 80; 137 } 138 139 /** 140 * @param array $_server 141 * 142 * @return string 143 */ 144 private function detectQuery(array $_server) 145 { 146 return isset($_server['QUERY_STRING']) ? $_server['QUERY_STRING'] : ''; 147 } 148 149 /** 150 * Determine URI scheme component from superglobal array 151 * 152 * When using ISAPI with IIS, the value will be "off" if the request was 153 * not made through the HTTPS protocol. As a result, we filter the 154 * value to a bool. 155 * 156 * @param array $_server A super-global $_SERVER array 157 * 158 * @return string Returns http or https depending on the URI scheme 159 */ 160 private function detectScheme(array $_server) 161 { 162 if (isset($_server['HTTPS']) && filter_var($_server['HTTPS'], FILTER_VALIDATE_BOOLEAN)) { 163 return 'https'; 164 } else { 165 return 'http'; 166 } 167 } 168} 169