【问题标题】:PHP Global variable not being imported into session handlerPHP全局变量未导入会话处理程序
【发布时间】:2009-09-21 06:50:08
【问题描述】:

我正在使用 ADOdb。出于某种原因,实际的 $db 没有被导入到“写入”函数中。

该函数旨在导入$db 的实际值。相反,它为$db 分配了一个空值:

<?php
// load ADODB class
include(DIR_WS_CLASSES . "adodb5/adodb.inc.php");

$db = NewADOConnection(DB_TYPE);
$db->Connect(DB_SERVER, DB_SERVER_USERNAME, DB_SERVER_PASSWORD, DB_DATABASE);


class SessionManager {
    var $life_time;

    function SessionManager(){
        global $db;
        // Read the maxlifetime setting from PHP
        $this->life_time = get_cfg_var("session.gc_maxlifetime");

        // Register this object as the session handler
        session_set_save_handler(array(&$this, "open"), 
                                array(&$this, "close"), 
                                array(&$this, "read"), 
                                array(&$this, "write"), 
                                array(&$this, "destroy"), 
                                array(&$this, "gc"));
    }

    function open($save_path, $session_name){
        global $sess_save_path;
        global $db;

        $sess_save_path = $save_path;

        return true;
    }

    function close(){
        global $db;
        return true;
    }

    function read($id){
        global $db;
        // Set empty result
        $data = '';

        // Fetch session data from the selected database
        $time = time();
        $newid = $db->qstr($id, get_magic_quotes_gpc());

        $sql = "SELECT session_data 
                FROM sessions 
                WHERE session_id = $newid 
                AND expires > $time";

        $rs = $db->Execute($sql) or die($db->ErrorMsg());
        $a = $rs->RecordCount();

        if($a > 0){
            $data = $rs->fields['session_data'];
        }

        return $data;
    }

    function write($id, $data){
        global $db;
        // Build query                
        $time = time() + $this->life_time;
        $newid = $db->qstr($id, get_magic_quotes_gpc());
        $newdata = $db->qstr($data, get_magic_quotes_gpc());
        $sql = "REPLACE sessions
                (session_id, session_data, expires) 
                VALUES($newid, $newdata, $time)";

        $rs = $db->Execute($sql) or die($db->ErrorMsg());

        return TRUE;
    }

    function destroy($id){
        global $db;
        // Build query
        $newid = $db->qstr($id, get_magic_quotes_gpc());
        $sql = "DELETE FROM sessions 
                WHERE session_id = $newid";

        $db->Execute($sql) or die($db->ErrorMsg());

        return TRUE;
    }

    function gc(){
    // Garbage Collection
        global $db;
        // Build DELETE query.  Delete all records that passed expiration time
        $sql = "DELETE FROM sessions 
                WHERE expires < UNIX_TIMESTAMP()";

        $db->Execute($sql) or die($db->ErrorMsg());

        // Always return TRUE
        return true;
    }
}


// initialize session
$sess = new SessionManager();
session_start();
?>

为什么实际的$db 没有在'write'函数中导入?

我该如何解决这个问题?

【问题讨论】:

  • 你怎么知道 $db 是空的?你得到什么错误信息?充实后,发布的代码可以正常工作。请发布一个最小的测试用例。您还可以尝试使用调试器(例如 Eclipse+PDT+XDEBUG)来跟踪正在发生的事情。请注意,全局变量是邪恶的;更好的解决方案是将$db 成员添加到对象write 是一种方法。
  • 您能告诉我们您遇到了什么错误吗?是不是说某个函数调用了未定义的对象。或者是其他东西。我完全相信您在某处分配了 $db 其他东西,或者您正在关闭连接。类似的东西。告诉我们您遇到的错误。
  • 我收到致命错误:在第 64 行对 E:\applications\myfurni\webroot\includes\classes\sessions\sessions.php 中的非对象调用成员函数 qstr()
  • Nirmal 请参阅下面的第二个答案。在您的代码中检查它。我相信它会解决你的问题。
  • 据我所知 session_start();应该在页面顶部。

标签: php adodb-php


【解决方案1】:

为那些不听评论的人编辑;)

“从 PHP 5.0.5 开始,写入和关闭处理程序在对象销毁后调用,因此不能使用对象或抛出异常。但是对象析构函数可以使用会话。可以从析构函数调用 session_write_close() 来解决鸡和蛋的问题”

所以我们的想法是有一个像这样的析构函数:

function __destruct() {
    session_write_close();
}

这样对象就可以在写入和关闭处理程序中使用。

然后,为了安全起见,在 write & close 中重新实例化 $db,因为全局 $db 析构函数很可能在 SessionHandler 之前调用。

【讨论】:

  • 也许你应该多放一些代码,这样我们就可以了解一些上下文。
  • 你忘记了“global $db;”在 write 方法中。
  • 但是我很难理解你的逻辑......为什么 $db 不是你班级的成员?
  • 没有。我错误地发布了我的最新试用版。现在我已经更正了代码示例。请看一下,看看你是否可以帮助我。谢谢。
  • 哦,我想我明白了。在会话关闭/保存之前,全局 $db 变量很可能被垃圾收集。您应该仔细阅读有关会话自定义处理程序的文档。您可能需要在某个时间点重新创建数据库连接。
【解决方案2】:

您要么不将$db 分配为全局值,要么将其分配一个空值。

【讨论】:

  • 我不想将空值分配给 $db。全局 $db 正在分配空值而不是导入原始值。
  • global $db 没有分配任何东西。它基本上将$db 导入本地命名空间。所以问题是你是否在全局命名空间中为$db 分配了任何东西(在所有函数之外或在具有global $db 声明的函数内部。
  • 是的,一个类在所有函数之外被分配给$db,它出现在页面的开头附近。
  • 这段代码是我为保存到数据库而编写的会话处理函数的一部分。现在我怀疑会话的编写是发生在脚本线程内部还是外部。
  • 赋值后检查$db的值了吗?问题是,每个新手都怀疑是他的运行时环境出了问题(我们都这样做),但几乎总是没有,所以检查你的流程和语法。
【解决方案3】:

我不是 PHP 专家,但也许你正在覆盖它。前后尝试 $db 的回显

全局 $db;

而且:你确定你给 $db 分配了任何东西(在函数内部查看它的值之前)?

【讨论】:

  • 我试过了,发现在任何地方都没有发生覆盖。在页面顶部为 $db 分配了一个类。所以,我很确定变量有一个预设值。此外,全局 $db 正在其他功能中工作!
【解决方案4】:

在函数内外尝试 $db 上的 var_dump。

【讨论】:

  • 当我在函数外执行 var_dump 时,它显示的是预期值。如果在使用全局之前在里面,它会给出一个未定义的变量错误。如果在全局之后,则显示空值。
【解决方案5】:

我很确定是什么问题。 当此文件包含在全局范围内时,您的代码将正常工作。 但是考虑一下:

$a=1;
function displaya()
{
    global $a;
    var_dump($a);
}

当您运行此文件时,您将看到int(1) 作为输出。

但考虑另一个文件:

function abc()
{
include("above-stated-file.php");
displaya();
}

abc();

现在它将显示NULL

原因是在第二个文件中。您的第一个文件包含在本地上下文中,而不是全局上下文中。这就是为什么global $a 不起作用的原因。

改成:

$GLOBALS['a']=....;

当你使用它时:$a=$GLOBALS['a'];

【讨论】:

  • 我试过了,但仍然出现错误通知:未定义的索引:第 59 行的 E:\applications\myfurni\webroot\includes\classes\sessions\sessions.php 中的 db
  • 我是这样分配的:$GLOBALS['db'] = NewADOConnection(DB_TYPE);
【解决方案6】:

试试这两件事:

  1. 分配

    $GLOBALS['db']=...;
    

    而不是

    $db=...;
    

    在您的全局脚本中。然后在您的函数中将其引用为$db=$GLOBALS['db'];

    原因:您可能将$db 分配在某个非全球性的地方。

  2. 将其设为您班级的私有财产。提供 getter,但不提供 setter。而是从您的构造函数中设置它。

【讨论】:

    【解决方案7】:

    您似乎没有在上述代码中的任何地方初始化$db

    我希望在某处看到$db = new ADO("myserver,mydb,user,password") 电话 在代码中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-08
      • 2012-11-08
      • 1970-01-01
      • 2013-04-27
      • 1970-01-01
      • 2014-03-25
      • 2021-07-14
      • 1970-01-01
      相关资源
      最近更新 更多