3v4l.org

run code in 300+ PHP versions simultaneously
<?php /** * Demonstration of a PHP bug: Capturing output as a string with an output buffer stops working * as soon as PHP has detected a client disconnect. * * Verified with different PHP 5.4 and 5.5 builds on Linux and Win7 with Apache 2.2, Apache 2.4 * and PHP-FPM SAPIs. * * PHP-FPM note: When testing with PHP-FPM, make sure the web server does not buffer the reponse. * For nginx, set "gzip off;" and "fastcgi_buffering off;" (only supported by version 1.6 and * above) in the vhost configuration. */ // We record the results in this file after the client connection was closed define('LOG_FILE', __DIR__ . '/ob-bug-test' . PHP_VERSION . '.log'); ini_set('error_log', __DIR__ . '/error.log'); // Let's not bother with HTML... header('Content-Type: text/plain; charset=utf-8'); // Prevent script from exiting when client disconnects ignore_user_abort(true); // Flush & close all output buffers to make the echo/flush calls // below send data to the client immediately while (ob_get_level()) { ob_end_flush(); } // Init log file echo "Results will go to " . LOG_FILE . "\n"; log_message("\n" . date('# Y-m-d H:i:s')); // Run the tests once before the client disconnects test_echo_output_buffer_capturing(); test_gd_output_buffer_capturing(); // Wait until client has closed connection while (!connection_aborted()) { log_message("\nClient is still connected"); // PHP only detects a client disconnect when trying to actually // send rsponse data to the client echo "Abort the request in your browser now by pressing " . "<Esc> or clicking the little X in the adress bar...\n"; flush(); sleep(1); } log_message("\nClient is now disconnected (connection_aborted() returns true)"); // Run the tests again, after client has disconnected test_echo_output_buffer_capturing(); test_gd_output_buffer_capturing(); // ============================================================================= /** * This is what e.g. the popular template engine Twig does when rendering a template. * * A common case when this might happen after client diconnect: when Twig is used to * render the body of an e-mail at the end of a long-running request. */ function test_echo_output_buffer_capturing() { ob_start(); echo 'Hello World'; $captured_output = ob_get_clean(); log_message("\nCapture echo in output buffer:"); log_message(' - captured string length: ' . strlen($captured_output)); } /** * The GD image output functions can either write to a file or to stdout. * * When the binary image data is needed as a string to e.g. write it to a DB blob field, * using an output buffer is a shorter and faster method than writing to a temp file. */ function test_gd_output_buffer_capturing() { // $img = imagecreatetruecolor(100, 100); // ob_start(); // // second imagejpeg() arg === null means "send image data to client/stdout" // // Really strange behaviour: when the client connection is closed, imagejpeg() // // triggers a warning (unrecoverable error) but returns true!? // $success = imagejpeg($img, null, 100); // $captured_output = ob_get_clean(); // imagedestroy($img); // log_message("\nCapture binary image data in output buffer:"); // log_message(' - image data length: ' . strlen($captured_output)); // log_message(' - imagejpeg() return value: ' . ($success ? 'true' : 'false')); } function log_message( $message ) { if (false === file_put_contents(LOG_FILE, $message . "\n", FILE_APPEND)) { die("Sorry, it seems " . LOG_FILE . " is not writable. Aborting...\n"); } }
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 42) Position 1 = 17
Branch analysis from position: 17
2 jumps found. (Code = 44) Position 1 = 20, Position 2 = 15
Branch analysis from position: 20
1 jumps found. (Code = 42) Position 1 = 45
Branch analysis from position: 45
2 jumps found. (Code = 44) Position 1 = 49, Position 2 = 36
Branch analysis from position: 49
1 jumps found. (Code = 62) Position 1 = -2
Branch analysis from position: 36
2 jumps found. (Code = 44) Position 1 = 49, Position 2 = 36
Branch analysis from position: 49
Branch analysis from position: 36
Branch analysis from position: 15
2 jumps found. (Code = 44) Position 1 = 20, Position 2 = 15
Branch analysis from position: 20
Branch analysis from position: 15
filename:       /in/pHAms
function name:  (null)
number of ops:  57
compiled vars:  none
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   15     0  E >   INIT_FCALL                                               'define'
          1        SEND_VAL                                                 'LOG_FILE'
          2        SEND_VAL                                                 '%2Fin%2Fob-bug-test8.0.0.log'
          3        DO_ICALL                                                 
   17     4        INIT_FCALL                                               'ini_set'
          5        SEND_VAL                                                 'error_log'
          6        SEND_VAL                                                 '%2Fin%2Ferror.log'
          7        DO_ICALL                                                 
   20     8        INIT_FCALL                                               'header'
          9        SEND_VAL                                                 'Content-Type%3A+text%2Fplain%3B+charset%3Dutf-8'
         10        DO_ICALL                                                 
   23    11        INIT_FCALL                                               'ignore_user_abort'
         12        SEND_VAL                                                 <true>
         13        DO_ICALL                                                 
   27    14      > JMP                                                      ->17
   28    15    >   INIT_FCALL                                               'ob_end_flush'
         16        DO_ICALL                                                 
   27    17    >   INIT_FCALL                                               'ob_get_level'
         18        DO_ICALL                                         $5      
         19      > JMPNZ                                                    $5, ->15
   32    20    >   FETCH_CONSTANT                                   ~6      'LOG_FILE'
         21        CONCAT                                           ~7      'Results+will+go+to+', ~6
         22        CONCAT                                           ~8      ~7, '%0A'
         23        ECHO                                                     ~8
   33    24        INIT_FCALL_BY_NAME                                       'log_message'
         25        INIT_FCALL                                               'date'
         26        SEND_VAL                                                 '%23+Y-m-d+H%3Ai%3As'
         27        DO_ICALL                                         $9      
         28        CONCAT                                           ~10     '%0A', $9
         29        SEND_VAL_EX                                              ~10
         30        DO_FCALL                                      0          
   36    31        INIT_FCALL_BY_NAME                                       'test_echo_output_buffer_capturing'
         32        DO_FCALL                                      0          
   37    33        INIT_FCALL_BY_NAME                                       'test_gd_output_buffer_capturing'
         34        DO_FCALL                                      0          
   40    35      > JMP                                                      ->45
   41    36    >   INIT_FCALL_BY_NAME                                       'log_message'
         37        SEND_VAL_EX                                              '%0AClient+is+still+connected'
         38        DO_FCALL                                      0          
   46    39        ECHO                                                     'Abort+the+request+in+your+browser+now+by+pressing+%3CEsc%3E+or+clicking+the+little+X+in+the+adress+bar...%0A'
   47    40        INIT_FCALL                                               'flush'
         41        DO_ICALL                                                 
   48    42        INIT_FCALL                                               'sleep'
         43        SEND_VAL                                                 1
         44        DO_ICALL                                                 
   40    45    >   INIT_FCALL                                               'connection_aborted'
         46        DO_ICALL                                         $17     
         47        BOOL_NOT                                         ~18     $17
         48      > JMPNZ                                                    ~18, ->36
   50    49    >   INIT_FCALL_BY_NAME                                       'log_message'
         50        SEND_VAL_EX                                              '%0AClient+is+now+disconnected+%28connection_aborted%28%29+returns+true%29'
         51        DO_FCALL                                      0          
   53    52        INIT_FCALL_BY_NAME                                       'test_echo_output_buffer_capturing'
         53        DO_FCALL                                      0          
   54    54        INIT_FCALL_BY_NAME                                       'test_gd_output_buffer_capturing'
         55        DO_FCALL                                      0          
  101    56      > RETURN                                                   1

Function test_echo_output_buffer_capturing:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/pHAms
function name:  test_echo_output_buffer_capturing
number of ops:  15
compiled vars:  !0 = $captured_output
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   66     0  E >   INIT_FCALL                                               'ob_start'
          1        DO_ICALL                                                 
   67     2        ECHO                                                     'Hello+World'
   68     3        INIT_FCALL                                               'ob_get_clean'
          4        DO_ICALL                                         $2      
          5        ASSIGN                                                   !0, $2
   70     6        INIT_FCALL_BY_NAME                                       'log_message'
          7        SEND_VAL_EX                                              '%0ACapture+echo+in+output+buffer%3A'
          8        DO_FCALL                                      0          
   71     9        INIT_FCALL_BY_NAME                                       'log_message'
         10        STRLEN                                           ~5      !0
         11        CONCAT                                           ~6      '+-+captured+string+length%3A+', ~5
         12        SEND_VAL_EX                                              ~6
         13        DO_FCALL                                      0          
   72    14      > RETURN                                                   null

End of function test_echo_output_buffer_capturing

Function test_gd_output_buffer_capturing:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/pHAms
function name:  test_gd_output_buffer_capturing
number of ops:  1
compiled vars:  none
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   94     0  E > > RETURN                                                   null

End of function test_gd_output_buffer_capturing

Function log_message:
Finding entry points
Branch analysis from position: 0
2 jumps found. (Code = 43) Position 1 = 10, Position 2 = 14
Branch analysis from position: 10
1 jumps found. (Code = 79) Position 1 = -2
Branch analysis from position: 14
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/pHAms
function name:  log_message
number of ops:  15
compiled vars:  !0 = $message
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   96     0  E >   RECV                                             !0      
   98     1        INIT_FCALL                                               'file_put_contents'
          2        FETCH_CONSTANT                                   ~1      'LOG_FILE'
          3        SEND_VAL                                                 ~1
          4        CONCAT                                           ~2      !0, '%0A'
          5        SEND_VAL                                                 ~2
          6        SEND_VAL                                                 8
          7        DO_ICALL                                         $3      
          8        TYPE_CHECK                                    4          $3
          9      > JMPZ                                                     ~4, ->14
   99    10    >   FETCH_CONSTANT                                   ~5      'LOG_FILE'
         11        CONCAT                                           ~6      'Sorry%2C+it+seems+', ~5
         12        CONCAT                                           ~7      ~6, '+is+not+writable.+Aborting...%0A'
         13      > EXIT                                                     ~7
  101    14    > > RETURN                                                   null

End of function log_message

Generated using Vulcan Logic Dumper, using php 8.0.0


preferences:
194.84 ms | 1396 KiB | 39 Q