所有项目的常见session.save_handler

时间:2015-06-08 12:43:53

标签: php symfony session vagrant

我正在使用vagrant虚拟机进行本地PHP开发,我注意到使用vagrant-winnfsd插件时存在会话写入问题。该插件满足我的需求,这就是为什么我不想重新配置vagrant,而是解决读/写问题。我不知道问题的根源,但它与描述的here完全相同。对我来说,SessionHandler::read()每次请求也需要大约120秒才能完成。

正如作者所建议的那样,重新配置会话处理程序以使用RDDBM或Memcache存储是有意义的。这听起来很合理,但我不想在每个项目中都这样做,我只想在php.ini中配置一次,因为它有session.save_handler参数,可以在那里设置为数据库或memcache。

我不介意拥有一个包含所有::read()::write()和其他方法的PHP类,主要的是将代码放在一个地方。

这可能吗?

更新:我找到了原因并非常感谢@Jasper N. Brouwer他们存储在NFS sync'd文件夹中。原因是我没有将prod环境添加到AppKernel.php“vagrant”修复程序中。所以它曾经是:

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();
}

dev env中没问题,但在prod中没有。应该是:

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 ,只是出于好奇和更容易调试,因为我们现在有这个赏金,我仍然发现整个PHP服务器的公共会话保存处理程序是一个好主意。如果我必须将其保存到数据库中,然后可以使用我的GUI工具在数据库中实时查看所有项目的会话数据,这在开发中可能很有用。也许,使用auto_prepend_file设置可以做到这一点?并在那里定义save hanlder,但我不知道如何在任何项目代码中禁止覆盖它。

1 个答案:

答案 0 :(得分:4)

会话

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

换句话说,例如,将session.save_path设置为/tmp。这可以是任何目录,只要它不是同步文件夹(如/vagrant)。您确实可以在php.ini

中执行此操作

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

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

其他写入繁重的操作

由于Vagrant NFS挂载相对较慢,我建议在同步文件夹之外执行其他写入操作。

重写事物的例子是缓存系统:

  • Doctrine 2可以使用文件缓存驱动程序进行元数据,查询和结果缓存。
  • Doctrine 2将在开发模式下编写Proxies。
  • Twig将"编译"模板到原始的php文件。
  • Symfony 2会在文件中缓存各种内容。
  • 很多其他人

另一个例子是记录器。日志通常会写入文件,这种情况会发生很多。

不幸的是,在服务器范围内没有真正的方法来配置这些目录,因为这完全取决于使用的组件,需要配置的内容,这是特定于项目的。

可能的Symfony 2解决方案

你可以尝试一种破解让Symfony 2使用环境变量使用cache-和logs-directory。

设置如下的环境变量:

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

这将确保CLI工具可以选择这些变量。 您可能希望在.bashrc或类似的内容中执行此操作。

您可能必须在网络服务器的配置中复制此内容:

对于Apache

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

对于Nginx

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

然后您可以像这样编辑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);
}

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

对于其他项目,您可以做类似的事情。

但是你必须在项目中做一些调整。因为这是本机PHP功能(如session.save_path所示),所以无法通过PHP配置来控制它(仅php.ini)。