Selbsterhaltendes PHP-Script – oder warum exec WIRKLICH böse ist.

Ziel der Übung war es ein selbsterhaltendes PHP-Script zu schreiben, welches nicht nur einen Apache Neustart überlebt sondern sich auch beim löschen zurück auf die Platte schreibt.

Um den eigenen Prozess vom Apache Prozess abzukoppeln verwende ich die Funktion

pcntl_fork();

posix_setsid();

Die beiden Funktionen sind einfach erklärt.

Die Funktion pcntl_fork(); erstellt eine Kopie des aktuellen Prozesses und gibt dem Parent-Prozess die eigene PID zurück. Der neue Child-Prozess bekommt hier eine 0 zurück, so das nun jeder der beiden Prozesse über seinen Status bescheid weiss.

Die Funktion posix_setsid(); sorgt dafür, das der neue Kindprozess von seinem Parent-Prozess getrennt wird.

Dieser läuft nun unabhängig zum Apache-Prozess.

Soweit so gut, aber ein Artikel zum Forken? Nein!

Da diese Funktion in den meisten Fällen per php.ini verboten ist (disabled_functions) müssen wir uns hier einen Workaround suchen.Da wir schon die passende Funktion aber nicht die Passenden Rechte haben, bleiben wir doch am besten bei unserem Ansatz.Wo nehmen, wenn nicht stehlen?

Wer unter Linux schonmal mit php-cli gearbeitet hat, dem ist eventuell aufgefallen, das php-cli eine andere php.ini besitzt als der von Apache ausgeführte Prozess.

Mein Ansatz war nun php-cli per exec auszuführen und somit die weitaus freizügigiere php.ini von php-cli zu laden.

Leider wird die php.ini des laufenden Prozesses aber included und wir haben die gleichen Einschränkungen wie vorher auch.

We have to go deeper.

Nach ein bisschen manpages lesen, kam mir folgender Paremeter unter:

-n               No php.ini file will be used

Und siehe da, php startet mit diesem Parameter ohne jegliche Einschränkungen:
$bootstrap_binary = "/usr/bin/php";
$bootstrap_args = "-n ".__FILE__." 1> /dev/null 2>&1 &";
$bootstrap = $bootstrap_binary." ".$bootstrap_args;
exec($bootstrap);

Nun haben wir ein php-cli in einem apache-php aber wie Nutzen wir das nun auf einem Shard-Webhost?

Als erstes überprüfen wir, ob wir per CLI oder per Apache aufgerufen wurden. Wurden wir per Apache aufgerufen und fehlt uns die Funktion pcntl_fork oder  posix_setsid führen wir uns selbst per exec() aus.

Aber…. aber… Moment mal, dann verbiete ich einfach exec!

Neben exec() stehen uns unter php noch system(), shell_exec(), passthru(), popen(), sowie proc_open() zur Verfügung.

In den meisten Fällen reicht hier auch schon exec, da viele Implementierungen von Scripten die ImageMagick  benutzen, dies über Exec ausführen.

Kleinkram

Nun speichern wir uns beim Start unseren eigenen Inhalt, Dateinamen,  und Atribute und übergeben diesen an unser Child.

Ändert sich nun etwas an der Datei, so können wir unser „Backup“ problemlos einspielen und dafür sorgen, das wir weiter ausführbar bleiben.

Fork me on GitHub