PHP xmlWriter resultaten naar log schrijven

Een bestaande applicatie die een XML export doet met XMLWriter moest voorzien worden van een mogelijkheid om de exacte XML output weg te schrijven in een log. Het script maakte in eerste instantie gebruik van directe output naar de browser:

$xml->openURI('php://output');

Om het totale resultaat van de XML output in een logfile te schrijven was dit niet ideaal. Het zou op zich wel kunnen maar omzetten naar gebruik van het geheugen voor opslag van de XML was iets handiger (zeker omdat het om relatief weinig data per run ging).

Hieronder de code voor een basis XML die zowel naar de browser gaat als naar een logfile:

// Set correct header
header('Content-Type: application/xml, charset=utf-8');

// Initiate XMLWriter
$xml = new XMLWriter();

// Create new xmlwriter using memory for string output
$xml->openMemory();

// Create document tag
$xml->startDocument('1.0', 'UTF-8');

// Create start element tag
$xml->startElement('test');

//  Write full element tag
$xml->writeElement('value', 'testwaarde');

// End current element
$xml->endElement();

// End current document
$xml->endDocument();

// Define logfile name
$filename = '/logs/' . date('Ymd_hm') . '.xml';

// Open file
$fp = fopen($filename, "w");

// Write memory output to file. The false boolean is to
// prevent XMLWriter from flushing the current buffer
fwrite($fp, $xml->outputMemory(false));

// Close the file
fclose($fp);

// Return the current buffer
echo $xml->outputMemory();

Dit is een redelijk kort samengevat voorbeeld en het kan altijd beter, netter en leuker maar het idee is duidelijk.

PHP memory limit stress test

In het vervolg op mijn eerdere bericht over een CPU stress test met PHP werd ook de vraag neergelegd om iets te maken wat de max uit het geheugen zou halen met PHP. Wederom volgde een korte brainstorm. Ik wilde voorkomen dat mijn memory test afhankelijk was van externe partijen (bijv. inlezen enorme datareeks of iets) en minimaal de processor zou belasten (om te voorkomen dat hij al tegen een CPU usage limiet aan zou lopen voor hij echt het geheugen vol kon stoppen). Het moest dus iets zijn wat iets simpels deed maar wel een monster ervan maakte voor het geheugen. Mijn oplossing is een scriptje wat éénmalig een string van 26 tekens maakt en die dan 5000 keer 5 keer achter elkaar plakt.

Even voor de lol de stringlengtes die PHP dus in het geheugen probeert te bewaren per for-loop (waarvan er 5000 zijn):
1x = 130 tekens
2x = 650 tekens
5x = 81250 tekens
10x = 253906250 tekens
15x = 793457031250 tekens

Etc. etc. Nog voor je bij een paarhonderd loops bent aangekomen vindt excel al dat de uitkomt “#GETAL!” is.

function generateData($loops)
{
	$chars = "ABCDEFGHJKLMNPQRSTUVWXYZ123456789";
	$i = 0;
	$string = null;
	
	while ($i <= 25) {
		$num = rand() % 33;
		$tmp = substr($chars, $num, 1);
		$string = $string . $tmp;
		$i++;
	}
	
	for ($i = 1; $i <= $loops; $i++) {
		$string = $string.$string.$string.$string.$string;
	}

	return $string;
}

$value = generateData(5000);
die('Wow, your memory is endless!');

Of download hem hier als kant-en-klaar PHP scriptje (tar file)