I recently ran into an issue on one of my Drupal projects. While tracking down the problem, I wrote a wrapper for PHP’s fwrite() function since it should be wrapped inside a loop in case there was a network issue while writing out the data. In the process, I also handled a Windows quirk that may also cause problems. This function was the result:
/** * Writing to a network stream may end before the whole string is written. * Return value of fwrite() may be checked. Windows quirk handled as well. * @param file_stream $aFileStream - the file stream instance. * @param string $aText - the string data to write out. * @param number $aRetryCount - number of attempts before giving up. * @return number - Returns the # of bytes written out. */ function fstream_write($aFileStream, $aText, $aRetryCount=3) { $ts = microtime(true); $num_queued = strlen($aText); //returns num bytes, which is what we want $num_wrote = 0; $num_retries = $aRetryCount + 0; // in case NULL is passed in $isWindows = (strtoupper(substr(php_uname('s'), 0, 3)) === 'WIN'); while (($num_queued > $num_wrote) && ($num_retries > 0)) { // handle Windows quirk since we are already going through all the trouble of while loop $theText = (!$isWindows) ? substr($aText, $num_wrote) : substr($aText, $num_wrote, 8100); // only care about warnings if on last retry $fwResult = ($num_retries > 1) ? @fwrite($aFileStream, $theText, strlen($theText)) : fwrite($aFileStream, $theText, strlen($theText)); if (!empty($fwResult)) { $num_wrote += $fwResult; } else { //cover the case of FALSE and 0 being returned //0 result may mean the socket/connection was severed, prevent infinite loop $num_retries -= 1; if ($num_retries > 0) { sleep(1); //give the target time to recover } else { $tl = microtime(true); watchdog('PHP', 'fstream_write> wrote: @num duration: @dur text: @out', array('@num'=>$num_wrote, '@dur'=>number_format($tl-$ts), '@out'=>$aText)); } } } return $num_wrote; }
In the end, it turns out my issue was fixed with a few configuration setting changes rather than any code changes, but this seemed useful enough to remember for later.