====== Tips und Regeln für PHP-Migration (auf Version 5) ======
Um die Kompatibilität zwischen PHP-Versionen zu maximieren und die Sicherheit und die Wartbarkeit von PHP-Skripten zu gewährleisten sollte sichergestellt sein, dass folgende Regeln eingehalten werden:
==== Variablen deklarieren und initialisieren ====
Auch wenn PHP sehr dynamisch ist, ist das Deklarieren von Variablen nicht unwichtig. Denn im Funktionskopf deklarierte Variablen verschaffen einen Überblick und Komplexität des Algorithmus und geben den sehr wichtigen Hinweis auf den Typ einer Variable.
* Richtig: function meine_funktion($param) {
$s = 0; // Zählvariable
$ret = ""; // Rückgabe
for ($s; $s < 10; $s++) $ret .= $s;
return $ret;
}
* Falsch: function meine_funktion($param) {
for ($s = 0; $s < 10; $s++) $ret .= $s;
return $ret;
}
==== Typisierung beachten ====
Da PHP keine Typisierung unterstützt, liegt es in der Verantwortung des Programmierer diese zu gewährleisten. Vorallem Eingabewerte sollten strikt typisiert werden. Dies ist auch sinnvoll um SQL-Injections zu vermeiden.
* Richtig: $id = intval($_GET["id"]);
* Falsch: $id = $_GET["id"];
* Richtig: if (strlen($name) > 0) {}
* Falsch: if ($name) {}
* Richtig: if (is_array($mein_array)) foreach ($mein_array ...) {}
* Falsch: foreach ($mein_array ...) {}
* Richtig: if (strpos("-", "hallo") === false) {}
* Falsch: if (!strpos("-", "hallo")) {}
==== Dateibenennung ====
Ab Version 5.3 soll PHP Namensräume unterstützen, bis dahin muss man versuchen sich diese selbst zu schaffen, in dem man Dateien nach ihrem Zweck benennt.
* Dateien die nur eingefügt, jedoch nie selbst aufgerufen werden sollten die Dateiendung ".inc.php" tragen.
* Dateien die Klassendefinitionen beinhalten dagegegen: ".class.php".
* Beispiel: include("helper_functions.inc.php");
include("modules/test/test.class.php");
$test = new Test();
==== Codeblöcke definieren ====
Dank der formatfreien C-Syntax ist es auch in PHP möglich Blöcke zu definieren oder diese wegzulassen. Bei Anweisungen die **normalerweise** Blöcke benötigen, ist es zwingend erforderlich dies auch zu tun. Um die Schreibweise zu kürzen und übersichtlicher zu gestalten sollten wenn schon Einzelanweisungen direkt dahinter stehen.
* Richtig: if ($variable == 1) {
echo "ich bin wahr";
}
* Richtig: if ($variable == 1) echo "ich bin wahr";
* Falsch: if ($variable == 1)
echo "ich bin wahr";
Hinweis: Ein sehr interessanter Artikel über die wahre Intention der ungarischen Notation: http://www.joelonsoftware.com/articles/Wrong.html
==== Keine Short-PHP-Tags verwenden ====
Entsprechende Einstellung in php.ini. Code in kurzen Tags wird ignoriert.
short_open_tag = Off
* Richtig:
* Falsch: ="Hallo Welt" ?>
==== Globale Variablen vermeiden ====
Viele Skripte setzen die Existenz von globalen Variablen vorraus. Dies ist nicht nur unsauber sondern **gefährlich**.
Das Registrieren von globalen Variablen ist zwingend in der php.ini abzustellen:
register_globals = Off
* Richtig: echo $_SERVER["DOCUMENT_ROOT"];
* Falsch: echo $DOCUMENT_ROOT;
* Richtig: $variable = $_GET["variable"];
* Falsch: echo $variable;
* Richtig: echo $_GLOBALS["variable"];
* Falsch: global $variable;
==== Referenzübergabe vermeiden ====
Funktionen haben zu bestimmen, ob sie eine Referenz benötigen, nicht der Aufruf. Die Option call by reference ist standardmäßig in neueren
PHP-Versionen abgeschalten. Die entsprechende Option in der php.ini lautet:
allow_call_time_pass_reference = Off
* Richtig: function foo(&$bar) { return 0; }
* Falsch: foo(&$bar);
==== Keine Fehler unterdrücken ====
Einige PHP-Funktionen werfen Fehler. Es gibt einen Grund dafür! Deswegen sollte einer Ausgabe niemals unterdrückt, sondern behandelt oder besser: vermieden werden.
* Richtig: if (is_writable($filename)) {
$fp = fopen($filename, "w");
fwrite($fp, "hallo");
fclose($fp);
}
* Falsch: if ($fp = @fopen($filename, "w")) {
fwrite($fp, "hallo");
fclose($fp);
}
==== Prozessaufrufe vermeiden ====
Mit dem exec-Befehl kann man viel anstellen, z.B. das gesamte Web-Verzeichnis löschen. Deshalb sollte das Starten von Befehlen mit dem Safe-Mode in der php.ini eingeschalten werden.
safe_mode = On
Demnach dürfen nur noch Programme gestartet werden, die unterhalb eines sicheren Verzeichnisses liegen, welches man in der php.ini folgendermaßen aktiviert.
safe_mode_exec_dir = /opt/php_safe_exec_dir
Hier sollte man **keinesfalls** /usr/bin oder sonstige Verzreichnisse eintragen, da ja der Sinn dieser Einschränkung ad absurdum geführt werden würde. Stattdessen sollte man dieses Verzeichnis anlegen und alle Befehle mit einem [[Shell-Befehle|symbolischen Link]] dort hinein verknüpfen. Die Programme werden unter dem Apache-Benutzer (www-data/wwwrun) ausgeführt.\\
Für Dateisystemoperationen sind die PHP-eigenen Klassen und Funktionen vorzuziehen. Sollte man dennoch mal in die Gelegenheit kommen, einen exec-Befehl auszuführen, dann muss der Befehl zwingend mit escapeshellcmd maskiert werden.
* Richtig: exec(escapeshellcmd($mein_befehl));
* Falsch: exec($mein_befehl);
Außerdem dürfen nur noch Dateien eingebunden werden, die der //open basedir restriction// unterliegen.
==== Fehlerausgabe abschalten ====
Potentielle Sicherheitsprobleme für Außenstehende sind immer leicht an den Fehlern zu erkennen die PHP auswirft. Dies ist aber ein enormes **Sicherheitsrisiko**. Deshalb wird das error reporting abgeschalten. In den Apache error_logs sind diese aber weiterhin sichtbar.
display_errors = Off
error_reporting = E_ALL & ~E_NOTICE
Dies lässt sich jedoch mit einer .htaccess Datei temporär (zu Berichtigungszwecken) aktivieren.
php_flag display_errors on
==== Das Einbinden externer Dateien vermeiden ====
PHP bietet die Möglichkeit Dateien einzubinden, die außerhalb des Servers liegen. Externe Server sind aber niemals vertrauenswürdig, deswegen wird diese Möglichkeit in der php.ini abgeschalten.
allow_url_fopen = Off
allow_url_include = Off