PHP: fwrite() wrapper

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.

2 thoughts on “PHP: fwrite() wrapper

Leave a Reply

Your email address will not be published. Required fields are marked *