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.