Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yii: weird redirect behaviour (https -> http)

Tags:

php

yii

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)?

like image 641
Denis Kulagin Avatar asked Sep 12 '26 05:09

Denis Kulagin


1 Answers

/**
     * 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.

like image 119
Ofir Baruch Avatar answered Sep 13 '26 20:09

Ofir Baruch



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!