9

问题

  • 会话数据的间歇性丢失是否可能是由于竞态条件?如果不是,可能是什么问题?
  • 从外部 php 脚本写入/读取 joomla 会话变量时,如何防止出现竞争条件?

细节

我在用着

  • Joomla 2.5
  • PHP 5.4.3
  • 阿帕奇 2.2.22
  • mysql 5.5.24
  • 本地主机上的 wampserver 2。
  • 我的脚本在 Joomla 之外。
  • (cometchat 版本 3.0.1)

该脚本使用异步 ajax 请求多次获取和设置 joomla 变量。我在会话中存储的数据是一个数组。一些阵列数据间歇性地丢失。一旦用户登录并使用脚本,它似乎会更加一致地发生。

老实说,我不太确定问题出在哪里,但我开始认为我的代码遇到了竞态条件。我认为 Joomla 可能会在完成写入之前尝试读取会话信息,或者它只是没有设置。丢失的信息似乎是随机选择的,数据的丢失是间歇性发生的。

脚本1

脚本 1 使用异步 ajax 请求来获取/设置 Joomla 会话变量。这将被多次调用。由于设计原因,直到 ajax 响应成功后才能再次调用脚本 1。

$.ajax(
            {   cache:false,
                url: 'script2.php',
                data: { 'change': change},              
                dataType: 'json',               
                success: function(data) 
                {
                    //do something
                }
            });

这是我在脚本 2 中用于访问 Joomla 和获取/设置会话数据的代码的粗略概念。

脚本2

<?php
//some code omitted for brevity

$app = &JFactory::getApplication('site');/
$app->initialise();                     

$nottimedout=false;
$session = JFactory::getSession();
$jquizstart = date( 'Y-m-d H:i:s', time() );    //<<-- time of access       
$nottimedout = $session->has('jtimedout');

if ($nottimedout==true)
{
    $jqid = $session->get('jqid');                //<<-- get array from session
    if (isset($_GET['change'])) 
    { 
        $qnumber=$_GET['change'];   
        $firephp->log($qnumber, 'qnumber');
        $jqid[$qnumber][3]=$jquizstart;     //<<--  add time of access to array
        $firephp->log($jqid[$qnumber][3], '$jqid[$qnumber][3]');
        $session->set('jqid', $jqid);       //<<-- store array in Joomla with updated data
    } 
    else
    {
        $firephp->log('CHANGE NOT SET');
    }

    echo json_encode(
                      array("nottimedout" => $nottimedout) 
                    );                  
}
else 
{
    //Do something  
}
?>

比赛条件测试

我认为数据可能会被覆盖,所以我使用下面的代码进行了快速测试。每次更新会话数组时,我都会使用更新的数据创建一个新的会话变量。

$qnum[$qnumber]=$jquizstart;
$session->set('var'.$qnumber, $qnum);

在另一个脚本中,当网站完成更新时,我检查了每个单独的会话以查看它们是否已设置。

//Test for race condition in Joomla session

        for ($counter=0; $counter<=$totalnumber-1; $counter++)
        {
            $racecondition=$session->get('var'.$counter);               
            $firephp->log($racecondition, 'var'.$counter.'=');
        }

测试结果

jqid 中缺少的数组信息也从相应的单个会话(仅包含更新数据的会话)中丢失,因此似乎不是数据被覆盖的问题。不过,我不确定这是否反驳了竞争条件。

任何关于您认为可能发生的事情以及如何解决此问题的建议都将受到欢迎。

编辑

即使是关于如何在 Joomla 中防止竞争条件的一般性答案也是受欢迎的。谢谢

编辑2

我开始怀疑 php5.4 和 Joomla 是否有问题。我听说他们一起玩得不好,我不记得在我从 php5.3 更新之前遇到过这个问题。不过我可能是错的。

编辑3

我无计可施。我使用 php 5.3.10 将网站安装在另一台服务器上。我以未登录用户的身份尝试了十次或更多次。没有数据丢失。然后我登录到 Joomla,几乎每次访问该页面时数据都丢失了。如果我不必使用 Joomla 会话就好了!GRRRrrrr

编辑4

现在变得绝望,只是尝试任何事情。JRequest 没有用,尽管我还是应该使用它。

由于登录时问题出现的频率更高,我认为这一定是因为会话中存储的内容比用户是访客时要多得多。Jqid 是一个大数组,所以我没有一直更新它,而是尝试制作几个较小的数组并在适当的时候更新每个数组。它完全没有效果。同样,无论如何我可能应该这样做。

EDIT5B

在尝试寻找临时解决方案时,我尝试测试会话是否已成功更新(这是在更新会话的同一脚本中完成的)。

这是我用来检查 jstart 的代码。

//jstart updated
$session->close('jstart');
$try_again_session = JFactory::getSession();
$newjstart=$try_again_session->get('jstart');
$firephp->log($newjstart[$qnumber], 'confirm_jstart_set=');

我发现有趣的是,jstart 在检查期间包含更新的信息,但在完成时它丢失了。我不太确定这意味着什么,但我想如果我们将JFactory::getSession()其视为一个变量,那么该变量仅针对该脚本进行更新(有点像局部变量?),JFactory::getSession()无论出于何种原因,数据库值都没有写入数据库。JFactory::getSession()因此,稍后,当此脚本再次触发时,它会检索保存在数据库中的旧值。

仍然不知道是什么导致会话未写入数据库。

4

2 回答 2

3

虽然我还没有找到解决问题的方法,但我找到了解决方法。这不是一个好方法,但它有效。每当更新会话变量时,将信息存储在 cookie 中作为备份。稍后在脚本中,检查是否缺少信息并根据需要从 cookie 进行更新。

我宁愿不这样做,但看起来我别无选择。

于 2012-11-04T06:59:57.953 回答
2

终于看起来我找到了解决方案!

我碰巧检查了 apache_error.log (wamp/logs/apache_error.log) 中的错误日志 有很多与会话相关的错误,例如

PHP Warning:  session_start(): Cannot send session cache limiter - headers already sent (output started at Z:\\libraries\\joomla\\session\\session.php:96) in Z:\\libraries\\joomla\\session\\session.php on line 532, referer: http://localhost/cq
PHP Warning:  Cannot modify header information - headers already sent by (output started at Z:\\libraries\\joomla\\session\\session.php:96) in Z:\\cometchat\\cometchatcss.php on line 68, referer: http://localhost/cq
PHP Warning:  session_destroy(): Session object destruction failed in Z:\\libraries\\joomla\\session\\session.php on line 96, referer: http://localhost/cq

关闭 cometchat 并重新启动服务器后,我发现间歇性会话数据丢失似乎停止了。更改后 apache_error.log 下不再出现错误

由于问题是间歇性的,我不能 100% 确定它是否已解决,但我有足够的信心将其写成解决方案。我正在使用

彗星版本 3.0.1

我会继续测试它。如果解决方案成立,我将尝试更新版本的 cometchat 并发布结果。

更新:它似乎与 cometchat 有关。我已经安装了最新版本 4.6.0,但会话丢失仍在发生。我可以通过在包含我的脚本的页面上排除 cometchat 来解决这个问题。

有用信息: 以防万一其他人发现自己在 Joomla 会话中苦苦挣扎-我发现这个网站非常有用http://tutsforu.com/joomla-module-tutorial/8-joomla-tutorial/75-using-session-in-joomla .html

具体来说

$session->getId();
$session->get('session.counter');
$session->isNew();
$session->getName();
$session->getState();
$session->getExpire();
于 2012-12-28T01:03:26.243 回答