输出后未编写 PHP 会话(外部 ajax 调用上的 echo 或 print_r)

Posted

技术标签:

【中文标题】输出后未编写 PHP 会话(外部 ajax 调用上的 echo 或 print_r)【英文标题】:PHP Session not written after Output(echo or print_r on external ajax Call) 【发布时间】:2011-08-03 10:29:21 【问题描述】:

我在调试这个特殊问题时遇到了一些严重的问题,我希望有人知道我做错了什么。

我有一个自定义 CMS 系统工作,它使用段落作为构建块,使用 Ajax(prototypejs) 调用和函数进行更新,这些函数按给定顺序解析 html 块,清理它们并将这些数据保存在关联数组中的会话变量中. 用户登录,会话已创建,我可以在我需要的每个页面中毫无问题地检查此会话。该系统直接在权威网站上运行,因此用户可以实时查看他的更新并像普通用户一样浏览网站,但要进行编辑。 所以,这里没有什么新鲜事。但奇怪的是。

最终用户站点处于编辑模式(管理员用户登录):路径“/”

验证记录状态后,函数处理可编辑内容并将关联数组保存到会话,它还启动一些javascript对象来编辑每个段落。数据实际上已保存,我可以使用外部脚本检查此 php 脚本结束后是否存在。如果我加载新页面(新内容),会话将使用新数据更新)

管理员用户使用 Inplaceeditor 修改一个段落,这个 HTML 块通过 Ajax 发送到一个 php 脚本,该脚本启动命名会话,读取当前会话数据,检查是否应该修改、附加或删除段落并将值重新分配给$_SESSION 中的现有数组键。如果我在分配新数据后创建var_dump() o print_r 到$_SESSION。之后脚本会回显处理过的html,并且ajax 会更新调用页面上的原始段落。

此脚本位于 /admin/cms/...等,这意味着站点根目录内至少有 4 个目录。

当脚本结束时,我使用相同的会话转储脚本检查数据是否真的被写入/提交,但是没有,$_SESSION 只有来自调用页面的原始数据。 相同的 ID,相同的会话名称,相同的 session_start(),但没有数据被写入。 整个操作非常快,所以我虽然可能是速度问题,但脚本在 session_write_close 完成之前就结束了。

但是如果我向$_SESSION 数组添加一个新键并将一些数据放在那里,数据就会被更新和写入。如果我不在此脚本上输出任何内容,而只是处理数据并设置会话变量,它也会得到更新和写入。

好像$_SESSION 数组的一些成员被阻止更新。

我做了什么来跟踪这个错误以及我确定我没有做错什么。

1.- register_globals 当然不可以 2.- session_name()session_start() 始终存在并在给定 命令。我曾经有多个session_start() -close 在同一页面上 使用多个命名会话,但 细化问题这不再 所以。 3.- 我在处理会话数据后使用session_write_close()。还有 试过了,让php决定 何时提交数据,但没有运气。 4.- 我仅将 cookie 用于 SID。 5.- 会话存储在 /tmp 上,我可以看到数据正在更新。 我也尝试使用自定义保存 DB 上的处理程序,但同样的问题, “_write”只有在没有输出时才会被调用。 我在 php.net、***、google 等网站上搜索了这个主题。我从不未经调查就问,这是我多年来的第一次……但这太不合逻辑了,一定是没有想到的小事。

最奇怪的是,当我只处理没有输出的数据时,$_SESSION 更新正常。但是,如果我之后通过添加输出来修改此脚本并重试,而不是只存在新的(最后一个)值,我会取回原始值,即由调用页面首先创建的那个值,有时在玩了几次之后次! PHP 不能在脚本之间缓存值,或者?我没有全局变量。

我真的一无所知。这个系统在 PHP4.3 上运行完美,因为我的两个用户使用 5.3.3 来校准数据,所以我检查了,是的,有严重的问题。今天我更新到(5.3.6),我无法提交这个会话值。

通过 Ajax 调用的脚本代码:

<?
session_cache_limiter('nocache'); 
session_name("CMS_ses");
session_start();
include('../htmLawed/htmLawed.php');
include("utils_cms.php");
include("../../../php/utils_array.php");

$value=$_POST['value'];
$editorId=$_POST['editorId'];
$clase=$_POST['clase'];
$editorId=str_replace("pre","",$editorId);
$value=html_entity_decode(stripslashes($value),ENT_QUOTES);
if (strlen(trim($value))==0)
    
    die();
    
$value="<div id=\"$editorId\"  class=\"$clase\">$value</div>";

$newXHTML=$value;
$retorno=CMS_nuevoBloque($newXHTML,$editorId);
$_SESSION['data']['CMSeditores']=$retorno[1];   
$_SESSION['data']['CMScont']=$retorno[2];   
session_write_close();

print_r($retorno[0]); //Offending part...without everything works
?>

这里真的没有什么奇怪的......主页代码更简单,没有奇怪的php指令等。

这里是调用者页面的标题

include 'php/db.php';
$len=$_GET['len'];
$sec=$_GET['sec'];
$cont=$_GET['cont'];
$admfin=$_GET['admfin'];
$fecha=$_GET['fecha'];
$token=$_GET['token'];
$cur=$_GET['cur'];

$PHP_SELF=$_SERVER['PHP_SELF'];
session_cache_limiter('nocache');
session_name("CMS_ses");
session_start();

$passvar='';
unset($adm);
if ((!empty($_SESSION['cms_logged'])) and (!isset($admfin)) )
    
    $nivelpermisos=$_SESSION['cms_logged_group'];
    $useractual=$_SESSION['cms_logged'];
    $adm=1;

    
elseif (empty($_SESSION['cms_logged']))
    
    unset($useractual);
    
    //.........rest of the code  

更新:我做了深夜测试,发现了一些我不明白的地方。请帮助: 它不仅与会话有关,还与 mysql 查询有关。相同的代码,但我没有尝试写入$_SESSION 数组,而是使用 session_id 对 Innodb 表进行了简单更新。当我输出一些代码时,更新确实被执行,(我可以输出查询字符串并且没有mysql_error() 或通知)问题,但是检查数据库该行没有得到更新。如果脚本和查询确实被提交,则输出输出。唯一常见的是会话开始并输出。

我重新启动了 Apache 等(谁知道)但没有运气。然后我做了一些非常愚蠢的事情,因为这是服务器端的事情。我将浏览器更改为 Firefox(使用 safari),一切正常!好的,重新检查,回到 safari,没有任何效果。两者并排运行,同样的问题。 PHP是服务器端,不同的浏览器如何处理不同的代码,浏览器可以说apache回滚,请求未处理或调用相同的脚本两次而不通知(检查safaris开发者控制台,脚本只调用一次)? safari 是否可以因为“认为”ajax 失败而静默重新提交数据?我使用 firebug 和 Safaris 开发工具检查了标头,没什么奇怪的,但是每当我使用 safari 进行 Ajax 调用时,调用者页面都会重新加载数据(Aka 连接到服务器...)。

我真的什么都不懂。

【问题讨论】:

@_@ 这让我眼花缭乱。 好吧,它越来越陌生了,我真的需要一些帮助: 非常难的问题。如果有的话,这是值得加分的。谁愿意? error_reporting 设置为 E_ALL,display_errors 设置为“1”?如果没有,那就去做吧。这可能是一些标题问题。另外,在使用 MySQL 存储会话时,是否提交事务并且在提交之前没有发生错误? 2 个问题 - 1. php/db.php 中是否有任何东西操纵会话? 2. 你是否在你的代码上做任何标题重定向?我遇到了会话问题,这是因为在我的所有标题重定向后我没有退出。 【参考方案1】:

我遇到了类似的问题(如果我理解正确的话)。我需要在脚本完成运行后强制写入会话数据(用于自定义会话驱动程序)。可以注册一个关闭函数,该函数应该在脚本完成后运行。

也许这会解决(或帮助您解决)您的问题。

http://php.net/manual/en/function.register-shutdown-function.php

【讨论】:

不是完美的答案,但至少您提供了一个具体的解决方案并且没有提出任何问题。恭喜!【参考方案2】:

感谢您的帮助。我以正确的顺序做所有事情,但仍然没有写入会话数据。会话名称是必要的,因为有时我们使用相同的自定义 CMS 测试同一域上的许多站点。所以,最后,在做了很多测试但没有运气之后,我发现注册全局变量在这个服务器上是活动的(我们从不使用它,编写代码时当然考虑到了这个选项),但是它与会话混淆了!关闭它带来了巨大的变化。没有更多的问题。我还在 DB 中创建了一个自定义会话处理程序,因此我可以以更集中的方式跟踪问题。 结论:永远不要使用注册全局变量+命名会话,会话中的复杂数据。 无论如何,我会给这个问题更多的时间和更多的测试。 Ajax 调用有时也太快了,我不得不放一个 sleep 命令,所以写会话数据真的完成了。谢谢

【讨论】:

【参考方案3】:

我不确定,但我认为很少有建议可能会有所帮助。

在刷新页面以进行测试之前删除会话 cookie :)

确保您没有为任何数组分配包含竖线字符 (|) 的键。这将防止会话数据被序列化和保存。

执行 session_regenerate_id(true);许多情况下 session_write_close 似乎与 session_regenerate_id 无关。或者如果您依赖 SID,则在 session_write_close() 之后执行 session_start() ;在您的情况下,我认为这是给您带来问题的原因,因为您每次都在结束当前会话而不是为下一页重新启动它。希望你明白我的意思。进一步确保数据实际上被刷新到浏览器使用 ob_end_flush();

我无法理解两者之间的联系

$_SESSION['data']['CMSeditores']=$retorno[1];   
$_SESSION['data']['CMScont']=$retorno[2];   

$nivelpermisos=$_SESSION['cms_logged_group'];
    $useractual=$_SESSION['cms_logged'];

我认为您需要在导致问题的数据部分而不是管理员登录部分粘贴更多代码。

希望对你有帮助。:)

【讨论】:

【参考方案4】:

您是否有任何理由两次建立会话名称?过去我遇到过问题,我会在没有名称的情况下建立会话,然后另一段脚本(不是我的)正在命名会话。即使在脚本结束时,我也能够打印出会话变量,但是一旦我进入新页面,我的会话就被遗忘了。直到我将第二个脚本中包含的名称复制到我的会话调用中才解决。

检查没有使用其他会话名称;另外,也许在第一次调用会话时尝试只命名一次会话?

【讨论】:

【参考方案5】:

问题:您是否首先调用 session_start()... 在任何输出到浏览器之前和分配任何变量之前?

听起来很傻,但试一试。

另外,您为什么使用会话名称?真的没有必要,除非你有很多同名的会话变量用于不同的目的,如果是这样,那么你需要先解决这个问题!

【讨论】:

【参考方案6】:

我也遇到过类似的问题,但几年前就遇到了。 IE 以自己的方式操纵标头,这会导致奇怪的 php 错误,您可以在 php.net 档案中找到这些错误。

@Diego Pino Navarro,请查看this help page 并找到 Safari 和 php 的问题。

我还找到了"Safari "forget" http-authentication's logon-information"。

【讨论】:

以上是关于输出后未编写 PHP 会话(外部 ajax 调用上的 echo 或 print_r)的主要内容,如果未能解决你的问题,请参考以下文章

会话过期后未调用 @PreDestroy

关闭后如何重新打开 php 会话?

PHP会话已经开始[重复]

使用 AJAX 自动刷新在 Web 应用程序上超时会话的方法

执行 AJAX 请求后未应用 CSS

如何修复谷歌不可见 reCAPTCHA 验证后未提交的 Ajax 表单