如何从外部PHP脚本编写/读取joomla会话变量时防止竞争条件?

Try*_*der 9 php session session-variables race-condition joomla2.5

质询

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

细节

我正在使用

  • Joomla 2.5
  • PHP 5.4.3
  • apache 2.2.22
  • mysql 5.5.24
  • 本地主机上的wampserver 2.
  • 我的脚本是Joomla的外部.
  • (cometchat版本3.0.1)

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

说实话,我不确定问题是什么,但我开始认为我的代码正在遭遇竞争条件.我认为Joomla可能会在完成编写之前尝试读取会话信息,或者只是没有设置.缺失的信息似乎是随机选择的,并且间歇性地发生数据丢失.

SCRIPT1

脚本1使用异步ajax请求来获取/设置Joomla会话变量.这将被多次调用.由于设计原因,在ajax响应成功之前,不能再次调用脚本1.

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

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

SCRIPT2

<?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  
}
?>
Run Code Online (Sandbox Code Playgroud)

对比赛条件的测试

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

$qnum[$qnumber]=$jquizstart;
$session->set('var'.$qnumber, $qnum);
Run Code Online (Sandbox Code Playgroud)

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

//Test for race condition in Joomla session

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

测试结果

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

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

编辑

关于如何预防Joomla的种族状况的广泛答案也是受欢迎的.谢谢

EDIT2

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

EDIT3

我的智慧结束了.我使用php 5.3.10在不同的服务器上安装了该网站.我作为未登记的用户尝试了十次或更多次.没有数据丢失.然后我登录到Joomla,几乎每次访问页面时数据都会丢失.如果我没有使用Joomla会话!GRRRrrrrr

EDIT4

现在变得绝望,只是尝试任何事情.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=');
Run Code Online (Sandbox Code Playgroud)

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

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

Try*_*der 2

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

\n\n

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

\n\n
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\nPHP 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\nPHP Warning:  session_destroy(): Session object destruction failed in Z:\\\\libraries\\\\joomla\\\\session\\\\session.php on line 96, referer: http://localhost/cq\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

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

\n\n

cometch 版本 3.0.1

\n\n

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

\n\n

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

\n\n

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

\n\n

具体来说

\n\n
$session->getId();\n$session->get(\'session.counter\');\n$session->isNew();\n$session->getName();\n$session->getState();\n$session->getExpire();\n
Run Code Online (Sandbox Code Playgroud)\n