PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


Archive for the ‘Debug Ausgaben’ tag

Debug Ausgaben im Code vergessen?

with 10 comments

Wahrscheinlich ist es jedem schon einmal passiert: Irgendwo ist ein var_dump() oder file_put_contents(‚/tmp/blub‘) im Code vergessen worden, natürlich in einem sehr unwahrscheinlichen Programmzweig, und unverhofft kommt eine Email mit einer „komischen Ausgabe“ inklusive internen Informationen von einem Benutzer. Aua!

Doch was kann man dagegen machen? Die beste Lösung ist natürlich: Keine Debug-Ausgaben solcher Art benutzen, sondern nur mittels IDE-Debugging/Breakpoints etc. den Code debuggen. Oder aber man verwendet Zend_Log in Verbindung mit dem Firebug-Writer, dann erhält man auch im Browser Debug-Ausgaben, aber nicht störend mitten im Code, sondern im Firebug/FirePHP Addon des Firefox. Außerdem kann man dieses Plugin dann nur für die Development-Umgebung aktivieren, im Produktivbetrieb sollte der Writer natürlich abgeschaltet werden. Dann ist sichergestellt dass keine internen Informationen nach außen dringen.

$logger = new Zend_Log();

// create the file writer
$formatter = new Zend_Log_Formatter_Simple('%timestamp% %priorityName% (%priority%): %message%' . PHP_EOL);
$fileWriter = new Zend_Log_Writer_Stream($tempDirectory . "/logs/" . date("Y-m-d") . ".log");
$fileWriter->setFormatter($formatter);
$logger->addWriter($fileWriter);

if ($debug) {
	$firebugWriter = new Zend_Log_Writer_Firebug();
	$logger->addWriter($firebugWriter);
}

Damit auch sichergestellt ist dass kein Entwickler doch noch var_dumps nutzt und vergisst, schreiben wir auch gleich noch einen Unit-Test, der den Source-Code nach „var_dump“ und „file_put_contents“ durchsucht und Alarm schlägt falls die beiden Funktionen an „nicht erlaubten Stellen“ genutzt werden. Im unten stehenden Beispiel habe ich auch noch einen Test für „console.log()“ Aufrufe im Javascript, denn die können Probleme machen wenn der Browser diese Funktion nicht unterstützt.

Das Script hier ist abgespeckt und muss natürlich an die Gegebenheiten angepasst werden. Es findet zum Beispiel auch auskommentierte var_dumps, das könnte man noch optimieren.

<?php
/*
 * This tests check in testing and stable if there are
 * console.log()  function calls in javascript
 * var_dump()     function calls in php
 *
 **/
class CheckDebuggingOutputTest extends PHPUnit_Framework_TestCase
{
	public function testJavascriptConsoleLog()
	{
		if (strpos(APPLICATION_PATH, 'testing') !== false || strpos(APPLICATION_PATH, 'stable') !== false) {
			$errorString = '';
			$jsList = file(APPLICATION_PATH . '/configs/js_includes.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
			foreach ($jsList as $jsFile) {
				$content = file(realpath(APPLICATION_PATH . '/../public/js/'.$jsFile), FILE_IGNORE_NEW_LINES);
				foreach ($content as $lineNumber => $line) {
					if (stripos($line, 'console.log') !== false) {
						$errorString .= 'console.log() call found in file '.$jsFile.' line '.($lineNumber+1)."\n";
					}
				}
			}
			if (!empty($errorString)) {
				$this->fail($errorString);
			}
		} else {
			$this->markTestSkipped('Debugging output should only be checked in testing and stable branch');
		}
	}

	public function testPhpVarDump()
	{
		if (strpos(APPLICATION_PATH, 'testing') !== false || strpos(APPLICATION_PATH, 'stable') !== false) {
			$errorString = '';
			// get all files with .php or .phtml extension, except sandbox/ folder
			$iterator = new RecursiveDirectoryIterator(realpath(APPLICATION_PATH.'/../'));
			foreach (new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::CHILD_FIRST) as $file) {
				if ($file->isFile() &&
					strpos($file->getPathname(), '/sandbox')===false &&
					$file->getFilename() != 'CheckDebuggingOutputTest.php' &&
					(substr($file->getFilename(), -3) == 'php' || substr($file->getFilename(), -4) == 'phtml')
				) {
					$content = file($file->getPathname(), FILE_IGNORE_NEW_LINES);
					foreach ($content as $lineNumber => $line) {
						if (stripos($line, 'var_dump') !== false) {
							$errorString .= 'var_dump() call found in file '.$file->getPathname().' line '.($lineNumber+1)."\n";
						}
					}
				}
			}
			if (!empty($errorString)) {
				$this->fail($errorString);
			}
		} else {
			$this->markTestSkipped('Debugging output should only be checked in testing and stable branch');
		}
	}
}

Findet ihr, dass ein solcher Test in die Testsuite reingehört, und der Build fehlschlagen darf wegen eines solchen „Fehlers“? Wie prüft ihr, ob ihr Debug-Ausgaben im Code vergessen habt? Oder nutzt ihr vor jedem Commit/Release die „projektweite Suche“ der IDE, um nach soetwas zu suchen?

Written by Michael Kliewe

April 6th, 2010 at 11:04 am