2

Requirement

How to forcibly redirect to https (redirect if user accessing http) on Yii2? I already tried web.config to force https, but it didn't work.

scenario

I am using Yii2 advanced app hosted on IIS 7.5.

ttrasn
  • 4,322
  • 4
  • 26
  • 43
rishad2m8
  • 1,365
  • 20
  • 27

3 Answers3

6

Its actually very easy in Yii2 as there is a predefined method for your check. Just three steps needed:

1. Extend the application class

Extend the default yii web-application class and override the handleRequest-method. Use the existing Yii2-function to check if the connection is secure.

class MyApplication extends \yii\web\Application
{
    public function handleRequest($request)
    {
        //check if connection is secure
        if (!$request->isSecureConnection) {
            //otherwise redirect to same url with https
            $secureUrl= str_replace('http', 'https', $request->absoluteUrl);
            //use 301 for a permanent redirect
            return Yii::$app->getResponse()->redirect($secureUrl, 301);
        } else {
            //if secure connection call parent implementation
            return parent::handleRequest($request);
        }
    }
}

2. Use new class in index.php

Within the index.php of your web-folder simply use your new application-class instead of the regular one where the application-instance is created.

3. Done!

That's it actually... :)! Hope it helps!

PLM57
  • 1,256
  • 12
  • 27
  • Does this happen AFTER the application has checked that the request doesn't end up in a 404 Not Found? I imagine I want it like that so that all invalid spam requests don't get a 302 before they finally get 404... Or would that actually be more resource intensive because for real requests it would start processing the request twice? And for the spammers who don't even want to follow the 302 they get now it saves us processing the request entirely... – TheStoryCoder Apr 02 '17 at 11:28
  • This actually IS the method resolving your request to a 404 if the route is invalid. So to be precise `return parent::handleRequest($request)` would trigger the 404. To answer your question: you qould first get a 302/301 and only then the 404. To prevent this you could first call `parent::handleRequest($request)` and catch the exception if there is one and then proceed as mentioned above. You can find the source code of the Application-class [here](https://github.com/yiisoft/yii2/blob/master/framework/web/Application.php#L78)! – PLM57 Apr 03 '17 at 13:20
  • Please provide an example of index.php of your web-directory. use your new application-class instead of the .... – user206 May 30 '19 at 13:37
1

Just add your rule in on beforeAction event on config.php.

'on beforeAction' => function ($event) {
    if (!(
          (!empty($_SERVER['HTTPS']) AND $_SERVER['HTTPS'] != 'off') || 
          $_SERVER['SERVER_PORT'] == 443
        )) {
            return Yii::$app->controller->redirect("https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
    }
}

This code check if user request is not http then move it to https.

From the PHP.net documentation :

for $_SERVER['HTTPS']

Set to a non-empty value if the script was queried through the HTTPS protocol.

Note: Note that when using ISAPI with IIS, the value will be off if the request was not made through the HTTPS protocol.

so this code should works for IIS.

for $_SERVER['SERVER_PORT']:

Note: Under the Apache 2, you must set UseCanonicalName = On, as well as UseCanonicalPhysicalPort = On in order to get the physical (real) port, otherwise, this value can be spoofed and it may or may not return the physical port value. It is not safe to rely on this value in security-dependent contexts.

so if you have any problem in this code, you can prevent to using $_SERVER['SERVER_PORT'] in rule.

At the end, If you want to do in whole advanced Yii2 do this config in common directory.

Community
  • 1
  • 1
ttrasn
  • 4,322
  • 4
  • 26
  • 43
0

It's very simple on IIS. Can use rewrite module to solve this issue. E.g.,

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>

    <!-- Other stuffs -->

        <rewrite>
            <rules>
                <clear />
                <rule name="Redirect to https" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions>
                        <add input="{HTTPS}" pattern="off" ignoreCase="true" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Permanent" appendQueryString="false" />
                </rule>

                <rule name="Hide Yii Index" stopProcessing="true">
                    <match url="." ignoreCase="false" />
                    <conditions>
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="index.php" appendQueryString="true" />        
                </rule>


            </rules>
        </rewrite>

    <!-- Other stuffs -->
    </system.webServer>    
</configuration>

It's very effective and fast. Can used for CDN url of our own without help of PHP code.
This code can used for ASP.Net also. In such case, remove Hide Yii Index section.

rishad2m8
  • 1,365
  • 20
  • 27