yiisoft / yii2

Yii 2: The Fast, Secure and Professional PHP Framework
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
14.23k stars 6.91k forks source link

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

Closed YiiRocks closed 6 years ago

YiiRocks commented 7 years ago

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
yii-bot commented 7 years ago

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

Thanks!

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

YiiRocks commented 7 years ago
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.

YiiRocks commented 6 years ago

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?

samdark commented 6 years ago

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

YiiRocks commented 6 years ago

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;
samdark commented 6 years ago
  1. Try disabling debug module to see if the issue is gone.
  2. Try switching to file session.
YiiRocks commented 6 years ago
  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.
samdark commented 6 years ago

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.

korvinko commented 6 years ago

Same problem for me on PHP 7.2 stable

SilverFire commented 6 years ago

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

schmunk42 commented 6 years ago

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

korvinko commented 6 years ago

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);
        }
    }
samdark commented 6 years ago

Will be fixed by https://github.com/yiisoft/yii2/pull/15523

YiiRocks commented 6 years ago

Updated to https://github.com/yiisoft/yii2-framework/commit/0bc50c86ec7f1e1c23729db271da6f47d92ef1fc, but still get the same error.

YiiRocks commented 6 years ago

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()
rob006 commented 6 years ago

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

samdark commented 6 years ago

Yes.

samdark commented 6 years ago

Should be alright now.

chosen1cwp commented 6 years ago

遇到同样的问题,已经按照方法解决,thanks