问题
- 会话数据的间歇性丢失是否可能是由于竞态条件?如果不是,可能是什么问题?
- 从外部 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()
因此,稍后,当此脚本再次触发时,它会检索保存在数据库中的旧值。
仍然不知道是什么导致会话未写入数据库。