dtrz99313 2015-06-08 12:43 采纳率: 100%
浏览 191
已采纳

所有项目的通用session.save_handler

I'm using vagrant virtual machine for local PHP development and I noticed that there are session write issues when using vagrant-winnfsd plugin. The plugin serves fine my needs, that's why I don't want to reconfigure vagrant, but rather solve the read/write problem. I don't know the origin of the problem, but it's exactly the same as described here. For me SessionHandler::read() also takes about 120 seconds to complete on every request.

So as the author suggest, it makes sense to reconfigure session handler to use either RDDBM or Memcache storage. That sounds reasonable, but I don't want to do this in every single project, I just want to configure it once in php.ini since it has session.save_handler parameter and it can be set to database or memcache there.

I don't mind having one PHP class with all ::read(), ::write() and others methods, main thing is having this code in one place.

Is that possible?

UPDATE: I found the reason and really thanks to @Jasper N. Brouwer they were storing in a NFS sync'd folder. The cause was that I did not add prod environment into AppKernel.php "vagrant" fix. So it used to be:

public function getCacheDir()
{
    if (in_array($this->environment, array('dev', 'test', ''))) {
        return '/run/shm/appname/cache/' .  $this->environment;
    }

    return parent::getCacheDir();
}

public function getLogDir()
{
    if (in_array($this->environment, array('dev', 'test'))) {
        return '/run/shm/appname/logs';
    }

    return parent::getLogDir();
}

and was ok in dev env, but not in prod. Should be:

public function getCacheDir()
{
    if (in_array($this->environment, array('dev', 'test', 'prod'))) {
        return '/run/shm/appname/cache/' .  $this->environment;
    }

    return parent::getCacheDir();
}

public function getLogDir()
{
    if (in_array($this->environment, array('dev', 'test', 'prod'))) {
        return '/run/shm/appname/logs';
    }

    return parent::getLogDir();
}

HOWEVER, just out of curiosity and for easier debugging, since we have now this bounty, I still find the common session save handler for the whole PHP server a nice idea. This may be useful in development if I have to save it into a DB and then can view session data for all projects in realtime in a database using my GUI tool. Maybe, it's possible to do it using auto_prepend_file setting? And define save hanlder there, but I'm not sure how to disallow override of it later in any project code.

  • 写回答

1条回答 默认 最新

  • dqn48247 2015-06-10 20:27
    关注

    Sessions

    A simpler solution is to keep using the files session save handler, but have it use a directory that is not a Vagrant "synced folder".

    In other words, set session.save_path to /tmp for example. This could be any directory, as long as it's not a synced folder (like /vagrant). And you could indeed do this in your php.ini.

    It's even better to use a directory that's actually a shared memory directory (/dev/shm), which is in-memory storage (not on-disk). On most Linux distributions /tmp is actually a folder inside /dev/shm.

    PS: I had a similar problem where session writes would produce empty files. I too wasn't able to track down the source of this problem (other than it had something to do with Vagrant synced folders using NFS), so after a while I gave up searching and simply did what I described above.

    Other write-heavy operations

    Because Vagrant NFS mounts are relatively slow, I recommend to perform other write-heavy operations outside of the synced folders as well.

    Examples of write-heavy things are cache systems:

    • Doctrine 2 may use a file cache driver for metadata-, query- and result-cache.
    • Doctrine 2 will write Proxies in development mode.
    • Twig will "compile" templates to raw php files.
    • Symfony 2 will cache various things in files.
    • A lot of others

    Another example is loggers. Logs will commonly be written to files, which happens a lot.

    Unfortunately there's no real way to configure these directories on a server-wide basis, because it all depends on what components are used, what needs to be configured, which is very project-specific.

    Possible Symfony 2 solution

    You could try a sort of hack to have Symfony 2 use a cache- and logs-directory using environment variables.

    Set an environment variables like so:

    export VENDORNAME_PHP_CACHE_ROOT_DIR='/dev/shm/vendorname/cache'
    export VENDORNAME_PHP_LOGS_ROOT_DIR='/dev/shm/vendorname/logs'
    

    This will make sure CLI tools can pick those variables up. You might want to do this in your .bashrc or something like it.

    You might have to duplicate this in the configuration of your web-server:

    For Apache

    SetEnv VENDORNAME_PHP_CACHE_ROOT_DIR /dev/shm/vendorname/cache
    SetEnv VENDORNAME_PHP_LOGS_ROOT_DIR /dev/shm/vendorname/logs
    

    For Nginx

    fastcgi_param VENDORNAME_PHP_CACHE_ROOT_DIR /dev/shm/vendorname/cache;
    fastcgi_param VENDORNAME_PHP_LOGS_ROOT_DIR /dev/shm/vendorname/logs;
    

    Then you can edit the getCacheDir() and getLogDir() methods of AppKernel.php like so:

    public function getCacheDir()
    {
        if ($dir = $this->getDir('VENDORNAME_PHP_CACHE_ROOT_DIR')) {
            return $dir;
        }
    
        return parent::getCacheDir();
    }
    
    public function getLogDir()
    {
        if ($dir = $this->getDir('VENDORNAME_PHP_LOGS_ROOT_DIR')) {
            return $dir;
        }
    
        return parent::getLogDir();
    }
    
    private function getDir($variable)
    {
        if (!in_array($this->environment, array('dev', 'test'))) {
            return;
        }
    
        if (!($rootDir = getenv($variable))) {
            return;
        }
    
        return sprintf('%s/appname/%s', $rootDir, $this->environment);
    }
    

    Now you can control the cache- and logs-directories of all Symfony 2 projects through those environment variables.

    For other projects you can do something similar.

    But you'll have to do a bit of tweaking in the projects themselves. Because this is not native PHP functionality (like session.save_path is), there's no way to control this through PHP configuration (php.ini alone).

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能
  • ¥15 jmeter脚本回放有的是对的有的是错的
  • ¥15 r语言蛋白组学相关问题