【问题标题】:Alternating class not found error when using session handler使用会话处理程序时未找到交替类错误
【发布时间】:2014-08-14 01:37:54
【问题描述】:

首先,如果它是相关的,它在会话处理程序中。这个函数是写入数据库的函数,并与我的其他函数一起传递给session_set_save_handler

session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy', 'sess_gc');

我有这段代码...

$qid = "select count(*) as total
        from zen_sessions
        where sesskey = '" . $key . "'";

if(!class_exists('DB'))
    require_once dirname(dirname(__FILE__)).'/class/DB.class.php';
var_dump(new DB());                      //this is line 109
$total = DB::select_one($qid);

条件和var_dump 用于测试。奇怪的是,有时它可以正常工作,而另一些却给我一个错误:

Fatal error: Class 'DB' not found in /path/to/file/session_functions.php on line 109

我不知道这怎么会在 require 而不是 var_dump 时崩溃,为什么只是有时?

提前感谢您的任何见解。

编辑——对评论/问题的回应:

以下代码的结果

var_dump(class_exists('DB', false)); 
var_dump(is_file(dirname(__DIR__).'/class/DB.class.php')); 

是:

bool(false) bool(true) 

在尝试要求它之前和要求之后的相同结果(或者当它没有给我错误时为真) 看起来像:

bool(true) bool(true) object(DB)#3 (0) { } 

前一个代码块是大约每 5 个页面加载一次的结果,而错误是其他 4 个的结果。

Edit2 -- 新发现。

更奇怪的是根据manual我应该永远不会看到这些调试语句或错误

注意:

“写”处理程序直到输出流被执行后才被执行 关闭。因此,“写”处理程序中调试语句的输出 永远不会在浏览器中看到。如果需要调试输出, 建议将调试输出写入文件。

编辑 3 - 为清楚起见的注释:

DB 类应该已经自动加载(并且在应用程序的其他任何地方)class_exists 和 require 只是用于测试目的。

编辑 4 - 堆栈跟踪

我决定尝试在找不到该类以查看堆栈跟踪时抛出异常,这就是我得到的

Fatal error: Uncaught exception 'Exception' with message 'DB Class Not Found.' 
in /path/to/file/session_functions.php:108 
Stack trace: #0 [internal function]: sess_write('074dabb967260e9...', 'securityToken|s...') 
#1 {main} thrown in /path/to/file/session_functions.php on line 108 

【问题讨论】:

  • 如果您改为使用class_exists('DB', false) 会怎样? + var_dump(is_file(dirname(dirname(__FILE__)).'/class/DB.class.php')); + __DIR__ 而不是 dirname(__FILE__)
  • @zerkms 看到我的编辑。结果几乎一样。
  • 警告您的代码容易受到 sql 注入攻击!
  • @DanielA.White 当你不知道$key 来自哪里时,这是一个相当大的飞跃。不过感谢您的关注。
  • 你在使用“命名空间”吗?从不工作的代码的第一原则开始......经常为“DB”执行“class_check”。在您认为应该加载的点之后立即开始。然后将该检查移向引起麻烦的代码。如果找不到“DB”类,则抛出异常。始终确保在使用类之前显式加载它们。使用“自动加载器”或“include_once”。如果在程序的大多数运行中使用该类,则始终无条件加载该类。

标签: php session


【解决方案1】:

尝试:

$save_handler = new DB();
session_set_save_handler($save_handler, true);

然后在你的类中映射读、写等函数。我遇到了类似的问题(关于未找到类的奇怪随机错误)为使用 redis 的 HHVM 实现另一个用户的自定义保存处理程序解决方法,这就是我修复它的方法。如果您使用 HipHopVirtualMachine(或者可能是其他类型的 JIT 编译器或应用程序缓存),有时您的项目可以缓存某些函数而无需更新,从而产生像这样的奇怪错误。通常重启 fastcgi 守护进程并向您的文件之一添加空格足以强制它重新解释您的项目。

【讨论】:

  • DB 类不是保存处理程序。它只是在函数中用于调用数据库。此代码所在的函数是sess_write 函数。
  • 感谢您的洞察力。因为这在大约 6 个其他项目上运行良好。只有一个让我有这样的感觉。我会研究它,也可能会重构使用实现SessionHandlerInterface 的类而不是函数。
【解决方案2】:

我能想到可能的唯一原因是来自 PHP 文档中关于 session_set_save_handler 的通知:

警告

如果会话在脚本终止时关闭,则当前工作目录会被一些 SAPI 更改。可以使用 session_write_close() 提前关闭会话。

根据您的经验,我猜当前工作目录已更改,因此require_once 找不到该文件。

我会尝试session_write_close(); 添加到您的函数中的某个位置,看看是否可以解决问题。

诚然,不知道为什么 is_file 在这种情况下会返回 true,但也许值得一试。

【讨论】:

  • 做到了!谢谢!仍然不知道为什么,但是当我知道范围使它每次都工作时,一定要关闭它。
  • 仍然不确定到底发生了什么,值得知道究竟是什么原因造成的。
【解决方案3】:

尽管我不能确定,但​​我敢打赌,错误出在其他地方,它只是像你描述的那样投射出来。

为了测试和调试您的代码,您需要使用像PDT 这样的调试器。但是问题是你需要调试你的代码的一部分,它超出了调试器的范围,即会话编写器!要克服这个问题,您可以使用session_write_close。您可以将它放在引导程序末尾的某个位置,或者如果您没有,您可以这样做:

<?php
function shutdown_function()
{
    session_write_close();
}

register_shutdown_function('shutdown_function');

然后通过设置断点,您可以从这里开始调试您的会话代码。如果我赢了,请告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多