diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index d3982f83bb..00593ea64d 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -4,6 +4,7 @@ Yii Framework 2 Change Log 2.0.8 under development ----------------------- +- Enh #10451: Check of existence of `$_SERVER` in `\yii\web\Request` before using it (quantum13) - Enh #10610: Added `BaseUrl::$urlManager` to be able to set URL manager used for creating URLs (samdark) - Enh #10764: `yii\helpers\Html::tag()` and `::beginTag()` return content without any HTML when the `$tag` attribute is `false` or `null` (pana1990) diff --git a/framework/web/Request.php b/framework/web/Request.php index 18b9a6eee2..2833c2e9c5 100644 --- a/framework/web/Request.php +++ b/framework/web/Request.php @@ -42,7 +42,7 @@ use yii\helpers\StringHelper; * @property array $eTags The entity tags. This property is read-only. * @property HeaderCollection $headers The header collection. This property is read-only. * @property string $hostInfo Schema and hostname part (with port number if needed) of the request URL (e.g. - * `http://www.yiiframework.com`). + * `http://www.yiiframework.com`), null in case it can't be obtained from `$_SERVER` and wasn't set. * @property boolean $isAjax Whether this is an AJAX (XMLHttpRequest) request. This property is read-only. * @property boolean $isDelete Whether this is a DELETE request. This property is read-only. * @property boolean $isFlash Whether this is an Adobe Flash or Adobe Flex request. This property is @@ -69,8 +69,8 @@ use yii\helpers\StringHelper; * @property string $scriptFile The entry script file path. * @property string $scriptUrl The relative URL of the entry script. * @property integer $securePort Port number for secure requests. - * @property string $serverName Server name. This property is read-only. - * @property integer $serverPort Server port number. This property is read-only. + * @property string $serverName Server name, null if not available. This property is read-only. + * @property integer $serverPort Server port number, null if not available. This property is read-only. * @property string $url The currently requested relative URL. Note that the URI returned is URL-encoded. * @property string $userAgent User agent, null if not present. This property is read-only. * @property string $userHost User host name, null if cannot be determined. This property is read-only. @@ -526,7 +526,8 @@ class Request extends \yii\base\Request * The returned URL does not have an ending slash. * By default this is determined based on the user request information. * You may explicitly specify it by setting the [[setHostInfo()|hostInfo]] property. - * @return string schema and hostname part (with port number if needed) of the request URL (e.g. `http://www.yiiframework.com`) + * @return string schema and hostname part (with port number if needed) of the request URL (e.g. `http://www.yiiframework.com`), + * null if can't be obtained from `$_SERVER` and wasn't set. * @see setHostInfo() */ public function getHostInfo() @@ -536,7 +537,7 @@ class Request extends \yii\base\Request $http = $secure ? 'https' : 'http'; if (isset($_SERVER['HTTP_HOST'])) { $this->_hostInfo = $http . '://' . $_SERVER['HTTP_HOST']; - } else { + } elseif (isset($_SERVER['SERVER_NAME'])) { $this->_hostInfo = $http . '://' . $_SERVER['SERVER_NAME']; $port = $secure ? $this->getSecurePort() : $this->getPort(); if (($port !== 80 && !$secure) || ($port !== 443 && $secure)) { @@ -601,13 +602,13 @@ class Request extends \yii\base\Request if ($this->_scriptUrl === null) { $scriptFile = $this->getScriptFile(); $scriptName = basename($scriptFile); - if (basename($_SERVER['SCRIPT_NAME']) === $scriptName) { + if (isset($_SERVER['SCRIPT_NAME']) && basename($_SERVER['SCRIPT_NAME']) === $scriptName) { $this->_scriptUrl = $_SERVER['SCRIPT_NAME']; - } elseif (basename($_SERVER['PHP_SELF']) === $scriptName) { + } elseif (isset($_SERVER['PHP_SELF']) && basename($_SERVER['PHP_SELF']) === $scriptName) { $this->_scriptUrl = $_SERVER['PHP_SELF']; } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $scriptName) { $this->_scriptUrl = $_SERVER['ORIG_SCRIPT_NAME']; - } elseif (($pos = strpos($_SERVER['PHP_SELF'], '/' . $scriptName)) !== false) { + } elseif (isset($_SERVER['PHP_SELF']) && ($pos = strpos($_SERVER['PHP_SELF'], '/' . $scriptName)) !== false) { $this->_scriptUrl = substr($_SERVER['SCRIPT_NAME'], 0, $pos) . '/' . $scriptName; } elseif (!empty($_SERVER['DOCUMENT_ROOT']) && strpos($scriptFile, $_SERVER['DOCUMENT_ROOT']) === 0) { $this->_scriptUrl = str_replace('\\', '/', str_replace($_SERVER['DOCUMENT_ROOT'], '', $scriptFile)); @@ -636,10 +637,17 @@ class Request extends \yii\base\Request * Returns the entry script file path. * The default implementation will simply return `$_SERVER['SCRIPT_FILENAME']`. * @return string the entry script file path + * @throws InvalidConfigException */ public function getScriptFile() { - return isset($this->_scriptFile) ? $this->_scriptFile : $_SERVER['SCRIPT_FILENAME']; + if (isset($this->_scriptFile)) { + return $this->_scriptFile; + } elseif (isset($_SERVER['SCRIPT_FILENAME'])) { + return $_SERVER['SCRIPT_FILENAME']; + } else { + throw new InvalidConfigException('Unable to determine the entry script file path.'); + } } /** @@ -825,25 +833,25 @@ class Request extends \yii\base\Request /** * Returns the server name. - * @return string server name + * @return string server name, null if not available */ public function getServerName() { - return $_SERVER['SERVER_NAME']; + return isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null; } /** * Returns the server port number. - * @return integer server port number + * @return integer server port number, null if not available */ public function getServerPort() { - return (int) $_SERVER['SERVER_PORT']; + return isset($_SERVER['SERVER_PORT']) ? (int) $_SERVER['SERVER_PORT'] : null; } /** - * Returns the URL referrer, null if not present - * @return string URL referrer, null if not present + * Returns the URL referrer. + * @return string URL referrer, null if not available */ public function getReferrer() { @@ -851,8 +859,8 @@ class Request extends \yii\base\Request } /** - * Returns the user agent, null if not present. - * @return string user agent, null if not present + * Returns the user agent. + * @return string user agent, null if not available */ public function getUserAgent() { @@ -861,7 +869,7 @@ class Request extends \yii\base\Request /** * Returns the user IP address. - * @return string user IP address. Null is returned if the user IP address cannot be detected. + * @return string user IP address, null if not available */ public function getUserIP() { @@ -869,8 +877,8 @@ class Request extends \yii\base\Request } /** - * Returns the user host name, null if it cannot be determined. - * @return string user host name, null if cannot be determined + * Returns the user host name. + * @return string user host name, null if not available */ public function getUserHost() { diff --git a/tests/framework/web/RequestTest.php b/tests/framework/web/RequestTest.php index aa45e137ce..8ee890a711 100644 --- a/tests/framework/web/RequestTest.php +++ b/tests/framework/web/RequestTest.php @@ -146,4 +146,59 @@ class RequestTest extends TestCase $this->assertEquals(['post/view', ['id' => 21, 'token' => 'secret']], $result); $this->assertEquals($_GET, ['id' => 63]); } + + public function testGetHostInfo() + { + $request = new Request(); + + unset($_SERVER['SERVER_NAME'], $_SERVER['HTTP_HOST']); + $this->assertEquals(null, $request->getHostInfo()); + + $request->setHostInfo('http://servername.com:80'); + $this->assertEquals('http://servername.com:80', $request->getHostInfo()); + } + + /** + * @expectedException \yii\base\InvalidConfigException + */ + public function testGetScriptFileWithEmptyServer() + { + $request = new Request(); + $_SERVER = []; + + $request->getScriptFile(); + } + + /** + * @expectedException \yii\base\InvalidConfigException + */ + public function testGetScriptUrlWithEmptyServer() + { + $request = new Request(); + $_SERVER = []; + + $request->getScriptUrl(); + } + + public function testGetServerName() + { + $request = new Request(); + + $_SERVER['SERVER_NAME'] = 'servername'; + $this->assertEquals('servername', $request->getServerName()); + + unset($_SERVER['SERVER_NAME']); + $this->assertEquals(null, $request->getServerName()); + } + + public function testGetServerPort() + { + $request = new Request(); + + $_SERVER['SERVER_PORT'] = 33; + $this->assertEquals(33, $request->getServerPort()); + + unset($_SERVER['SERVER_PORT']); + $this->assertEquals(null, $request->getServerPort()); + } }