$_POST/$_GET-Inhalte in normale Variablen umwandeln

Wie die Inhalte aus den Superglobalen Arrays $_GET und $_POST in normale Variablen transferiert werden können

1. Erläuterungen

Sofern die Einstellung register_globals deaktiviert wurde (was der Fall sein sollte), sind die GET- und POST-Parameter nur über die gleichnamigen Superglobals ($_GET, $_POST) erreichbar. Sobald register_globals hingegen angeschaltet ist, wird für jeden Parameter eine gleichnamige Variable erzeugt. Bei Aufruf von http://www.example.com/index.php?do=list_users&page=14 würden etwa die Variablen „do” (mit Wert „list_users”) und „page” (mit Wert „14”) vollautomatisch erzeugt werden. Um dieses Verhalten nachzubilden kann die Funktion extract() auf $_GET und/oder $_POST angewendet werden. Die Funktion liest alle Schlüssel-Wert-Paare aus und bildet Variablen mit dem Schlüssel als Namen und dem Wert als Variableninhalt.

2. Beispiel: extract()

Im nachfolgenden Beispiel wird extract() auf einige exemplarische GET-Daten angewendet.

PHP-Code
<?php
    // $_GET mit Beispieldaten füllen
	$_GET = array('do' => 'list_users', 'page' => '14');

	// $do existiert noch nicht, das sollte also einen Fehler erzeugen
	var_dump($do);

	// Parameter aus $_GET extrahieren
	extract($_GET);

	// Extrahierte Parameter ausgeben
	// diesmal sollte die Ausgabe von $do keinen Fehler erzeugen
	var_dump($do);
	var_dump($page);
?>

HTML-Code: Ausgabe
<br />
<b>Notice</b>:  Undefined variable: do in <b>...\test.php</b> on line <b>6</b><br />
NULL
string(10) "list_users"
string(2) "14"


3. Beispiel: Gefahren beim Verwenden von extract()

Wird extract() ohne Sicherheitsüberprüfungen verwendet, dann kann ein Angreifer zuvor definierte Variablen überschreiben. Im nachfolgenden Beispiel soll der Benutzer zur Ausführung des Kommandos „admin_login” eigentlich nur den Parameter „password” übergeben, welcher dann mit dem Wert in $adminPassword verglichen wird. Ein Angreifer kann aber nun auch „adminPassword” als Parameter senden, wodurch die Variable $adminPassword überschrieben werden würde. Der Passwortschutz könnte sich so leicht umgehen lassen.

PHP-Code
<?php
	$adminPassword = 'asdasd';
	$_POST = array('do'=>'admin_login', 'password'=>'xyz', 'adminPassword'=>'xyz');

	extract($_POST);

	switch ($do) {
		case 'admin_login':
			if ($password === $adminPassword) {
				echo("Sie sind als Admin eingeloggt!");
			} else {
				echo("Falsches Admin-Passwort!");
			}
			break;

		// .. hier koennte weitere case's stehen ..

		default:
			echo("Unbekannte do-Option gewaehlt.");
	}
?>

HTML-Code: Ausgabe
Sie sind als Admin eingeloggt!

4. Beispiel: extract() mit EXTR_SKIP

Um die Sicherheitsprobleme beim Extrahieren von Variablen aus $_GET/$_POST zu umgehen, kann das Flag EXTR_SKIP verwendet werden. Wird dieses an extract() übergeben, dann werden Variablen nur extrahiert, falls diese noch nicht definiert sind. Es kommt also nicht zu Überschreibungen bereits existierenden Variablen. Das vorherige Beispiel, erweitert um EXTR_SKIP erzeugt daher diesmal die gewünschte Ausgabe, da der Wert in $adminPassword nicht mehr überschrieben wird:

PHP-Code
<?php
	$adminPassword = 'asdasd';
	$_POST = array('do'=>'admin_login', 'password'=>'xyz', 'adminPassword'=>'xyz');

	// hier wurde EXTR_SKIP hinzugefuegt
	extract($_POST, EXTR_SKIP);

	switch ($do) {
		case 'admin_login':
			if ($password === $adminPassword) {
				echo("Sie sind als Admin eingeloggt!");
			} else {
				echo("Falsches Admin-Passwort!");
			}
			break;

		// .. hier koennte weitere case's stehen ..

		default:
			echo("Unbekannte do-Option gewaehlt.");
	}
?>

HTML-Code: Ausgabe
Falsches Admin-Passwort!

5. Beispiel: Eigene extract-Funktion

Die Funktion extract() lässt sich mit wenigen Zeilen Code nahezu funktionsgleich nachbauen. Das folgende Beispiel zeigt die Funktion myExtract(), welches alle Schlüssel-Wert-Paare aus einem übergebenen Array ausliest und in das $GLOBALS array schreibt. Auf diese Weise kann im globalen Geltungsbereich direkt auf die Variablen zugegriffen werden (aus $_GET['do'] wird zum Beispiel $do). In Funktionen müssen die Variablen zunächst per „global $var;” als globale Variablen „markiert” werden.

PHP-Code
<?php
	// Ersatz fuer extract()
	function myExtract($arr) {
		// diese Schleife koennte auch durch array_merge ersetzt werden,
		// die Schleife passt aber besser zu den naechsten beiden Beispielen
		foreach ($arr as $key=>$val) {
			$GLOBALS[$key] = $val;
		}
	}

	// Ausgabe von $do im Geltungsbereich einer Funktion
	function dumpGlobalDo() {
		global $do;
		var_dump($do);
	}

	$_GET = array('page' => 'users', 'do' => 'profile');
	myExtract($_GET);
	var_dump($page);
	var_dump($do);
	dumpGlobalDo();
?>

HTML-Code: Ausgabe
string(5) "users"
string(7) "profile"
string(7) "profile"


Das zuvor angesprochene Problem der Sicherheit (bereits definierte Variablen werden potenziell überschrieben) ist hier noch vorhanden. Wir wandeln die Funktion myExtract() daher nun leicht ab, sodass sie ein zusätzliches Array $limitTo erwartet. Dieses Array soll die Namen aller Schlüssel enthalten, die extrahiert werden sollen. Alle Schlüssel, die nicht in $limitTo aber dafür in $arr vorhanden sind, werden ignoriert.

PHP-Code
<?php
	function myExtract($arr, $limitTo) {
		foreach ($arr as $key=>$val) {
			// über in_array diesmal prüfen, ob der Schlüssel in $limitTo enthalten ist
			if (in_array($key, $limitTo)) {
				$GLOBALS[$key] = $val;
			}
		}
	}

	// Beispieldaten in GET
	$_GET = array('page' => 'users', 'do' => 'profile', 'attack_param'=>'evil attack!');

	// wir extrahieren nur 'page'
	myExtract($_GET, array('page'));

	// $page sollte extrahiert worden sein
	var_dump($page);

	// Diese beiden Variablen sollten nicht extrahiert worden sein.
	// Der Versuch, sie auszugeben, sollte zu einem Fehler führen.
	var_dump($do);
	var_dump($attack_param);
?>

HTML-Code: Ausgabe
string(5) "users"
<br />
<b>Notice</b>:  Undefined variable: do in <b>...\test.php</b> on line <b>22</b><br />
NULL
<br />
<b>Notice</b>:  Undefined variable: attack_param in <b>...\test.php</b> on line <b>23</b><br />
NULL


6. Beispiel: Eigenes extract() ohne globalen Geltungsbereich

Wer in seinen Funktionen nicht „global $var;” schreiben will, der kann den nachfolgenden Code-Schnipsel verwenden. Die foreach-Schleife in diesem durchläuft alle Variablen aus $_GET und erzeugt für jede dieser eine Variable mit dem Schlüssel als Namen und dem Wert als Variableninhalt. Nach dem Verlassen der Funktion gehen die extrahierten Variablen wieder verloren, sind also nur noch in $_GET vorhanden. Der Nachteil ist, dass die Schleife in jede Funktion eingefügt werden muss, für welche die Variablen extrahiert werden sollen. Eine Auslagerung in eine eigene Funktion ist nicht möglich, da mit dem Ende dieser Funktion wiederum alle extrahierten Variablen verloren gehen würden.

PHP-Code
<?php
	$_GET = array('page' => 'users', 'do' => 'profile');

	function dumpGET() {
		// hier werden die Variablen extrahiert, man beachte den variablen Variablennamen "$$key"
		foreach ($_GET as $key=>$val) {
			$$key = $val;
		}

		var_dump($page);
		var_dump($do);
	}

	dumpGET();
?>

HTML-Code: Ausgabe
string(5) "users"
string(7) "profile"

Deprecated: Directive 'allow_url_include' is deprecated in Unknown on line 0