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.

PHP: Query Result Loops

Pro Tip: when you loop through the results of a query like this:

$theDatabase->getSqlData($theSQLtext);
while ( $theDatabase->getNextRow() ) {
    //... do a ton of stuff ...
}

I would like to point out that it will fail eventually. Why? Oh there’s nothing wrong with it, per se…

But if somewhere in all of that ton of stuff inside the while loop you ask the database for something else (like a small list of items for a drop down control), then when you get back to the “while” line, it will now either return the wrong data row or most likely just end prematurely — because of lazy coding!

All that is needed to avoid this hard to detect bug, is to save off the query result given in the first line and use it in the “while” line. No question now which row will be returned and everything will be correct no matter how many nested database calls you put inside the while loop.

$theQueryResult = $theDatabase->getSqlData($theSQLtext);
while ( $theDatabase->getNextRow($theQueryResult) ) {
    //... do a ton of stuff...
}