title: PHP: trying to get fgets() to trigger both on CRLF, CR and LF
body: <p>I'm reading streams in PHP, using proc_open and fgets($stdout), trying to get every line as it comes in.</p>
  
  <p>Many linux programs (package managers, wget, rsync) just use a CR (carriage return) character for lines which periodically updates "in place", like download progress. I'd like to catch these updates (as separate lines) as soon as they happen.</p>
  
  <p>At the moment, fgets($stdout) just keeps reading until a LF, so when progress is going very slowly (big file for example) it just keeps on reading until it's completely done, before returning all the updated lines as one long string, <em>including</em> the CRs.</p>
  
  <p>I've tried setting the "mac" option to detect CRs as line endings:</p>
  
  <pre><code>ini_set('auto_detect_line_endings',true); 
  </code></pre>
  
  <p>But that doesn't seem to work. </p>
  
  <p>Now, stream_get_line would allow me to set CRs as line breaks, but not a "catch all" solution which treats both CRLF, CR and LF as delimiters. </p>
  
  <p>I could of course read the whole line, split it using various PHP methods and replace all types of linebreaks with LFs, but it's a stream, and I want PHP to be able to get an indication of progress while it's still running.</p>
  
  <p><strong>So my question:</strong></p>
  
  <p>How can I read from the STDOUT pipe (from proc_open) until a LF <strong>or</strong> CR happens, without having to wait until the whole line is in?</p>
  
  <p>Thanks in advance!</p>
  
  <h2>Solution:</h2>
  
  <p>I used Fleshgrinder's filter class to replace \r with \n in the stream (see accepted answer), and replaced fgets() with fgetc() to get more "realtime" access to contents of STDOUT:</p>
  
  <pre><code>$stdout = $proc-&gt;pipe(1);
  stream_filter_register("EOL", "EOLStreamFilter");
  stream_filter_append($stdout, "EOL"); 
  
  while (($o = fgetc($stdout))!== false){
      $out .= $o;                            // buffer the characters into line, until \n.
      if ($o == "\n"){echo $out;$out='';}    // can now easily wrap the $out lines in JSON
  }
  </code></pre>