session_start()在响应发送到浏览器后导致大量警告

时间:2014-08-22 00:04:24

标签: php http-headers session-variables

修改

这就是代码的用途:

  1. 用户点击一个按钮,在服务器上启动一个长时间运行的进程(实际上没有上传文件,只是为了让代码正常工作)
  2. 如果流程在发送响应之前完成,则用户的浏览器似乎没有发生任何事情,他们可能会再次点击/重新加载页面/做其他不受欢迎的事情
  3. 需要立即回复让用户知道他们必须等待
  4. 进度指示器显示进程已达到多远,即用户必须等待多长时间
  5. 我只需要一些方法可以实时告诉用户服务器上的进展情况。点击后,一切都在服务器上发生,直到完成该过程,然后他们得到重定向信号并转到下一页。

    Flowchart

    如果我需要丢弃所有代码并尝试别的东西我会做的!

    结束编辑

    这个问题已被多次询问,但我找不到真正有用的答案。

    我是第一次设置进度指示器,除了很多警告外,我主要使用它。这是代码:

    <?php
    session_name('test');
    $filesize = 10000000;
    
    // Allow script to send response but keep running afterwards
    ignore_user_abort(true);
    ob_start();
    header('Connection: close');
    header('Content-Length: ' . ob_get_length());
    ob_end_flush();
    //ob_flush();
    flush();
    
    for ($i = 0; $i < $filesize; $i += rand(4096, 8192)) { // Just testing...
      ob_start();
      @session_start();
      $_SESSION['progress'] = $i;
      session_write_close();
      ob_end_clean();
    }
    ob_start();
    @session_start();
    $_SESSION['progress'] = $filesize;
    session_write_close();
    ob_end_clean();
    exit;
    ?>
    

    我有第二个脚本,然后读取$_SESSION中的值,这是很好的工作。 如果我在上面的脚本中移除了@之前的session_start();,我会收到以下大量错误:

    [Fri Aug 22 08:59:59.109375 2014] [:error] [pid 4100:tid 1248] [client 127.0.0.1:2577] PHP Warning:  session_start(): Cannot send session cookie - headers already sent in C:\\server\\Apache24\\htdocs\\localhost\\SRI\\progress.php on line 36, referer: http://localhost/SRI/progress.php
    [Fri Aug 22 08:59:59.109375 2014] [:error] [pid 4100:tid 1248] [client 127.0.0.1:2577] PHP Stack trace:, referer: http://localhost/SRI/progress.php
    [Fri Aug 22 08:59:59.109375 2014] [:error] [pid 4100:tid 1248] [client 127.0.0.1:2577] PHP   1. {main}() C:\\server\\Apache24\\htdocs\\localhost\\SRI\\progress.php:0, referer: http://localhost/SRI/progress.php
    [Fri Aug 22 08:59:59.109375 2014] [:error] [pid 4100:tid 1248] [client 127.0.0.1:2577] PHP   2. session_start() C:\\server\\Apache24\\htdocs\\localhost\\SRI\\progress.php:36, referer: http://localhost/SRI/progress.php
    [Fri Aug 22 08:59:59.109375 2014] [:error] [pid 4100:tid 1248] [client 127.0.0.1:2577] PHP Warning:  session_start(): Cannot send session cache limiter - headers already sent in C:\\server\\Apache24\\htdocs\\localhost\\SRI\\progress.php on line 36, referer: http://localhost/SRI/progress.php
    [Fri Aug 22 08:59:59.109375 2014] [:error] [pid 4100:tid 1248] [client 127.0.0.1:2577] PHP Stack trace:, referer: http://localhost/SRI/progress.php
    [Fri Aug 22 08:59:59.109375 2014] [:error] [pid 4100:tid 1248] [client 127.0.0.1:2577] PHP   1. {main}() C:\\server\\Apache24\\htdocs\\localhost\\SRI\\progress.php:0, referer: http://localhost/SRI/progress.php
    [Fri Aug 22 08:59:59.109375 2014] [:error] [pid 4100:tid 1248] [client 127.0.0.1:2577] PHP   2. session_start() C:\\server\\Apache24\\htdocs\\localhost\\SRI\\progress.php:36, referer: http://localhost/SRI/progress.php
    

    我真的不喜欢使用@,因为它只会抑制警告;我宁愿修理它们。是否有一种更清洁的方法来实现这一目标?

    我已经删除了以下内容:

    • UTF-8 BOM
    • flush()与下一个session_start()
    • 之间的输出
    • 为每session_start()
    • 使用输出缓冲(ob)
    • 使用pcntl_fork()(在Apache下不起作用)

    第二批ob_start()有助于及时响应浏览器,但我的错误日志仍在填满!我怀疑,因为flush()已经发送了标题,我仍然在同一个脚本中,这就是警告不断发生的原因。我有一个用于开发的WAMP服务器,但是将工作程序传输到LAMP服务器。

2 个答案:

答案 0 :(得分:0)

在PHP中发送任何输出后,您无法调用session_start()或header()。这是因为您正在使用脚本创建HTTP响应,最终看起来像这样:

HTTP/1.1 200 OK
Server: nginx/1.6.1
Cookie: ...

// Content goes here

一旦开始输出内容,就无法输出标题,因为这会导致格式错误的响应。每次调用ob_end_flush()时,都会发送输出缓冲区的内容。这意味着您无法在其后执行session_start()。

在上面的代码中,您应该能够删除所有内容并执行:

<?php

  session_name('test');
  session_start();

  $filesize = 10000000;

  // whatever else you want to do

  $_SESSION['progress'] = $filesize;

还要确保在打开php括号之前没有空格。这通常是调用session_start()时获取错误的罪魁祸首。有时它也可以通过包含文件上的尾随空格来实现。

答案 1 :(得分:0)

好的,所以我通过将我的两个脚本(进程和进度)分成三个脚本(准备,处理和进度)来解决问题,这三个脚本由同一网页的三个不同部分调用:

  1. 发送“准备”请求。服务器初始化一些变量并将其保存在$_SESSION中。成功后转到第2步
  2. 发送“处理”请求。服务器在步骤1中使用先前存储在$_SESSION中的变量开始运行长进程。成功加载内容/重定向到下一页
  3. 在第2步运行时定期发送“进度”请求。关于页面上的成功更新进度指示器
  4. 因为我正在使用XHR / AJAX这个解决方案似乎可以解决问题!我不再需要“发送输出但继续运行”的解决方案。