I have a whole website working using HTTPS protocol. But recently I have noticed very weird bahaviour of Yii. When I make a redirect:
$this->redirect('/article/123456');
It first does 302-redirect to http version of the page (I can see by headers):
HTTP://site.xyz/article/123456
X-Powered-By: PHP/5.4.45-0+deb7u2
Then NGINX does a 301-redirect to the https version:
HTTPS://site.xyz/article/123456
Why is it happening and how does Yii build an absolute URL (always thought it uses relative ones)?
/**
* Redirects the browser to the specified URL.
* @param string $url URL to be redirected to. Note that when URL is not
* absolute (not starting with "/") it will be relative to current request URL.
* @param boolean $terminate whether to terminate the current application
* @param integer $statusCode the HTTP status code. Defaults to 302. See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html}
* for details about HTTP status code.
*/
public function redirect($url,$terminate=true,$statusCode=302)
{
if(strpos($url,'/')===0 && strpos($url,'//')!==0)
$url=$this->getHostInfo().$url;
header('Location: '.$url, true, $statusCode);
if($terminate)
Yii::app()->end();
}
Source
Check the note regarding the URL parameter:
@param string $url URL to be redirected to. Note that when URL is not * absolute (not starting with "/") it will be relative to current request URL.
However, In your code the URL is starting with "/" so according to the source code, the next thing that would happen is: $url = $this->getHostInfo().$url;
So let's take a look at the source of the getHostInfo function:
public function getHostInfo($schema='')
{
if($this->_hostInfo===null)
{
if($secure=$this->getIsSecureConnection())
$http='https';
else
$http='http';
if(isset($_SERVER['HTTP_HOST']))
$this->_hostInfo=$http.'://'.$_SERVER['HTTP_HOST'];
else
{
$this->_hostInfo=$http.'://'.$_SERVER['SERVER_NAME'];
$port=$secure ? $this->getSecurePort() : $this->getPort();
if(($port!==80 && !$secure) || ($port!==443 && $secure))
$this->_hostInfo.=':'.$port;
}
}
if($schema!=='')
{
$secure=$this->getIsSecureConnection();
if($secure && $schema==='https' || !$secure && $schema==='http')
return $this->_hostInfo;
$port=$schema==='https' ? $this->getSecurePort() : $this->getPort();
if($port!==80 && $schema==='http' || $port!==443 && $schema==='https')
$port=':'.$port;
else
$port='';
$pos=strpos($this->_hostInfo,':');
return $schema.substr($this->_hostInfo,$pos,strcspn($this->_hostInfo,':',$pos+1)+1).$port;
}
else
return $this->_hostInfo;
}
I'd advise you to check if the first condition returns true (while I don't find it likely that _hostInfo has been defined) and to check the result of the $this->getIsSecureConnection() function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With