PHP

Natürlich ist auch PHP auf unseren Servern verfügbar. Wir setzen hierbei auf ein Setup, bei dem für jeden Uberspace ein eigener PHP-Interpreter unter FastCGI läuft. Der kleine Nachteil dabei ist, dass beim ersten Aufruf eines PHP-Scripts nach einem Webserver-Restart oder nach längerer Nichtbenutzung zunächst ein PHP-Interpreter gestartet für deinen Uberspace gestartet werden muss, was ca. 1-2 Sekunden dauert. Aber keine Sorge: Sobald er einmal läuft, gehen die weiteren Zugriffe so schnell wie erwartet. Die Vorteile dieses Systems überwiegen aber aus unserer Sicht die kleine „Denkpause“:

  • Der eigene PHP-Interpreter läuft mit deinen Rechten und nicht wie anderswo mit den Rechten des Webservers. Insofern kannst du auf alle Dateien deines Uberspaces genauso zugreifen wie auf der Shell auch; gleichzeitig besteht eine maximale Absicherung gegen Übergriffe auf andere Uberspaces.
  • Durch diese Trennung der Interpreter können wir auf Frickeleien wie open_basedir, den safe_mode oder disable_functions getrost verzichten: Warum sollen wir PHP in Funktionen einschränken, die dir spätestens bei Nutzung einer anderen Programmiersprache doch sowieso bereitstünden?
  • Durch Einsatz des eigenen Interpreters kannst du problemlos eine eigene php.ini zum Einsatz bringen - oder auch die Version deines Interpreters wechseln.

Pfad zum PHP-Interpreter

Nach Einrichtung deines Uberspaces funktioniert PHP automatisch und arbeitet mit einer aktuellen Version der 5er-Serie. Unsere PHP-Interpreter sind manuell kompiliert und liegen in einer zunächst vermutlich ungewohnten Struktur, nämlich unter /package/host/localhost (/package, sprich: „slash package“, ist eine von Dan J. Bernstein vorgeschlagene Struktur zum Paketmanagement, das nur so nebenbei). So sieht das aus:

[clara@xenon ~]$ ls -ld /package/host/localhost/php-*
lrwxrwxrwx 1 root root    7 Nov 24  2009 /package/host/localhost/php-5 -> php-5.3
lrwxrwxrwx 1 root root   10 Jan 22  2010 /package/host/localhost/php-5.2 -> php-5.2.11
lrwxrwxrwx 1 root root   12 Aug 30 12:08 /package/host/localhost/php-5.2.11 -> php-5.2.11-7
drwxr-xr-x 7 root root 4096 Nov 28  2009 /package/host/localhost/php-5.2.11-1
drwxr-xr-x 7 root root 4096 Jan 22  2010 /package/host/localhost/php-5.2.11-2
drwxr-xr-x 7 root root 4096 Mar  9  2010 /package/host/localhost/php-5.2.11-3
drwxr-xr-x 7 root root 4096 Mar  9  2010 /package/host/localhost/php-5.2.11-4
drwxr-xr-x 7 root root 4096 Mar  9  2010 /package/host/localhost/php-5.2.11-5
drwxr-xr-x 7 root root 4096 Mar 29  2010 /package/host/localhost/php-5.2.11-6
drwxr-xr-x 7 root root 4096 Aug 30 12:08 /package/host/localhost/php-5.2.11-7
lrwxrwxrwx 1 root root    9 Mar  6  2010 /package/host/localhost/php-5.3 -> php-5.3.2
drwxr-xr-x 7 root root 4096 Oct  8  2009 /package/host/localhost/php-5.3.0
lrwxrwxrwx 1 root root   11 Jan 22  2010 /package/host/localhost/php-5.3.1 -> php-5.3.1-5
drwxr-xr-x 7 root root 4096 Nov 24  2009 /package/host/localhost/php-5.3.1-1
drwxr-xr-x 6 root root 4096 Nov 27  2009 /package/host/localhost/php-5.3.1-2
drwxr-xr-x 7 root root 4096 Dec  3  2009 /package/host/localhost/php-5.3.1-3
drwxr-xr-x 7 root root 4096 Jan 21  2010 /package/host/localhost/php-5.3.1-4
drwxr-xr-x 7 root root 4096 Jan 22  2010 /package/host/localhost/php-5.3.1-5
lrwxrwxrwx 1 root root   11 Dec 14 11:19 /package/host/localhost/php-5.3.2 -> php-5.3.2-6
drwxr-xr-x 7 root root 4096 Mar  6  2010 /package/host/localhost/php-5.3.2-1
drwxr-xr-x 7 root root 4096 Mar  9  2010 /package/host/localhost/php-5.3.2-2
drwxr-xr-x 7 root root 4096 May  6  2010 /package/host/localhost/php-5.3.2-3
drwxr-xr-x 7 root root 4096 May 29  2010 /package/host/localhost/php-5.3.2-4
drwxr-xr-x 7 root root 4096 Jun 22  2010 /package/host/localhost/php-5.3.2-5
drwxr-xr-x 7 root root 4096 Dec 14 11:14 /package/host/localhost/php-5.3.2-6
drwxr-xr-x 9 root root 4096 Nov  3 12:04 /package/host/localhost/php-5.3.3-1

Was du hier siehst, ist ein mehrstufiges System von Symlinks. Die physischen Verzeichnisse tragen jeweils die vollständige Versionsnummer der PHP-Installation, plus noch einen von uns angefügten Release-Suffix, mit dem wir markieren, dass wir eine bestehende PHP-Installation - üblicherweise mit zusätzlichen Modulen - neu kompiliert haben. php-5.3.2-6 heißt also: Die 6. Kompilierung von PHP 5.3.2. Mit Symlinks bauen wir dann immer generischere Versionsangaben zurück.

Konkret bedeutet das: php-5 ist die jeweils aktuellste Version in der aktuellsten Kompilierung der PHP-5-Serie. php-5.4 ist das aktuellste PHP 5.4 und wird auch immer eins bleiben, auch wenn irgendwann PHP 5.5 erscheinen sollte. php-5.3.1 bleibt immer PHP 5.3.1, auch wenn wir auf 5.3.2 oder 5.3.3 upgraden.

Hintergrund ist, dass es zwischen PHP-Versionen oft - manchmal nur minimale - Inkompatibilitäten gibt, die dafür sorgen, dass manche Dinge nicht richtig funktionieren. So gibt es auch heute noch einige Applikationen, die so spezifische Bugs beinhalten, dass sie nur mit PHP 5.2 korrekt ausführbar sind, während sie unter PHP 5.3 nicht richtig laufen. Mit unserem Schema hast du die Möglichkeit, unabhängig davon, was gerade aktuell ist, eine ganz bestimmte PHP-Version auf deinem Uberspace festzupinnen und für alle Zeit dabei zu bleiben (auch wenn ohne Frage sinnvoller wäre, keine Software einzusetzen, die zwangsweise auf älteren PHP-Versionen besteht).

PHP-Version einstellen

In deinem etc-Verzeichnis gibt es eine Datei namens phpversion, in der die Variable PHPVERSION gesetzt wird:

[martina@helium ~]$ cat ~/etc/phpversion 
## 2011-01-21 /usr/local/sbin/uberspace-account-create.sh 
PHPVERSION=5.3.10

Hier kannst du die Versionsnummer deiner Wahl eintragen - wähle einfach eine der Versionen, die in /package/host/localhost/php-* vorliegen. Nach dieser Änderung musst du deinen Interpreter neu starten. Das war's!

Wenn du den PHP-Interpreter auch direkt auf der SSH-Shell benutzt, musst du dich einmal aus- und wieder einloggen, damit deine ~/.bash_profile neu eingelesen wird; erst dann ist die Version auch auf der Shell entsprechend umgestellt.

Damit du den Zusammenhang verstehst: PHP wird bei uns über das Script php-fcgi-starter gestartet, was in deinem FastCGI-Verzeichnis liegt. Dieses Script bindet die ~/etc/phpversion ein. So sieht das aus:

[martina@helium ~]$ cat ~/fcgi-bin/php-fcgi-starter
#!/bin/sh
## 2011-01-21 /usr/local/sbin/uberspace-account-create.sh 
. ~/etc/phpversion
export PHPRC="/home/martina/etc"
exec /package/host/localhost/php-${PHPVERSION}/bin/php-cgi

Die Zentralisierung der PHP-Version in der separaten Datei hat den Vorteil, dass wir diese dann auch gleich via /etc/profile.d/phpversion.sh dergestalt einbinden können, dass sie nicht nur für deine Website gilt, sondern auch auf der Shell, wenn du einfach nur php ohne Angabe eines konkreten Pfads aufrufst.

Eigene php.ini

Wir setzen bei unseren PHP-Installationen eine php.ini ein, die weitestgehend der php.ini-recommended bzw. php.ini-production entspricht, wie das PHP-Entwicklungsteam sie vorschlägt, ergänzt um die Angabe der lokalen Zeitzone, die ab PHP 5.3 erforderlich ist. Die php.ini liegt dabei im Verzeichnis lib des von dir gewählten PHP-Interpreters. Mittels php --ini kannst du dir den vollständigen Pfad anzeigen lassen. So sieht das aus:

[martina@helium html]$ php --ini
Configuration File (php.ini) Path: /package/host/localhost/php-5.3.2-6/lib
Loaded Configuration File:         /package/host/localhost/php-5.3.2-6/lib/php.ini
Scan for additional .ini files in: (none)
Additional .ini files parsed:      (none)

Möchtest du nun abweichende Einstellungen von der Vorgabekonfiguration vornehmen, so lege dir eine Kopie der php.ini in deinem etc-Verzeichnis an; diese Kopie kannst du dann nach eigenem Gusto bearbeiten (das test -f zu Beginn stellt sicher, dass eine bereits bestehende lokale php.ini auf deinem Uberspace nicht überschrieben wird):

[martina@helium ~]$ test -f ~/etc/php.ini || cp -a /package/host/localhost/php-$PHPVERSION/lib/php.ini ~/etc/
[martina@helium ~]$ nano -w ~/etc/php.ini

Bitte beachte: Die eigene php.ini ersetzt die globale. Es ist also nicht möglich, lediglich die gewünschten Abweichungen in der eigenen php.ini zu notieren, in der Hoffnung, dass diese dann mit den globalen Einstellungen zusammengeführt würden. Stattdessen gelten dann für alle Einstellungen die einkompilierten Werte (plus dann deine eigenen), die sich von den in der globalen php.ini vorgegebenen Einstellungen unterscheiden.

Nach Änderungen musst du deinen PHP-Interpreter neu starten, damit jene übernommen werden.

Übrigens: Die eigene php.ini wirkt auch auf PHP-Scripts, die du außerhalb des Webservers ausführst, also direkt auf der Shell, als Cronjob, via runwhen etc., da wir über die /etc/profile.d/phpversion.sh auch die Umgebungsvariable PHPRC auf dein eigenes etc-Verzeichnis setzen.

PHP-Interpreter neu starten

Dein PHP-Interpreter wird bei einem Webserver-Restart beendet, außerdem nach längerer Inaktivität (wenn also über längere Zeit kein PHP-Script von deinem Uberspace aufgerufen wird). Nach Änderungen am php-fcgi-starter oder dem Anlegen oder Ändern einer eigenen php.ini musst du aber eventuell noch laufende PHP-Interpreter beenden, damit beim nächsten Aufruf einer PHP-Seite von deinem Uberspace die gewünschten Änderungen zum Tragen kommen. Das geht am einfachsten so:

[martina@helium ~]$ killall -u martina php-cgi

Die Angabe deines Uberspace-Namens mit -u ist optional; ohne ihn wirst du ein paar Fehlermeldungen erhalten, weil killall dann auch versuchen wird, die PHP-Interpreter anderer User zu killen, wozu du natürlich nicht berechtigt bist. Deine eigenen werden aber natürlich damit trotzdem beendet. Eine Meldung „php-cgi: Kein Prozess abgebrochen“ stellt kein Problem dar: Sie signalisiert einfach nur, dass ohnehin kein PHP-Prozess unter deiner User-ID läuft, der abgebrochen werden könnte.

Der Neustart deines PHP-Interpreters erfolgt dann automatisch beim nächsten Aufruf einer PHP-Seite.

Eigene PEAR-Module installieren

(Für wiederkehrende Besucher: Wir haben hier früher den Weg über den PEAR-Installer aus dem Web dokumentiert, http://pear.php.net/go-pear - der aber leider mit neueren PHP-Versionen nicht mehr funktioniert. Dafür haben wir jetzt eine noch schickere Lösung gefunden, bei der du gar nichts mehr installieren musst, sondern nur noch eine eigene PEAR-Konfiguration anlegen musst.)

Viele größere PHP-Applikationen benötigen eine ganze Reihe an Modulen aus dem PEAR-Repository. Global haben wir nur ein Standardset davon installiert; wenn dir etwas fehlt, kannst du das zunächst ganz simpel bei uns anfragen.

Wenn du nicht warten willst oder aber volle Kontrolle haben willst, kannst du dir problemlos eigene PEAR-Module innerhalb deines Uberspaces installieren. Das Kommandozeilentool pear wird bereits von unserem PHP-Setup bereitgestellt; was dir noch fehlt, ist eine lokale Konfigurationsdatei mit den Pfaden, in denen deine eigenen PEAR-Module installiert werden sollen. Diese kannst du dir wie folgt anlegen:

[martina@helium ~]$ pear config-create ~ ~/.pearrc

Dir wird eine Übersicht über die verwendeten Pfade angezeigt. Du kannst hier ersehen, dass PEAR gerne das Unterverzeichnis pear in deinem Home-Verzeichnis verwenden möchte, was eine gute Idee ist. Anschließend solltest du das Channel-Protokoll aktualisieren, weil dies typischerweise immer schon neuer ist als das der PEAR-Version, die mit PHP ausgeliefert wird (wenn nicht, schadet der Befehl auch nichts):

[martina@helium ~]$ pear channel-update pear.php.net

Das war's auch schon beinahe - nur ein letzter Schritt fehlt noch: Du musst nämlich deinem PHP sagen, wo es die von dir selbst installierten PEAR-Module finden kann. Dazu brauchst du eine eigene php.ini, um in jener dann den include_path so zu setzen kannst, dass er deine lokale PEAR-Installation mit berücksichtigt. Dazu legst du dir eine Kopie der globalen php.ini an (das test -f zu Beginn sorgt dafür, dass die globale php.ini nur dann in deinen Uberspace kopiert wird, wenn du dort nicht schon eine liegen hast - die sollte dann ja nicht überschrieben werden):

[martina@helium ~]$ test -f ~/etc/php.ini || cp -a /package/host/localhost/php-$PHPVERSION/lib/php.ini ~/etc/

Nun gilt es, den include_path anzupassen. Wir schlagen vor, hier drei Verzeichnisse angeben (die jeweils durch einen Doppelpunkt getrennt werden): Erstens den aktuellen Pfad (symbolisiert durch einen Punkt), zweitens dein lokales PEAR-Verzeichnis, drittens das globale PEAR-Verzeichnis. Die erste und dritte Angabe sind unser Default; die zweite kommt nun dazu. Du kannst das von Hand mit einem Texteditor machen oder mit einem regulären Ausdruck direkt ersetzen; unser Vorschlag:

[martina@helium ~]$ perl -pi -e "s|^include_path.*|include_path=.:$HOME/pear/php:/package/host/localhost/php-$PHPVERSION/lib/php|" ~/etc/php.ini

Bitte vergiss nicht, noch deinen PHP-Interpreter neu zu starten. Das ist erforderlich, weil ja deine php.ini angepasst wurde. Nach der Installation einzelner PEAR-Module brauchst du diesen Neustart nicht; diese werden automatisch zur Laufzeit gesucht und gefunden.

Das war's - du kannst nun eigene PEAR-Module installieren und nutzen. Wir zeigen das hier mal exemplarisch am Beispiel des PEAR-Moduls Mail_Mime (du musst diesen Schritt natürlich nicht nachvollziehen, ist ja nur ein Beispiel):

[martina@helium ~]$ pear install Mail_Mime
downloading Mail_Mime-1.8.1.tgz ...
Starting to download Mail_Mime-1.8.1.tgz (31,530 bytes)
........done: 31,530 bytes
install ok: channel://pear.php.net/Mail_Mime-1.8.1

Eigene PECL-Module installieren

Du benötigst zunächst, so wie im vorigen Abschnitt beschrieben, eine eigene ~/.pearrc, damit das pecl-Tool temporäre Dateien innerhalb deines eigenen Verzeichnisses ablegt (global kann es da zu Kollisionen kommen, wenn durch andere User bereits ein /tmp/pear angelegt wurde, auf dem du dann keine Schreibrechte hast). Der erste Schritt ist also:

[martina@helium ~]$ pear config-create ~ ~/.pearrc

Während im Prinzip die Installation von PECL-Modulen analog zu der von PEAR-Modulen mit dem Kommandozeilentool pecl erfolgen könnte, so funktioniert das in der Praxis leider nicht. Zwar bietet die Konfigurationsdatei .peclrc theoretisch die Möglichkeit, das extension_dir, in dem kompilierte Erweiterungen installiert werden sollen, userspezifisch festzulegen - in der Praxis kommt diese Einstellung im Prozess der Installation aber gar nicht zum Tragen, sondern es wird das extension_dir verwendet, das von php-config ausgegeben wird, so dass das pecl-Tool Module grundsätzlich global installieren will, was als Nicht-root-User natürlich nicht möglich ist. Auch eine eigene php.ini mit angepasstem extension_dir hilft in diesem Punkt nicht.

Wir haben daher einen eigenen kleinen Wrapper geschrieben, der das pecl-Tool lediglich zum Download des Moduls verwendet und es dann aber gemäß der Anleitung zum Kompilieren mittels phpize selbst baut und innerhalb deines Uberspaces installiert, und zwar im Verzeichnis ~/pecl (sofern du kein anderes extension_dir mittels einer eigenen php.ini angegeben hast - dann würde automatisch jenes verwendet). Solltest du noch keine eigene php.ini haben, legt es automatisch eine Kopie des globalen Defaults für dich an. Anschließend bindet es das Modul dort ein.

Der Wrapper wird mit uberspace-install-pecl aufgerufen und bekommt den Namen des gewünschten PECL-Moduls als Argument übergeben. Er kann im Gegensatz zum Original-pecl-Tool zwar keine Abhängigkeiten auflösen; da aber viele häufig benutzten Module ohnehin keine besonderen Abhängigkeiten zu anderen PECL-Modulen haben, sollte das kein Problem darstellen. Zu den Modulen, die sich erfahrungsgemäß unproblematisch installieren lassen, zählen unter anderem apc, imagick, mongo, pecl_http, uploadprogress und zip.

So sieht die Installation dann aus, exemplatisch am Beispiel des Moduls mongo:

[martina@helium ~]$ uberspace-install-pecl mongo
Creating build directory ... done: /tmp/tmp.BYQti10179
Downloading PECL module ... 
downloading mongo-1.2.7.tgz ...
Starting to download mongo-1.2.7.tgz (84,677 bytes)
....................done: 84,677 bytes
File /tmp/tmp.BYQti10179/mongo-1.2.7.tgz downloaded
Extracting ./mongo-1.2.7.tgz ... done: extracted to ./mongo-1.2.7
Configuring for:
PHP Api Version:         20090626
Zend Module Api No:      20090626
Zend Extension Api No:   220090626
[...]
Copying /package/host/localhost/php-5.3.5-1/lib/php.ini to ~/etc ... done
Configuring your extension_dir to /home/martina/pecl ... done
Creating /home/martina/pecl ... done
Installing mongo.so to /home/martina/pecl ... done
Activating mongo.so in ~/etc/php.ini ... done
Killing currently running PHP processes (if any) ... done

Da im letzten Schritt alle aktuell noch laufenden PHP-Interpreter beendet werden, wirkt sich die Installation sofort im Web aus. Solltest du über eine PECL-Erweiterung stolpern, die sich nicht mittels uberspace-install-pecl installieren lässt, sag uns einfach Bescheid und wir schauen, was wir für dich tun können.

PHP-Scripts unter Cron

Wie du ja weißt, kannst du bei uns zwischen verschiedenen PHP-Versionen wählen, die wir zu diesem Zweck unter /package für dich installiert haben.

Sowohl auf der interaktiven SSH-Shell als auch bei der Ausführung über den Webserver haben wir dabei dafür gesorgt, dass automatisch die in deiner ~/etc/phpversion eingestellte Version und ggf. auch deine eigene php.ini verwendet wird. Der Haken ist aber, dass Cron keinen Mechanismus bietet, diese Einstellungen ebenfalls einzubinden. Wenn du also unter Cron ein Script mit php somescript.php ausführen lässt, kommt dabei /usr/bin/php zum Tragen, was die Standard-PHP-Version ist, die von der Linux-Distribution mitgeliefert wird - und die ist alt, um nicht zu sagen: Sehr alt. PHP-Scripts, die neuere Versionen voraussetzen, werden daher nicht damit funktionieren.

Du musst also das, was wir in Bezug auf die PHP-Version auf deiner Shell und bei der Ausführung über den Webserver automatisch setzen, in deiner Crontab manuell machen. Dazu musst du zu Beginn der Crontab die folgenden Zeilen ergänzen und für dich anpassen (als eigenständige Zeilen vor dem eigentlichen Job):

PATH=/package/host/localhost/php-5/bin:/bin:/usr/bin
PHPRC=/home/DeinUsername/etc

Die Angabe „5“ in der ersten Zeile müsstest du hierbei ggf. manuell anpassen, wenn du explizit z.B. noch PHP 5.2 verwenden willst. „DeinUsername“ musst du durch deinen Usernamen ersetzen. Es ist in der crontab leider nicht möglich, Platzhalter wie $HOME in Variablenzuweisungen zu verwenden (in den Zeilen mit den eigentlichen Jobs schon, weil diese dann durch Cron unter einer Shell ausgeführt werden).

Nach dieser Änderung laufen deine PHP-Cronjobs mit der gleichen Version und auch der gleichen php.ini wie du es gewohnt bist.

PHP-Scripts unter runwhen

Auch unter runwhen gilt die gleiche Problemstellung wie bei PHP-Scripts unter cron: Sowohl die Versionseinstellung aus der ~/etc/phpversion als auch eine ggf. angelege eigene php.ini haben hier keine Wirkung.

Du musst daher das von runwhen-conf angelegte run-Script (also ~/service/jobname/run) wie folgt erweitern, am Besten gleich oben unter der Zeile, die die Variable RUNWHEN definiert:

export USER=`id -un`
export HOME=/home/$USER
source $HOME/.bash_profile

Damit wird deine gewohnte Shell-Umgebung geladen, die unter anderem auch die in der ~/etc/phpversion eingestellte PHP-Version aktiviert sowie die Variable PHPRC setzt.

Nach dieser Änderung laufen deine PHP-runwhen-Jobs mit der gleichen Version und auch der gleichen php.ini wie du es gewohnt bist.

development/php.txt · Zuletzt geändert: 2012/04/27 21:41 von uber
Recent changes RSS feed Driven by DokuWiki Valid XHTML 1.0 Valid CSS