Common session.save_handler for all projects

Ale*_*xey 2 php session symfony vagrant

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();
}
Run Code Online (Sandbox Code Playgroud)

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();
}
Run Code Online (Sandbox Code Playgroud)

但是,出于好奇和简化调试的需要,由于我们现在有了这个赏金,我仍然发现整个PHP服务器的通用会话保存处理程序是一个不错的主意。如果必须将其保存到数据库中,然后可以使用GUI工具在数据库中实时查看所有项目的会话数据,这在开发中可能很有用。也许可以使用auto_prepend_file设置来做到这一点?并在那里定义save hanlder,但是我不确定以后如何在任何项目代码中禁止覆盖它。

Jas*_*wer 5

届会

一个更简单的解决方案是继续使用files会话保存处理程序,但让它使用的目录不是 Vagrant的“同步文件夹”。

换句话说,设置session.save_path/tmp例如。该目录可以是任何目录,只要它不是已同步的文件夹(例如/vagrant)即可。而且您确实可以在自己的服务器上执行此操作php.ini

最好使用实际上是共享内存目录(/dev/shm)的目录,该目录是内存中的存储(不是磁盘上的)。在大多数Linux发行版/tmp中,实际上是一个文件夹/dev/shm

PS:我有一个类似的问题,会话写入会产生空文件。我也无法找到问题的根源(除了它与使用NFS的Vagrant同步文件夹有关),所以一段时间后,我放弃了搜索,只是做了上面描述的事情。

其他繁重的写操作

由于Vagrant NFS的挂载速度相对较慢,因此我建议在同步文件夹之外也执行其他大量写入操作。

大量写入的示例是高速缓存系统:

  • 原则2可以将文件缓存驱动程序用于元数据,查询和结果缓存。
  • 教义2将以开发模式编写代理。
  • Twig将模板“编译”为原始php文件。
  • Symfony 2将在文件中缓存各种内容。
  • 其他很多

另一个例子是记录器。日志通常会写入文件,这经常发生。

不幸的是,没有一种真正的方法可以在服务器范围内配置这些目录,因为这完全取决于所使用的组件,需要配置的组件,这与项目非常相关。

可能的Symfony 2解决方案

您可以尝试一种破解方法,以使Symfony 2使用带有环境变量的缓存目录和日志目录。

设置环境变量,如下所示:

export VENDORNAME_PHP_CACHE_ROOT_DIR='/dev/shm/vendorname/cache'
export VENDORNAME_PHP_LOGS_ROOT_DIR='/dev/shm/vendorname/logs'
Run Code Online (Sandbox Code Playgroud)

这将确保CLI工具可以选择这些变量。您可能想用自己的.bashrc东西或类似的东西来做。

您可能必须在Web服务器的配置中重复此操作:

对于Apache

SetEnv VENDORNAME_PHP_CACHE_ROOT_DIR /dev/shm/vendorname/cache
SetEnv VENDORNAME_PHP_LOGS_ROOT_DIR /dev/shm/vendorname/logs
Run Code Online (Sandbox Code Playgroud)

对于Nginx

fastcgi_param VENDORNAME_PHP_CACHE_ROOT_DIR /dev/shm/vendorname/cache;
fastcgi_param VENDORNAME_PHP_LOGS_ROOT_DIR /dev/shm/vendorname/logs;
Run Code Online (Sandbox Code Playgroud)

然后,您可以像这样编辑getCacheDir()getLogDir()方法AppKernel.php

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);
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以通过这些环境变量来控制所有Symfony 2项目的缓存和日志目录。

对于其他项目,您可以执行类似的操作。

但是您必须对项目本身进行一些调整。由于这不是 PHP的本机功能(就像这样session.save_path),因此无法通过PHP配置(php.ini单独)来控制它。