Die Jungs von WordPress haben wieder mal ganze Arbeit geleistet: Wieder ist eine neue Version draußen. Und nun stellt sich die Frage: Wie am einfachsten aktualisieren, ohne die in der eigenen Installation vorhandenen Patches erneut einpflegen zu müssen?Da ich schon seit längerem recht gerne SVN verwende, hab ich mir bereits beim Aufsetzen meines Blogs überlegt, dass ich jegliche Patches, sei es ein WordPress-Update oder eine von mir vorgenommene Änderung über ein kleines SVN-Repo verwalte. Das mag für viele, die noch nicht mit einer Versionsverwaltung jetzt erstmal seltsam klingen, weil ich im Grunde genommen zwei Mal jede Änderung ausführen muss, aber im Endeffekt ist das eigentlich ganz einfach.
Aber gehen wir der Reihe nach: Um diese Art des Updates ausführen zu können, benötigt man entweder ein lokales SVN-Repository, oder einen SVN-Server, der die Repository-Daten vorhält. Bei mir ist dies der Einfachheit halber ein lokales SVN-Repository, da dies weniger Aufwand beim Erstellen benötigt.
In diesem Repository müssen nun zwei Strukturen gepflegt werden:
- Die WordPress-Basis-Installation mit Plugins
- Die Server-Kopie mit jeglichen Erweiterungen\Patches
Um die erste Kopie zu erstellen, benötigt man von WordPress eine beliebige Original-Version. Diese entpackt man einfach in ein Branch-Verzeichnis und committet dieses. Damit wäre der erste Teil abgeschlossen. Jetzt muss durch kopieren dieses gerade angelegten Branch-Verzeichnisses der Trunk befüllt werden. Hierbei ist es wichtig, wirklich eine Kopie vom Branch über SVN anzulegen, damit später im Repository beide Verzeichnisse verwand sind und somit das Zusammenführen von Veränderungen vereinfacht wird. Nach dem die Kopie korrekt in der Arbeitskopie registriert wurde, noch einmal committen und wir haben ein einfach manage-bares WordPress.
Fehlen noch die Plugins: Diese müssen IMMER zuerst im Branch eingepflegt werden (durch Reinkopieren), bevor diese mit einem svn merge in die Server-Kopie übernommen werden können. dies ist nötig, damit immer in eine Richtung von der unveränderten zur veränderten Version gepatcht wird, da sonst die Originalversion verunreinigt und damit im schlimmsten Falle wertlos wird. Die Plugins sind hierbei, wie bei jeder normalen WordPress-Installation auch, einfach im Branch in das Plugin-Verzeichnis abzulegen, committen und die Änderungen aus dem Branch in den Trunk mergen (in die Server-Kopie) – fertig!
Und nun zum Interessanten Teil, wo sich dieser Mehraufwand plötzlich eindrucksvoll auszahlt. Nehmen wir nun an, WordPress stürzt immer mit einem Fatal Error ab, weil z.B. die Textersetzung mit preg_replace mit /e-Modifier auf dem Server nicht erlaubt ist. An statt jetzt für jedes WordPress-Update erneut einen Patch einspielen zu müssen, kann man sich jetzt eine ganze Menge Arbeit sparen. Dazu korrigiert man den Fehler nicht wie gerade bei den Versionsupdates und den Plugins gezeigt im Branch (Original-Stand der Software), sondern korrigiert diesen einmalig in seiner Serverkopie innerhalb des Repositories. Nach einem Commit ist dieser Stand gesichert und kann jederzeit wieder geholt werden. Außerdem haben wir jetzt 2 Vorteile: Wir wissen, wann wir einen Bug behoben haben UND im Falle eines Versionsupdates von WordPress wird unsere Fehlerkorrektur automatisch mit beachtet und im Versionsupdate eingepflegt.
Wer mir jetzt nicht glaubt, dass das wirklich so einfach geht, für den hab ich ein schönes Beispiel. Angenommen, ich hab nicht nur eine solche Fehlerkorrektur, sondern eine ganze Reihe davon. Bei einer Fehlerkorretur bzw. Anpassung mag es vielleicht noch gehen, eine blanke WordPress-Version herzunehmen und kurz einen Patch einzuspielen. Aber bei hunderten? Gerade, wenn man keine expliziten Patch-Files hat???
Bliebe noch ein letzter Punkt zu klären, denn ich habe preg_replace mit /e-Modifier nicht umsonst oben angesprochen. Auf meinem Server habe ich nämlich genau dieses Problem und zwar ganz einfach deshlab, weil viele PHP-Autoren noch nie etwas von preg_replace_callback gehört haben. So musste ich nicht nur an einer Stelle, sondern gleich an mehreren Stellen mein WordPress anpassen, wie man gleich im Diff-File (von SVN) noch sieht. Die Änderungen sind relativ unspektakulär, der Effekt ist aber in Sachen Sicherheit nicht zu verkennen, da mit preg_replace mit /e beliebiger PHP-Code ausgeführt werden kann, da es keine Möglichkeit gibt, bestimmte Zeichen innerhalb eines Ergebnis-Strings (der als PHP-Code angesehen wird) eindeutig zu maskieren. Mit dem folgenden Patch wird daher die unsichere Funktion preg_replace gegen die wesentlich sichere und zudem flexiblere Funktion preg_replace_callback ausgetauscht. Aber gut, nun die Patches gegen WordPress 2.6.3:
Index: ./wp-includes/kses.php
===================================================================
--- ./wp-includes/kses.php (Revision 5)
+++ ./wp-includes/kses.php (Revision 6)
@@ -381,6 +381,9 @@
return '0.2.2';
}
+$wp_kses_split_allowed_html = null;
+$wp_kses_split_allowed_protocols = null;
+
/**
* wp_kses_split() - Searches for HTML tags, no matter how malformed
*
@@ -394,10 +397,18 @@
* @return string Content with fixed HTML tags
*/
function wp_kses_split($string, $allowed_html, $allowed_protocols) {
- return preg_replace('%((|$))|(< [^>]*(>|$)|>))%e',
- "wp_kses_split2('\\1', \$allowed_html, ".'$allowed_protocols)', $string);
+ global $wp_kses_split_allowed_html, $wp_kses_split_allowed_protocols;
+ $wp_kses_split_allowed_html = $allowed_html;
+ $wp_kses_split_allowed_protocols = $allowed_protocols;
+ return preg_replace_callback('%((|$))|(< [^>]*(>|$)|>))%',
+ 'wp_kses_split_cbwrap', $string);
}
+function wp_kses_split_cbwrap($match) {
+ global $wp_kses_split_allowed_html, $wp_kses_split_allowed_protocols;
+ return wp_kses_split2($match[1], $wp_kses_split_allowed_html, $wp_kses_split_allowed_protocols);
+}
+
/**
* wp_kses_split2() - Callback for wp_kses_split for fixing malformed HTML tags
*
und
Index: ./wp-includes/class-phpmailer.php
===================================================================
--- ./wp-includes/class-phpmailer.php (Revision 10)
+++ ./wp-includes/class-phpmailer.php (Revision 11)
@@ -1180,6 +1180,10 @@
return $encoded;
}
+ function EncodeQ_callback($match) {
+ return '='.sprintf('%02X', ord($match[1]));
+ }
+
/**
* Encode string to quoted-printable.
* @access private
@@ -1191,11 +1195,11 @@
$encoded .= $this->LE;
// Replace every high ascii, control and = characters
- $encoded = preg_replace('/([\000-\010\013\014\016-\037\075\177-\377])/e',
- "'='.sprintf('%02X', ord('\\1'))", $encoded);
+ $encoded = preg_replace_callback('/([\000-\010\013\014\016-\037\075\177-\377])/',
+ 'EncodeQ_callback', $encoded);
// Replace every spaces and tabs when it's the last character on a line
- $encoded = preg_replace("/([\011\040])".$this->LE."/e",
- "'='.sprintf('%02X', ord('\\1')).'".$this->LE."'", $encoded);
+ $encoded = preg_replace_callback("/([\011\040])(?=".$this->LE.")/",
+ 'EncodeQ_callback', $encoded);
// Maximum line length of 76 characters before CRLF (74 + space + '=')
$encoded = $this->WrapText($encoded, 74, true);
@@ -1214,15 +1218,15 @@
switch (strtolower($position)) {
case "phrase":
- $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
+ $encoded = preg_replace_callback("/([^A-Za-z0-9!*+\/ -])/", 'EncodeQ_callback', $encoded);
break;
case "comment":
- $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
+ $encoded = preg_replace_callback("/([\(\)\"])/", 'EncodeQ_callback', $encoded);
case "text":
default:
// Replace every high ascii, control =, ? and _ characters
- $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
- "'='.sprintf('%02X', ord('\\1'))", $encoded);
+ $encoded = preg_replace_callback('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/',
+ 'EncodeQ_callback', $encoded);
break;
}
Bevor ich aber diesen Post für heute beende noch ein Wort zum vorhin vorgenommenen Update von WordPress 2.6.3 auf 2.6.5 (DE Edition): Es dauerte MIT Upload auf den Server ganze 5 Minuten, ist mit Datum\Uhrzeit lokal festgehalten UND kann jederzeit einfach rückgängig gemacht werden (wenn es denn nötig wäre). Diese Methode kann aber eigentlich noch mehr, denn theoretisch lässt sich auf diese Art nicht nur ein WordPress schnell und unkompliziert updaten, sondern sogar das für seine Inline-Hacks bekannte phpBB und andere Software-Systeme, an denen man unabhängig vom Distributor eigene Veränderungen vornehmen möchte. Wer also mit einem Versionsverwaltungssystem noch nicht viel am Hut hatte, dem bietet sich hiermit eine einfache Möglichkeit, eine ganze Reihe von Funktionen kennenzulernen.
Ich freu mich schon auf eure Kommentare!
Gerne 😉
Frage 1: Kannst du noch einen Crashkurs für das erstellen des lokalen Repo machen? Ich hab zwar mal das komplette Handbuch gelesen, aber das ist mir irgendwie zu durcheinander.
Frage 2: Exportierst du die Verzeichnisse zuerst oder kommen .svn-Verzeichnisse mit auf den Server? Zumindest FileZilla unter Windows will die immer mit hochladen.
Ansonsten sehr schicke Lösung, werde ich vermutlich auch mal machen.
Grüße,
Martok
Kommentar by Martok — 28.11.2008 @ 18:23:02
Zu Frage 1: Je nach verwendetem Betriebssystem gibt es hier verschiedene Möglichkeiten. Unter Linux (und wenn man die Kommandozeilen-Tools hat auch unter Windows geht es ganz einfach mit
Wobei die Angabe des Repository-Typs wichtig ist, da es mit Berkeley-DBs gern mal Probleme gibt. Außerdem sind FSFS-Repos besser portierbar (das ist aber genug Stoff für nen eigenen Post).
Wenn man unter Windows keine Lust auf Kommandozeile hat, nehmen einem Clients wie TortoiseSVN die Arbeit ab. Ein leeres Verzeichnis erstellen, in dieses im Explorer wechseln und im Kontext-Menü TortoiseSVN -> Projektarchiv hier erstellen auswählen, das war’s.
Zum Nutzen dieses Repositories dann
verwenden oder bei TortoiseSVN das Repository mit file:///C:/name/des/verzeichnisses auschecken.
Zu Frage 2: Theoretisch egal, aber ein Export bietet sich an (tut ich übrigens auch). Gute FTP-Clients(tm) bieten einem die Möglichkeit, bestimmte Dateimasken auszuschließen. Es ist aber eigentlich egal, ob man die .svn-Verzeichnisse mit hochläd, da der Apache standardmäßig versteckte Dateien und Verzeichnisse mit einem 404 (Not Found) beantwortet. Bei TortoiseSVN kann man hier einfach das zu exportierende Verzeichnis mit der rechten Maustaste schnappen und dieses in einen leeren Ordner ziehen. Im daraufhin erscheinenden Kontext-Menü „SVN hierher exportieren“ wählen und fertig. Der Eintrag „SVN Alles hierher exportieren“ exportiert auch unversionierte Dateien. In beiden Fällen wird ein Unterverzeichnis mit dem Namen des exportierten Verzeichnisses am Zielort angelegt.
BenBE.
Kommentar by BenBE — 28.11.2008 @ 18:39:08