Why does PHP hang after writing 4096 bytes to a process started with proc_open? Why does PHP hang after writing 4096 bytes to a process started with proc_open? php php

Why does PHP hang after writing 4096 bytes to a process started with proc_open?


I ran into the exact same issue trying to do WAV to MP3 conversion using LAME on Windows and was unable to find a workable solution.

I tried dozens of things including blocking/non-blocking writes, writing small (< 1k) chunks of data, sleeping and trying to write but it never was able to write all data. About as much as I could ever write before it failing was around 40kb (failure being fwrite would always return 0 and never write more data to the stream, no matter how long I waited; regardless of the sizes of the chunks written before. I even tried waiting seconds between writes and they would always succeed to about 30-40kb and never write more).

Ultimately I gave up and luckily LAME could read input from a file instead of STDIN, so I just opted to write the data to a temp file, call LAME, and remove the temp file.

Here's the relevant code:

// file descriptors for reading and writing to the Lame process$descriptors = array(        0 => array('pipe', 'r'), // stdin        1 => array('pipe', 'w'), // stdout        2 => array('pipe', 'a'), // stderr);if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {    // workaround for Windows conversion    // writing to STDIN seems to hang indefinitely after writing approximately 0xC400 bytes    $wavinput = tempnam(sys_get_temp_dir(), 'wav');    if (!$wavinput) {        throw new Exception('Failed to create temporary file for WAV to MP3 conversion');    }    file_put_contents($wavinput, $data);    $size = 0;} else {    $wavinput = '-'; // stdin}// Mono, variable bit rate, 32 kHz sampling rate, read WAV from stdin, write MP3 to stdout$cmd  = sprintf("%s -m m -v -b 32 %s -", self::$lame_binary_path, $wavinput);$proc = proc_open($cmd, $descriptors, $pipes);if (!is_resource($proc)) {    throw new Exception('Failed to open process for MP3 encoding');}stream_set_blocking($pipes[0], 0); // set stdin to be non-blockingfor ($written = 0; $written < $size; $written += $len) {    // write to stdin until all WAV data is written    $len = fwrite($pipes[0], substr($data, $written, 0x20000));    if ($len === 0) {        // fwrite wrote no data, make sure process is still alive, otherwise wait for it to process        $status = proc_get_status($proc);        if ($status['running'] === false) break;        usleep(25000);    } else if ($written < $size) {        // couldn't write all data, small pause and try again        usleep(10000);    } else if ($len === false) {        // fwrite failed, should not happen        break;    }}fclose($pipes[0]);$data = stream_get_contents($pipes[1]);$err  = trim(stream_get_contents($pipes[2]));fclose($pipes[1]);fclose($pipes[2]);$return = proc_close($proc);if ($wavinput != '-') unlink($wavinput); // delete temp file on Windowsif ($return !== 0) {    throw new Exception("Failed to convert WAV to MP3.  Shell returned ({$return}): {$err}");} else if ($written < $size) {    throw new Exception('Failed to convert WAV to MP3.  Failed to write all data to encoder');}return $data;