Legacy-PHP · 4 Min. Lesezeit
Von PHP 5 auf PHP 8, ohne den Shop anzuhalten
Zwei PHP-Versionen parallel auf einem Server, während der Code Stück für Stück umzieht.
Auf dieser Seite
Die E-Mail vom Hosting-Anbieter ist höflich und endgültig: PHP 5.6 wird zum Quartalsende abgeschaltet. Der Shop läuft auf Code von 2012, niemand, der ihn geschrieben hat, ist noch da, und er nimmt jeden Tag Bestellungen an. Die Version umstellen und hoffen ist kein Plan. Alles neu schreiben ist ein Plan, aber meistens ein schlechter.
So machen wir es: Beide Versionen laufen parallel, und der Code zieht in kleinen Stücken um, jedes für sich getestet.
Warum nicht einfach umstellen?
Weil PHP 8 vieles ablehnt, was PHP 5 akzeptiert hat, und zwar meist mit einem fatalen Fehler, nicht mit einer Warnung. Die üblichen Verdächtigen:
| Was der alte Code macht | Was daraus wurde |
|---|---|
mysql_query() und der Rest von mysql_* |
entfernt in PHP 7.0; stattdessen PDO oder mysqli |
ereg(), split() |
entfernt in PHP 7.0; stattdessen preg_* |
each(), create_function() |
entfernt in PHP 8.0 |
| ein Konstruktor mit dem Namen der Klasse | seit PHP 8.0 ignoriert; das Objekt entsteht ohne ihn |
0 == "abc" ist wahr |
seit PHP 8.0 falsch, was manche if-Abfragen still verändert |
| Eigenschaften, die Objekten im Vorbeigehen hinzugefügt werden | veraltet seit PHP 8.2 |
null an strlen(), trim() und Co. übergeben |
veraltet seit PHP 8.1 |
Die ersten drei legen die Website lahm. Die letzten vier sind schlimmer: Die Website läuft weiter und tut etwas leicht anderes.
Schritt 1: eine Kopie und eine Landkarte
Auf dem Live-Server passiert nichts. Wir nehmen eine Kopie des Codes und eine anonymisierte Kopie der Datenbank, richten beides auf einem Testserver ein und lesen den Code. Zwei Werkzeuge sparen hier Tage:
- PHPCompatibility, ein Regelsatz für PHP_CodeSniffer, listet jede Zeile auf, die unter einer bestimmten PHP-Version bricht.
- Rector schreibt viele dieser Zeilen automatisch um, zum Beispiel alte Array-Syntax oder entfernte Funktionen.
Keines davon ersetzt das Lesen. Sie liefern die Landkarte; die Route legt ein Mensch fest. Das Ergebnis dieses Schritts ist eine schriftliche Liste: was bricht, wo, wie riskant es ist und was zuerst zu tun ist.
Schritt 2: ein Sicherheitsnetz
Bevor wir etwas ändern, stellen wir sicher, dass wir es merken würden, wenn etwas kaputtgeht:
- Backups, die wir tatsächlich einmal auf dem Testserver wiederhergestellt haben;
- eine kurze Liste der Abläufe, die Geld bringen: Suche, Warenkorb, Kasse, die Rechnungs-E-Mail, der Export für die Verwaltung;
- eine Prüfung für jeden dieser Abläufe, automatisiert, wo es günstig ist, und schriftlich, wo nicht.
Schritt 3: zwei Versionen auf einem Server
Auf einem Server der Red-Hat-Familie (AlmaLinux, Rocky, RHEL) installiert das Remi-Repository mehrere PHP-Versionen nebeneinander, jede mit eigenem php-fpm-Dienst. nginx schickt dann jeden Teil der Website an die Version, für die er bereit ist:
# der neue, getestete Teil läuft auf PHP 8
location ^~ /checkout/ {
fastcgi_pass unix:/var/opt/remi/php85/run/php-fpm/www.sock;
include fastcgi.conf;
}
# alles andere läuft vorerst noch auf PHP 5.6
location ~ \.php$ {
fastcgi_pass unix:/opt/remi/php56/root/var/run/php-fpm/www.sock;
include fastcgi.conf;
}
Die Socket-Pfade hängen davon ab, wie jeder Pool eingerichtet ist; es kommt auf das Prinzip an. Die Website läuft die ganze Zeit weiter, und jeder Teil zieht um, wenn er bereit ist, nicht wenn der Kalender es sagt.
Schritt 4: kleine Schritte
Ein Teil nach dem anderen: umstellen, auf dem Testserver prüfen, zu einer ruhigen Stunde live stellen, einen Tag lang die Logs beobachten. Dann der nächste Teil. Die Datenbankschicht kommt meist zuerst, weil fast alles von ihr abhängt und weil in mysql_* die Sicherheitslücken wohnen:
// vorher
$res = mysql_query("SELECT * FROM orders WHERE id=" . $_GET['id']);
// nachher
$stmt = $db->prepare('SELECT * FROM orders WHERE id = ?');
$stmt->execute([(int) $_GET['id']]);
Wenn der letzte Teil umgezogen ist, wird PHP 5.6 abgeschaltet, und niemand merkt es. Genau das ist das Ziel.
Sollten wir nicht lieber neu schreiben?
Selten. Alter Code ist hässlich, aber er enthält auch Jahre behobener Fehler und Geschäftsregeln, die nie jemand aufgeschrieben hat. Eine Neuentwicklung wirft all das weg und muss es wiederfinden, meistens im Livebetrieb. Wir schlagen eine Neuentwicklung nur vor, wenn die Landkarte aus Schritt 1 zeigt, dass sie günstiger ist, und sagen das dann schriftlich.
Wie lange dauert es?
Das hängt von der Größe des Codes ab und davon, wie viele Überraschungen er birgt, und genau das findet Schritt 1 heraus. Deshalb fangen wir dort an: mit einer kleinen Analyse zum Festpreis, die mit dem Plan und einem Preis für den Rest endet.
Wenn die E-Mail Ihres Hosting-Anbieters schon angekommen ist, senden Sie uns eine Anfrage.
Soll das bei Ihnen umgesetzt werden?
Zwei Fragen und eine E-Mail-Adresse. Wir antworten innerhalb von zwei Werktagen, meist schneller.