所有项目通用 session.save_handler
Common session.save_handler for all projects
我正在使用 vagrant 虚拟机进行本地 PHP 开发,我注意到在使用 vagrant-winnfsd 插件时存在会话写入问题。该插件很好地满足了我的需求,这就是为什么我不想重新配置 vagrant,而是解决 read/write 问题。我不知道问题的根源,但它与描述的完全一样here。对我来说 SessionHandler::read()
也需要大约 120 秒才能完成每个请求。
因此,正如作者所建议的,重新配置会话处理程序以使用 RDDBM 或 Memcache 存储是有意义的。这听起来很合理,但我不想在每个项目中都这样做,我只想在 php.ini 中配置一次,因为它有 session.save_handler
参数并且可以在那里设置为数据库或内存缓存.
我不介意一个 PHP class 包含所有 ::read()
、::write()
和其他方法,主要是将此代码放在一个地方。
这可能吗?
更新: 我找到了原因,非常感谢@Jasper N. Brouwer,他们存储在 NFS 同步文件夹中。原因是我没有将 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
环境中正常,但在 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,但我不确定以后如何在任何项目代码中禁止覆盖它。
会话数
一个更简单的解决方案是继续使用 files
会话保存处理程序,但让它使用 而不是 Vagrant "synced folder" 的目录。
换句话说,例如将session.save_path
设置为/tmp
。这可以是任何目录,只要它不是同步文件夹(如 /vagrant
)即可。您确实可以在 php.ini
.
中执行此操作
最好使用实际上是共享内存目录的目录 (/dev/shm
),它是内存存储(而不是磁盘上)。在大多数 Linux 发行版中 /tmp
实际上是 /dev/shm
.
中的一个文件夹
PS:我有一个类似的问题,会话写入会产生空文件。我也无法找到这个问题的根源(除了它与使用 NFS 的 Vagrant 同步文件夹有关),所以过了一会儿我放弃了搜索并简单地做了我上面描述的。
其他写入密集型操作
因为 Vagrant NFS 挂载速度相对较慢,我建议在同步文件夹之外执行其他写入密集型操作。
写入繁重的事物的例子是缓存系统:
- Doctrine 2 可以使用文件缓存驱动程序进行元数据、查询和结果缓存。
- Doctrine 2 将在开发模式下编写 Proxies。
- Twig 会将 "compile" 模板转换为原始 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'
这将确保 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;
然后你可以像这样编辑 AppKernel.php
的 getCacheDir()
和 getLogDir()
方法:
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
一个人)。
我正在使用 vagrant 虚拟机进行本地 PHP 开发,我注意到在使用 vagrant-winnfsd 插件时存在会话写入问题。该插件很好地满足了我的需求,这就是为什么我不想重新配置 vagrant,而是解决 read/write 问题。我不知道问题的根源,但它与描述的完全一样here。对我来说 SessionHandler::read()
也需要大约 120 秒才能完成每个请求。
因此,正如作者所建议的,重新配置会话处理程序以使用 RDDBM 或 Memcache 存储是有意义的。这听起来很合理,但我不想在每个项目中都这样做,我只想在 php.ini 中配置一次,因为它有 session.save_handler
参数并且可以在那里设置为数据库或内存缓存.
我不介意一个 PHP class 包含所有 ::read()
、::write()
和其他方法,主要是将此代码放在一个地方。
这可能吗?
更新: 我找到了原因,非常感谢@Jasper N. Brouwer,他们存储在 NFS 同步文件夹中。原因是我没有将 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
环境中正常,但在 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,但我不确定以后如何在任何项目代码中禁止覆盖它。
会话数
一个更简单的解决方案是继续使用 files
会话保存处理程序,但让它使用 而不是 Vagrant "synced folder" 的目录。
换句话说,例如将session.save_path
设置为/tmp
。这可以是任何目录,只要它不是同步文件夹(如 /vagrant
)即可。您确实可以在 php.ini
.
最好使用实际上是共享内存目录的目录 (/dev/shm
),它是内存存储(而不是磁盘上)。在大多数 Linux 发行版中 /tmp
实际上是 /dev/shm
.
PS:我有一个类似的问题,会话写入会产生空文件。我也无法找到这个问题的根源(除了它与使用 NFS 的 Vagrant 同步文件夹有关),所以过了一会儿我放弃了搜索并简单地做了我上面描述的。
其他写入密集型操作
因为 Vagrant NFS 挂载速度相对较慢,我建议在同步文件夹之外执行其他写入密集型操作。
写入繁重的事物的例子是缓存系统:
- Doctrine 2 可以使用文件缓存驱动程序进行元数据、查询和结果缓存。
- Doctrine 2 将在开发模式下编写 Proxies。
- Twig 会将 "compile" 模板转换为原始 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'
这将确保 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;
然后你可以像这样编辑 AppKernel.php
的 getCacheDir()
和 getLogDir()
方法:
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
一个人)。