Programmieren mit PHP: Unterschied zwischen den Versionen

Aus
(Die Seite wurde neu angelegt: == Meine Tipps für PHP == Falls jemand über diese Seite stolpert und mit dem Gedanken spielt PHP zu lernen, dann hier die für mich wichtigsten Tipps: === Register Gl...)
(kein Unterschied)

Version vom 20. März 2009, 18:41 Uhr

Meine Tipps für PHP

Falls jemand über diese Seite stolpert und mit dem Gedanken spielt PHP zu lernen, dann hier die für mich wichtigsten Tipps:

Register Globals ausschalten

Wenn immer ihr einen Server mit PHP aufsetzt oder Euch ein Hosting für Eure Webpage sucht, achtet darauf, dass register globals auf off sind. Ansonsten bittet den Hoster dies zu tun oder, falls er das nicht tut, verlasst ihn schnell. Falls ihr selber einen Server aufsetzt oder einen Rootserver und damit Zugriff auf die php.ini hat, dann könnt ihr die entsprechende Änderung auch selber durchführen. Öffnet dazu die php.ini. Wenn ihr nicht wisst wo diese liegt, dann legt eine PHP Datei mit folgendem Inhalt an:

<?php
phpinfo();
//irgendwo steht das etwas wie
//Configuration File (php.ini) Path /usr/syno/etc/php.ini
//weiter unten steht etwa
//register_globals Off Off
?>

In dieser angegebenen Datei sucht ihr nach register globals, ändert den Wert auf off und speichert die Datei wieder (bei der Ausgabe von phpinfo() stehen jeweils zweimal die Zustände der Einstellung. Dies kommt daher, dass der erste Wert der Local Einstellung entspricht, der zweite hingegen der Master Vorgabe)

Gefahr von Register Globals

<?php
if($password == 'totalGeheim'){
  $login = true;
  //Code
}
//viel mehr Code
if($login == true){
  echo 'Total geheimer Text';
}
?>

Diesen Code kann man bei register_globlas ON gleich auf zweit Arten umgehen. Entweder man übergibt dem Script eine POST oder GET Variable mit dem Namen password und dem Wert totalGeheim oder man gibt schlicht und eirgreifend einen Wert mit Namen login und Wert 1. Dieser Code hat gleich mehrere Don't dos drin. Zum ersten ist es einfach nötig - egal ob register_globals ON oder OFF - Variabeln zu initialisieren und zum anderen muss man Variabeln v.a. im Umfeld von register_globals ON neben dem Wert auch auf den Typ prüfen. Eine Initialisierung von login mit false und password mit NULL würde jegliche Versuche eines Angreifers via GET oder POST unmöglich machen.

Ausserdem könnte man das Problem entschärfen indem man den === Verlgeichoperator verwenden würde. Da PHP Variabeln, die via GET oder POST hereinkamen immer als String sieht. Das führt dazu, dass der Text nur angezeigt wird, wenn man das Passwort kennt und $login auf den Boolean Wert true gesetzt wurde.

Beim Programmieren ist es sehr wichtig sich nicht auf eine bestimmte Servereinstellung zu verlassen. Sonst kann das dazu führen, dass der Code nicht mehr portabel ist. Vorallem als Entwickler sollte man beachten, dass der Code sowohl in Umgebungen mit register_globals ON als auch OFF laufen kann.

Eigenheiten und "Macken" von PHP

Auto Type Cast und Typisierung

Und mit der Zeit gewöhnt man sich an die Eigenheiten von PHP, die es eben von echten Programmiersprachen unterscheidet. Typische solche "Eigenheiten" sind zum Beispiel das automatische Type Casting oder die nicht strikte Typisierung (strikt oder dynamisch) von Variabeln. In jeder echten Programmiersprache muss man BEVOR man eine Variable benutzt diese deklarieren d.h. bekanntmachen welchen Datentyp die Variable hat (z.B. String, Integer, Float ...).

Folgender Code gäbe in fast jeder anderen Sprache einen schweren Fehler:

<?php
$i = 1;
?>

Dem Parser von PHP ist es egal wenn eine Variable ohne Deklaration verwendet wird.

Der Parser denkt sich: Hhm eine unbekannte Variable i hhhm und der Programmierer will ihr einen Wert von 1 zuweisen. Hhm mal überlegen was könnte der beste Datentyp für 1 sein ????? (Grübel und studier) Ach ja ich hab's ich deklariere i einfach mit dem Datentyp Integer für ganze Zahlen und initialisiere diese mit 1"

Wohingegen ein Compiler denkt: Also echt ich kann doch nicht einer Variable deren Typ ich nicht kenne irgendeinen Wert zuweisen, du Spinner. Wo kämen wir denn da hin ???? Ich muss doch für die Variable Speicher reservieren. Wie denn ohne den Typ zu kennen ?? Nein wirklich so einen Quellcode versuche ich gar nicht erst zu kompilieren. Fehler und tschüss"

Oben habe ich als Beispiel für Eigenheiten von PHP neben dem Type Casting auch die nicht strikte Typisierung erwähnt. In einer richtigen Programmiersprache kann das Ergebnis einer Division zweier Zahlen entweder Integer ODER Float (Fliesskommmazahl) sein.

<?php
//Variable als Integer
$h = 0;

for($i=1;$i<=30;$i++){
  $h = 30/$i;
  var_dump($h);
}
?>

var_dump() ist eine PHP Funktion, welche den Typ und den Inhalt einer Variable ausgibt. Anscheinend ist jede dritte Zahl vom Typ Integer der Rest ist Float !

int(30)
int(15)
int(10)
float(7.5)
int(6)
int(5)
float(4.2857142857143)
float(3.75)
float(3.3333333333333)
int(3)
float(2.7272727272727)
float(2.5)
float(2.3076923076923)
float(2.1428571428571)
int(2)
float(1.875)
float(1.7647058823529)
float(1.6666666666667)
float(1.5789473684211)
float(1.5)
float(1.4285714285714)
float(1.3636363636364)
float(1.304347826087)
float(1.25)
float(1.2)
float(1.1538461538462)
float(1.1111111111111)
float(1.0714285714286)
float(1.0344827586207)
int(1)

2/3 aller Zuweisungen der Division würden in echten Programmiersprachen Fehler produzieren. Dies da 2 von 3 Resultaten nicht ganzzahlig sind, Kommazahlen (Float) also. Ein Typenwechsel ist in einer echten Programmiersprache nicht möglich. PHP castet den Variabelntyp bei 2 von 3 Divisionen automatisch auf Float und dann wieder für einmal zurück auf Integer. Das nennt sich bei PHP Autocast und ist eigentlich etwas sehr nettes. In Gewissen Situationen kann sich dieser Autocastmechanismus jedoch auch sehr nervig sein.

Vergleichsoperatoren

<?php
$heuhaufen = 'Ich bin ein String';
$nadel = 'Ich';
$suche = stripos($heuhaufen,$nadel);
if($suche == false) {
  die('Nix gefunden');
}else{
  die('Gefunden an Position '.$suche);
}
?>

Obiger Code wird NIEMALS in den else-Zweig hineinkommen. Die Problematik liegt hier wiederum beim Autocast von PHP, aber auch beim Vergleichsoperator == von PHP. Ein ==-Operator vergleicht nur den Wert der beiden Variabeln. Die Funktion gibt die Position von $nadel zurück. Und diese Position im String ist eben 0. Damit PHP den Integer 0 mit dem Boolean false vergleichen kann muss ein Type Casting stattfinden. Dabei wird ein Boolean Wert false zu Integer Wert 0 gecastet und die Bedingung ist damit erfüllt. Andererseits würde ein Boolean true als Integer 1 interpretiert. Damit obiger Code korrekt laufen kann stellt PHP den === Operator zur Verfügung. Dieser vergleicht neben dem Wert der Variabeln auch ihren Typ. Nur wenn Typ und Wert identisch sind wird die Bedingung erfüllt.

Initialisieren von Variabeln

Obwohl es in PHP bei solchen Aktionen keine Fehler gibt, sollte man gleich von Anfang an allen Variabeln einen Wert zuweisen (z.B. alle im Script verwendeten Variabeln mit einem Initialwert belegen). Es ist einfach sauberer als wild drauf los Werte zuzuweisen ! Ausserdem "killt" man damit das leidige register_globals-Problem von PHP , das bei entsprechender Serverkonfigurationen ein echtes Sicherheitsrisiko darstellt.

error_reporting(E_ALL|E_STRICT)

Die weiteren Fehler können durch ein entsprechendes Setzen des Error Reportings zur Laufzeit der Scripts abgefangen werden. Es sind dies nicht Parser Fehler, sondern die sogenannten Warnings, die neu dazukommen. Anhand derer kann man auf mögliche Fehlerquellen im Code schliessen.

<?php
//erste Anweisung kommt während der Entwicklung
//UND NUR WÄHREND DER ENTWICKLUNG
//als erste Zeile eines JEDEN PHP Scripts
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors','1');
?>