title: error: incomplete chunked encoding in php scripts
body: <p>Trying to run some php scripts on a new shared server account, the scripts constantly hang and timeout with no error messages. Only when running the scripts in Chrome with the web developer console up did I get a hint of what was going on: "net::ERR_INCOMPLETE_CHUNKED_ENCODING" is what it would say.</p>
  
  <p>Fiddler2 was slightly more specific: </p>
  
  <p>Fiddler.Network.ProtocolViolation - [#165] Transfer-Encoding: Chunked response did not terminate with a proper zero-size chunk.</p>
  
  <p>...and:</p>
  
  <p>Fiddler.Network.ProtocolViolation - [#165] [HTTPLint #M012] The HTTP Chunked response body was incomplete; most likely lacking the final 0-size chunk.</p>
  
  <p>I made a test script to demonstrate the problem. All it did was sleep() for a random 20-60 seconds, then display a random string. Ten iterations by default.</p>
  
  <p>But the helpdesk at this hosting provider kept insisting that it had something to do with a hard 60 second timeout in the php environment, which I knew was hogwash. So I put together a second test script that used Ajax to call another script multiple times in succession. Again, it was bone simple, just a sleep() for a random time between 40 and 55 seconds, then generate and display a short random string of characters.</p>
  
  <p>So it could never take more than 60 seconds to execute. But it still kept failing, albeit with "net::ERR_EMPTY_RESPONSE" for the xhr call in the Chrome console instead of "net::ERR_INCOMPLETE_CHUNKED_ENCODING".</p>
  
  <p>When I showed this to them, they actually admitted there was a problem, which felt like a victory. But it was short-lived. The very next day they came back and said, so sorry, they couldn't figure out what was causing this, nothing they can do, have I considered upgrading to a vps?</p>
  
  <p>I have become somewhat obsessed. I want to know what the hell is causing this.</p>
  
  <p>The code for the first test script I wrote: </p>
  
  <pre><code>&lt;?php
  
  set_time_limit(3600);
  error_reporting(E_ALL); 
  ini_set('display_errors', TRUE);
  ini_set('display_startup_errors', TRUE);
  
  
  function generateRandomString($length = 10) {
      $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
      $charactersLength = strlen($characters);
      $randomString = '';
      for ($i = 0; $i &lt; $length; $i++) {
          $randomString .= $characters[mt_rand(0, $charactersLength - 1)];
      }
      return $randomString;
  }
  
  isset($_REQUEST["limit"]) ? $limit = $_REQUEST["limit"] : $limit = 10;
  
  
  
  echo '&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"&gt;
  &lt;html&gt;
  &lt;head&gt;
  &lt;meta http-equiv="content-type" content="text/html; charset=iso-8859-1"&gt;';
  
  echo "&lt;title&gt;Test Script&lt;/title&gt;&lt;/head&gt;&lt;body&gt;";
  
  //ob_start ();
  echo "&lt;br&gt;&lt;br&gt;A random delay between 20 and 60 seconds will be generated, then a randomly generated string will be displayed&lt;br&gt;The default limit on iterations is ten&lt;br&gt;When the script terminates normally, the phrase \"test complete\" will be output at the bottom&lt;br&gt;&lt;br&gt;";
   flush();
  
  
  for ($i = 0; $i &lt; $limit; $i++) {
    $delay = mt_rand (20, 60);
    echo "&lt;br&gt;&lt;br&gt;&lt;br&gt;iteration ".($i+1)." - script will now sleep for $delay seconds";
      flush();
    sleep ($delay);
    echo "&lt;br&gt;&lt;br&gt;Here is a random string:&lt;br&gt;";
    $length = mt_rand (50, 100);
    echo generateRandomString($length);
      flush();
  } 
  
  
  echo '&lt;br&gt;&lt;br&gt;...test complete&lt;/body&gt;&lt;/html&gt;';
  ob_end_flush();
  ?&gt;
  </code></pre>
  
  <p>You can go to this page: <a href="http://www.scripttest1.cu.cc/test_script.php" rel="nofollow">http://www.scripttest1.cu.cc/test_script.php</a> to see for yourself what happens when it is run on this server. </p>
  
  <p>The code for the second test script:</p>
  
  <pre><code>&lt;?php
  set_time_limit(600);
  error_reporting(E_ALL); 
  ini_set('display_errors', TRUE);
  ini_set('display_startup_errors', TRUE);
  
  isset($_REQUEST["limit"]) ? $limit = $_REQUEST["limit"] : $limit = 15;
  isset($_REQUEST["longorshort"]) ? $longorshort = $_REQUEST["longorshort"] : $longorshort = "long";
  $start = 1;
  
  echo '&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"&gt;
  &lt;html&gt;
  &lt;head&gt;
  &lt;meta http-equiv="content-type" content="text/html; charset=iso-8859-1"&gt;';
  
  echo "&lt;title&gt;Test Script 2&lt;/title&gt;&lt;/head&gt;&lt;body&gt;";
  echo '&lt;script src="test_script_js7.js"&gt;&lt;/script&gt;';
  
  echo "
    &lt;br&gt;Clicking the button below will start the script running
    &lt;br&gt;The script called via XMLHttpRequest will generate a random delay between 40 and 55 seconds (5-10 seconds if \"longorshort\" is set to \"short\" in the url string), then a randomly generated string will be displayed in the table on the bottom
    &lt;br&gt;The default limit on iterations is fifteen
    &lt;br&gt;When the process terminates normally, the phrase \"test complete\" will be output in the \"Main Info\" cell
    &lt;br&gt;&lt;b&gt;The script called via XMLHttpRequest will &lt;u&gt;never take more than 60 seconds&lt;/u&gt; to complete processing&lt;/b&gt;
  
  ";
  //echo "&lt;img src=http://nzbstar.info/download_batch.png onclick=\"getter($limit, '$start', '$longorshort')\"&gt;&lt;br&gt;";
  echo "&lt;br&gt;&lt;img src=start.jpg onclick=\"getter_outer($limit, '$start', '$longorshort')\"&gt;&lt;br&gt;&lt;a href=\"javascript:master_switch();\"&gt;click here to abort&lt;/a&gt;  ";
  
  echo "&lt;table border=1&gt;&lt;tr&gt;";
  echo "&lt;td valign=top&gt;&lt;div id=main_info&gt;Main Info:&lt;/div&gt;&lt;/td&gt;";
  echo "&lt;td valign=top&gt;&lt;div id=iteration&gt;Iterations:&lt;/div&gt;&lt;/td&gt;";
  echo "&lt;td valign=top&gt;&lt;div id=message&gt;Messages:&lt;/div&gt;&lt;/td&gt;";
  echo "&lt;/tr&gt;&lt;/table&gt;";
  
  echo "&lt;table border=1 style=table-layout:fixed;&gt;&lt;tr&gt;";
  for ($i = 1; $i &lt;= $limit; $i++) {
    echo "&lt;td valign=top&gt;&lt;div class=getter id=post_$i&gt;&lt;i&gt;Result $i&lt;/i&gt;&lt;/div&gt;&lt;/td&gt;";
    if ( ($i%5 == 0) ) {echo "&lt;/tr&gt;&lt;tr&gt;";}
  }
  echo "&lt;/tr&gt;&lt;/table&gt;";
  
  
  
  
  echo '&lt;/body&gt;&lt;/html&gt;';
  ?&gt;
  </code></pre>
  
  <p>...the javascript:</p>
  
  <pre><code>var master_off = false;
  var getter_running_now = false;
  
  function getter_outer(limit, i, longorshort){
    if (getter_running_now) {alert ("Script is already running!"); return;}
    getter_running_now = true;
  
    if (master_off) {document.getElementById("main_info").innerHTML += "&lt;br&gt;master switch off, aborting!"; return;} 
    if (i &gt;= limit) {document.getElementById("main_info").innerHTML += "&lt;br&gt;Got to the next getter when we shouldn't have, there's a bug!"; return;}
    getter(limit, i, longorshort);
  }
  
  function getter(limit, i, longorshort){  
    if (master_off) {document.getElementById("main_info").innerHTML += "&lt;br&gt;master switch off, aborting!"; return;} 
    if (i &gt;= limit) {document.getElementById("main_info").innerHTML += "&lt;br&gt;Got to the next getter when we shouldn't have, there's a bug!"; return;}
  
    var post_number_element = "post_" + i;
  
    var batch_result_script = "test_script_2a.php?longorshort=" + longorshort;
  
    document.getElementById("iteration").innerHTML = "Iterations:&lt;br&gt;Doing iteration: " + i;
    document.getElementById(post_number_element).innerHTML = "doing this one...&lt;br&gt;";
    var xmlhttp=new XMLHttpRequest();
    xmlhttp.onreadystatechange=function(){
      if (xmlhttp.readyState==4){
        if (xmlhttp.status==200){
          var result = "&lt;b&gt;result for " + post_number_element + " is:&lt;/b&gt;&lt;br&gt;" + xmlhttp.responseText + "&lt;br&gt;&lt;span style=color:green;&gt;Success!&lt;/span&gt;";
          document.getElementById(post_number_element).innerHTML = result;
          i++;
          if (i &gt;= limit) {
            document.getElementById("main_info").innerHTML += "&lt;br&gt;&lt;span style=color:green;&gt;Test complete!&lt;/span&gt;";
          }
          else {getter(limit, i, longorshort);}
        }
        else {document.getElementById("message").innerHTML += "&lt;br&gt; - &lt;span style=color:red;&gt;http return status for iteration " + i + " was " + xmlhttp.status + "&lt;/span&gt;";}
      }
    }
    xmlhttp.open("GET",batch_result_script,true);
    xmlhttp.send();
  }
  
  
  
  function master_switch(){
    master_off = true;
    document.getElementById("main_info").innerHTML += "&lt;br&gt;&lt;span style=color:red;&gt;Master Switch Off!&lt;/span&gt;";
  </code></pre>
  
  <p>}</p>
  
  <p>...and the script it calls via ajax:</p>
  
  <pre><code> &lt;?php
  set_time_limit(600);
  error_reporting(E_ALL); 
  ini_set('display_errors', TRUE);
  ini_set('display_startup_errors', TRUE);
  
  
  function generateRandomString($length = 10) {
      $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
      $charactersLength = strlen($characters);
      $randomString = '';
      for ($i = 0; $i &lt; $length; $i++) {
          $randomString .= $characters[mt_rand(0, $charactersLength - 1)];
      }
      return $randomString;
  }
  
  if ( isset($_REQUEST["longorshort"]) &amp;&amp; $_REQUEST["longorshort"] == "short" ) {$delay = mt_rand (5, 10);}
  else {$delay = mt_rand (40, 55);}
  
  
  sleep ($delay);
  echo "&lt;br&gt;Here is a random string:&lt;br&gt;";
  $length = mt_rand (5, 10);
  echo generateRandomString($length);
  
  
  ?&gt;
  </code></pre>
  
  <p>Go here: <a href="http://www.scripttest1.cu.cc/test_script_2.php?longorshort=long" rel="nofollow">http://www.scripttest1.cu.cc/test_script_2.php?longorshort=long</a> to see it in action. Unlike with the first script, the error it generates is "empty response". But I assume the two are related.</p>
  
  <p>Both these scripts work fine on both another shared server, and a vps with LAMP, to which I have access. They also work on <em>this</em> server, for a while, before they fail. The first test script usually gets through a few iterations before it dies. The second one, with the Ajax, will <em>sometimes</em> run right through to completion if the "longorshort" is set to "short".</p>
  
  <p>Also, the first test script works flawlessly from the command line. The second one of course won't work right in that environment. </p>
  
  <p>The server runs PHP Version 5.4.44 and Apache Version 2.4.16 under Linux.</p>
  
  <p>Google has not been my friend. I posted to Stackoverflow and got exactly 5 (five) views, zero responses.</p>
  
  <p>Can anyone here at least toss me a clue? Or failing that, point me to an alternative to Stackoverflow where they might actually answer my question?</p>