Yii2: PHP 7.2: session_cache_limiter(): Cannot change cache limiter when session is active

Created on 13 Sep 2017  ยท  19Comments  ยท  Source: yiisoft/yii2

What steps will reproduce the problem?

Hitting a page with HttpCache::className() defined in behaviours in the controller

What is the expected result?

A working page

What do you get instead?

PHP Warning โ€“ yii\base\ErrorException

session_cache_limiter(): Cannot change cache limiter when session is active
1. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/filters/HttpCache.php at line 192
2. yii\base\ErrorHandler::handleError(2, 'session_cache_limiter(): Cannot ...', '/homepages/user/htdocs/...', 192, ...)
3. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/filters/HttpCache.php at line 192 โ€“ session_cache_limiter('')
4. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/filters/HttpCache.php at line 138 โ€“ yii\filters\HttpCache::sendCacheControlHeader()
5. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/base/ActionFilter.php at line 75 โ€“ yii\filters\HttpCache::beforeAction(yii\base\InlineAction)
6. yii\base\ActionFilter::beforeFilter(yii\base\ActionEvent)
7. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/base/Component.php at line 557 โ€“ call_user_func([yii\filters\HttpCache, 'beforeFilter'], yii\base\ActionEvent)
8. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/base/Controller.php at line 274 โ€“ yii\base\Component::trigger('beforeAction', yii\base\ActionEvent)
9. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/web/Controller.php at line 164 โ€“ yii\base\Controller::beforeAction(yii\base\InlineAction)
10. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/base/Controller.php at line 155 โ€“ yii\web\Controller::beforeAction(yii\base\InlineAction)
11. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/base/Module.php at line 528 โ€“ yii\base\Controller::runAction('index', [])
12. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/web/Application.php at line 103 โ€“ yii\base\Module::runAction('lyrics/index', [])
13. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/base/Application.php at line 386 โ€“ yii\web\Application::handleRequest(yii\web\Request)
14. in /homepages/user/htdocs/yii/webroot/index.php at line 18 โ€“ yii\base\Application::run()

Additional info

| Q | A
| ---------------- | ---
| Yii version | 2.0.12-dev
| PHP version | PHP 7.2.0RC1
| Operating system | Debian 3.14.77-2~ui80+4

php7 bug

All 19 comments

Thanks for posting in our issue tracker.
In order to properly assist you, we need additional information:

  • When does the issue occur?
  • What do you see?
  • What was the expected result?
  • Can you supply us with a stacktrace? (optional)
  • Do you have exact code to reproduce it? Maybe a PHPUnit tests that fails? (optional)

Thanks!

_This is an automated comment, triggered by adding the label status:need more info._

class CalculatorController extends \yii\web\Controller {
    public function behaviors() {
        return [
            [
                'class' => HttpCache::className(),
                'etagSeed' => function (BaseObject $action) {
                    return serialize([YII_DEBUG, phpversion(), Yii::$app->user->id, file(Yii::getAlias('@app/views/'.$action->controller->id.'/'.$action->id.'.php'), FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)]);
                },
                'lastModified' => function (BaseObject $action) {
                    return filemtime(Yii::getAlias('@app/views/'.$action->controller->id.'/'.$action->id.'.php'));
                },
                'only' => ['wpapsk'],
            ],
        ];
    }

    public function actionWpapsk() {
        return $this->render('wpapsk');
    }
}

The same setup, server, install, code, ... does not give any problem when switching back to PHP 7.1.9.

According to http://php.net/manual/en/function.session-cache-limiter.php, session_cache_limiter() needs to be called before session_start(). Is that done correctly in https://github.com/yiisoft/yii2/blob/master/framework/filters/HttpCache.php#L192?

Should be but it seems not... please share your application config removing passwords and DB names/hosts.

common.php

<?php
$secrets = require(__DIR__ . '/secrets.php');

return [
    'aliases' => [
        '@assets' => '//s.mister42.me',
        '@assetsroot' => __DIR__ . '/../../www/assets/me.mister42.s',
        '@bower' => '@vendor/bower-asset',
        '@npm'   => '@vendor/npm-asset',
    ],
    'basePath' => __DIR__,
    'bootstrap' => ['log'],
    'components' => [
        'assetManager' => [
            'basePath' => '@assetsroot',
            'baseUrl' => '@assets',
            'bundles' => [
                'yii\bootstrap\BootstrapAsset' => [
                    'css' => [],
                ],
                'yii\bootstrap\BootstrapPluginAsset' => [
                    'js' => [YII_ENV_DEV ? 'js/bootstrap.js' : 'js/bootstrap.min.js'],
                ],
                'yii\jui\JuiAsset' => [
                    'css' => [YII_ENV_DEV ? 'themes/smoothness/jquery-ui.css' : 'themes/smoothness/jquery-ui.min.css'],
                    'js' => [YII_ENV_DEV ? 'jquery-ui.js' : 'jquery-ui.min.js'],
                ],
                'yii\web\JqueryAsset' => [
                    'js' => [YII_ENV_DEV ? 'jquery.js' : 'jquery.min.js'],
                ],
            ],
            'linkAssets' => true,
        ],
        'authManager' => [
            'class' => 'yii\rbac\DbManager',
        ],
        'cache' => [
            'class' => 'yii\caching\DbCache',
        ],
        'fileCache' => [
            'class' => 'yii\caching\FileCache',
            'directoryLevel' => 0,
        ],
        'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host='.$secrets['MySQL']['host'].';dbname='.$secrets['MySQL']['db'],
            'username' => $secrets['MySQL']['user'],
            'password' => $secrets['MySQL']['pass'],
            'charset' => 'utf8',
            'tablePrefix' => 'mister42_',

            'enableSchemaCache' => true,
            'schemaCache' => 'fileCache',
            'schemaCacheDuration' => 60*60*24*7,

            'enableQueryCache' => true,
            'queryCache' => 'fileCache',
            'queryCacheDuration' => 60*60*24*2,
        ],
        'formatter' => [
            'class' => 'app\models\Formatter',
        ],
        'i18n' => [
            'translations' => [
                'site' => [
                    'class' => 'yii\i18n\PhpMessageSource',
                    'sourceLanguage' => 'en',
                ],
            ],
        ],
        'mailer' => [
            'class' => 'yii\swiftmailer\Mailer',
            'transport' => [
                'class' => 'Swift_SmtpTransport',
                'host' => $secrets['email']['host'],
                'username' => $secrets['email']['username'],
                'password' => $secrets['email']['password'],
                'encryption' => 'tls',
            ],
        ],
        'pdf' => [
            'class' => \kartik\mpdf\Pdf::classname(),
            'mode' => \kartik\mpdf\Pdf::MODE_UTF8,
        ],
        'urlManager' => [
            'enablePrettyUrl' => true,
            'normalizer' => [
                'class' => 'yii\web\UrlNormalizer',
            ],
            'showScriptName' => false,
            'rules' => [
                ''                                                                  => 'site/index',
                'favicon.ico'                                                       => 'site/faviconico',
                'robots.txt'                                                        => 'site/robotstxt',
                'sitemap.xml'                                                       => 'feed/sitemap',
                'lyrics/<artist:.*?>/<year:\d{4}>/<album:.*?>.pdf'                  => 'lyrics/albumpdf',
                'lyrics/<artist:.*?>/<year:\d{4}>/<album:.*?>-<size:.{2,5}>.jpg'    => 'lyrics/albumcover',
                'lyrics/<artist:.*?>/<year:\d{4}>/<album:.*?>'                      => 'lyrics/index',
                'lyrics/<artist:.*?>'                                               => 'lyrics/index',
                'articles/<id:\d+>/<title:.*?>.pdf'                                 => 'articles/pdf',
                'art<id:\d+>'                                                       => 'permalink/articles',
                'articles/<id:\d+>/<title:.*?>'                                     => 'articles/index',
                'articles/<id:\d+>'                                                 => 'articles/index',
                'articles/<action:search>'                                          => 'articles/index',
                'articles/<action:tag>/<tag:\w+>'                                   => 'articles/index',
                'articles/page-<page:\d+>'                                          => 'articles/index',
                'articles'                                                          => 'articles/index',
                'articles/<action>'                                                 => 'articles/<action>',
                '<controller:calculator|feed|lyrics|tools>'                         => '<controller>/index',
                '<alias:\w+>'                                                       => 'site/<alias>',
            ],
        ],
    ],
    'language' => 'en',
    'name' => 'Mr.42',
    'params' => require(__DIR__ . '/params.php'),
    'runtimePath' => __DIR__ . '/../../../.cache/yii/mister42',
    'timeZone' => 'Europe/Berlin',
    'vendorPath' => __DIR__ . '/../../vendor',
];

web.php

<?php
$secrets = require(__DIR__ . '/secrets.php');

$config = [
    'id' => 'mister42',
#   'catchAll' => ['site/offline'],
    'components' => [
        'authClientCollection' => [
            'class'   => \yii\authclient\Collection::className(),
            'clients' => [
                'facebook' => [
                    'class'         => 'Da\User\AuthClient\Facebook',
                    'clientId'      => $secrets['facebook']['Id'],
                    'clientSecret'  => $secrets['facebook']['Secret'],
                ],
                'github' => [
                    'class'         => 'Da\User\AuthClient\GitHub',
                    'clientId'      => $secrets['github']['Id'],
                    'clientSecret'  => $secrets['github']['Secret'],
                ],
                'google' => [
                    'class'         => 'Da\User\AuthClient\Google',
                    'clientId'      => $secrets['google']['Id'],
                    'clientSecret'  => $secrets['google']['Secret'],
                ],
            ],
        ],
        'errorHandler' => [
            'errorAction' => 'site/error',
        ],
        'log' => [
            'traceLevel' => YII_DEBUG ? 3 : 0,
            'targets' => [
                [
                    'class' => 'yii\log\DbTarget',
                    'except' => ['yii\web\HttpException:404'],
                    'levels' => ['error'],
                    'logTable' => 'log_mister42_error',
                ], [
                    'class' => 'yii\log\DbTarget',
                    'categories' => ['yii\web\HttpException:404'],
                    'logTable' => 'log_mister42_404',
                ],
            ],
        ],
        'request' => [
            'cookieValidationKey' => $secrets['cookieValidationKey'],
        ],
        'session' => [
            'class' => 'yii\web\DbSession',
            'sessionTable' => 'x_session',
        ],
        'view' => [
            'theme' => [
                'pathMap' => [
                    '@Da/User/resources/views' => '@app/views/user'
                ],
            ],
        ],
    ],
    'modules' => [
        'user' => [
            'class' => Da\User\Module::class,
            'administrators' => ['admin'],
            'allowAccountDelete' => false,
            'controllerMap' => [
                'profile' => 'app\controllers\user\ProfileController',
            ],
            'classMap' => [
                'Profile' => 'app\models\user\Profile',
                'RegistrationForm' => 'app\models\user\RegistrationForm',
            ],
            'routes' => [
                'profile/<username:\w+>'                    => 'profile/show',
                'recenttracks/<username:\w+>'               => 'profile/recenttracks',
                '<action:(login|logout)>'                   => 'security/<action>',
                '<action:(register|resend)>'                => 'registration/<action>',
                'confirm/<id:\d+>/<code:[A-Za-z0-9_-]+>'    => 'registration/confirm',
                'forgot'                                    => 'recovery/request',
                'recover/<id:\d+>/<code:[A-Za-z0-9_-]+>'    => 'recovery/reset',
                'settings/<action:\w+>'                     => 'settings/<action>',
            ],
        ],
    ],
    'params' => require(__DIR__ . '/params.php'),
];

if (YII_DEBUG && in_array($_SERVER['REMOTE_ADDR'], $secrets['params']['specialIPs'])) {
    $config['bootstrap'][] = 'debug';
    $config['modules']['debug'] = [
        'class' => 'yii\debug\Module',
        'allowedIPs' => $secrets['params']['specialIPs'],
    ];
}

if (YII_ENV_DEV && in_array($_SERVER['REMOTE_ADDR'], $secrets['params']['specialIPs'])) {
    $config['bootstrap'][] = 'gii';
    $config['modules']['gii'] = [
        'class' => 'yii\gii\Module',
        'allowedIPs' => $secrets['params']['specialIPs'],
    ];
} else
    define('YII_ENV_DEV', false);

return $config;
  1. Try disabling debug module to see if the issue is gone.
  2. Try switching to file session.
  1. No chance (except I just get a general error message of course)
  2. If it is enough to comment out the components.session part, no change
Error (#2)
An internal server error occurred.

I'll try to check it with local 7.2 in a few days but can't guarantee that it will be fixed/release in 2.0.13. Too many things to check for that milestone already.

Same problem for me on PHP 7.2 stable

I've seen this error in console application when worked on PHP 7.2 compatibility fixed. It happened when script echoed something prior to calling session functions that send headers. I will check how the behavior works to verify this issue

I am seeing this in dockerized tests on 7.2, see https://travis-ci.org/yiisoft/yii2-docker/jobs/318068967

Could someone explain me why we need use session_cache_limiter in yii\filters\HttpCache with sendCacheControlHeader method?

    protected function sendCacheControlHeader()
    {
        if ($this->sessionCacheLimiter !== null) {
            if ($this->sessionCacheLimiter === '' && !headers_sent() && Yii::$app->getSession()->getIsActive()) {
                header_remove('Expires');
                header_remove('Cache-Control');
                header_remove('Last-Modified');
                header_remove('Pragma');
            }
            if (!Yii::$app->getSession()->getIsActive()) {
                session_cache_limiter($this->sessionCacheLimiter);
            }
        }
        $headers = Yii::$app->getResponse()->getHeaders();

        if ($this->cacheControlHeader !== null) {
            $headers->set('Cache-Control', $this->cacheControlHeader);
        }
    }

Here we send headers manually in last if condition. Why we need session_cache_limiter with it?

I just removed it block and cache still works good:

    protected function sendCacheControlHeader()
    {
        $headers = Yii::$app->getResponse()->getHeaders();

        if ($this->cacheControlHeader !== null) {
            $headers->set('Cache-Control', $this->cacheControlHeader);
        }
    }

https://github.com/yiisoft/yii2-framework/commit/e6959f4903de42ccd28e796f2872f4a37a798bff

PHP Warning โ€“ yii\base\ErrorException
session_cache_limiter(): Cannot change cache limiter when session is active
1. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/filters/HttpCache.php at line 192
2. yii\base\ErrorHandler::handleError(2, 'session_cache_limiter(): Cannot ...', '/homepages/user/htdocs/...', 192, ...)
3. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/filters/HttpCache.php at line 192 โ€“ session_cache_limiter('')
4. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/filters/HttpCache.php at line 138 โ€“ yii\filters\HttpCache::sendCacheControlHeader()
5. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/base/ActionFilter.php at line 76 โ€“ yii\filters\HttpCache::beforeAction(yii\base\InlineAction)
6. yii\base\ActionFilter::beforeFilter(yii\base\ActionEvent)
7. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/base/Component.php at line 627 โ€“ call_user_func([yii\filters\HttpCache, 'beforeFilter'], yii\base\ActionEvent)
8. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/base/Controller.php at line 274 โ€“ yii\base\Component::trigger('beforeAction', yii\base\ActionEvent)
9. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/web/Controller.php at line 164 โ€“ yii\base\Controller::beforeAction(yii\base\InlineAction)
10. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/base/Controller.php at line 155 โ€“ yii\web\Controller::beforeAction(yii\base\InlineAction)
11. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/base/Module.php at line 528 โ€“ yii\base\Controller::runAction('wpapsk', [])
12. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/web/Application.php at line 103 โ€“ yii\base\Module::runAction('calculator/wpapsk', [])
13. in /homepages/user/htdocs/yii/vendor/yiisoft/yii2/base/Application.php at line 386 โ€“ yii\web\Application::handleRequest(yii\web\Request)
14. in /homepages/user/htdocs/yii/www/webroot/index.php at line 23 โ€“ yii\base\Application::run()

Should move session_cache_limiter() calls to Session component and wrap with freeze/unfreeze in the same way as timeout or useCookies?

Yes.

Should be alright now.

้‡ๅˆฐๅŒๆ ท็š„้—ฎ้ข˜๏ผŒๅทฒ็ปๆŒ‰็…งๆ–นๆณ•่งฃๅ†ณ๏ผŒthanks

Was this page helpful?
0 / 5 - 0 ratings