【发布时间】:2012-10-14 16:28:52
【问题描述】:
问题
- 会话数据的间歇性丢失是否可能是由于竞争条件造成的?如果不是,可能是什么问题?
- 如何在写/读 joomla 时防止出现竞态条件 来自外部 php 脚本的会话变量?
详情
我正在使用
- 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
}
});
这是我在脚本 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
}
?>
比赛条件测试
我认为数据可能会被覆盖,所以我使用下面的代码进行了快速测试。每次我更新会话数组时,我都会使用更新的数据创建一个新的会话变量。
$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 中防止竞争条件的一般性答案也是受欢迎的。谢谢
EDIT2
我开始怀疑 php5.4 和 Joomla 是否有问题。我听说他们一起玩得不好,我不记得在我从 php5.3 更新之前遇到过这个问题。不过我可能是错的。
EDIT3
我束手无策。我使用 php 5.3.10 将网站安装在另一台服务器上。我以未登录用户的身份尝试了十次或更多次。没有数据丢失。然后我登录到 Joomla,几乎每次访问该页面时数据都丢失了。如果我不必使用 Joomla 会话就好了!呸呸呸
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=');
我发现有趣的是,jstart 在检查过程中包含更新的信息,但在完成时它丢失了。
我不太确定这意味着什么,但我想如果我们将JFactory::getSession() 视为一个变量,那么该变量仅针对此脚本进行更新(有点像局部变量?),JFactory::getSession() 的数据库值不管原因未写入数据库。因此,稍后,当此脚本再次触发时,它会检索保存在数据库中的旧值 JFactory::getSession()。
仍然不知道是什么导致会话未写入数据库。
【问题讨论】:
-
在 Joomla 中不要使用 isset 使用 getvar $change = JRequest::getVar("change",'value if change does not exist');无论如何,这是我的第一个想法。
-
好点。从现在开始我将使用它。
标签: php session session-variables joomla2.5 race-condition