{"id":26,"date":"2008-11-28T15:44:24","date_gmt":"2008-11-28T15:44:24","guid":{"rendered":"http:\/\/blog.benny-baumann.de\/?p=26"},"modified":"2008-11-28T15:49:02","modified_gmt":"2008-11-28T15:49:02","slug":"update-leicht-gemacht","status":"publish","type":"post","link":"https:\/\/blog.benny-baumann.de\/?p=26","title":{"rendered":"Update leicht gemacht"},"content":{"rendered":"<p>Die Jungs von WordPress haben wieder mal ganze Arbeit geleistet: Wieder ist eine neue Version drau\u00dfen. Und nun stellt sich die Frage: Wie am einfachsten aktualisieren, ohne die in der eigenen Installation vorhandenen Patches erneut einpflegen zu m\u00fcssen?<!--more-->Da ich schon seit l\u00e4ngerem recht gerne SVN verwende, hab ich mir bereits beim Aufsetzen meines Blogs \u00fcberlegt, dass ich jegliche Patches, sei es ein WordPress-Update oder eine von mir vorgenommene \u00c4nderung \u00fcber ein kleines SVN-Repo verwalte. Das mag f\u00fcr viele, die noch nicht mit einer Versionsverwaltung jetzt erstmal seltsam klingen, weil ich im Grunde genommen zwei Mal jede \u00c4nderung ausf\u00fchren muss, aber im Endeffekt ist das eigentlich ganz einfach.<\/p>\n<p>Aber gehen wir der Reihe nach: Um diese Art des Updates ausf\u00fchren zu k\u00f6nnen, ben\u00f6tigt man entweder ein lokales SVN-Repository, oder einen SVN-Server, der die Repository-Daten vorh\u00e4lt. Bei mir ist dies der Einfachheit halber ein lokales SVN-Repository, da dies weniger Aufwand beim Erstellen ben\u00f6tigt.<\/p>\n<p>In diesem Repository m\u00fcssen nun zwei Strukturen gepflegt werden:<\/p>\n<ol>\n<li>Die WordPress-Basis-Installation mit Plugins<\/li>\n<li>Die Server-Kopie mit jeglichen Erweiterungen\\Patches<\/li>\n<\/ol>\n<p>Um die erste Kopie zu erstellen, ben\u00f6tigt man von WordPress eine beliebige Original-Version. Diese entpackt man einfach in ein Branch-Verzeichnis und committet dieses. Damit w\u00e4re der erste Teil abgeschlossen. Jetzt muss durch kopieren dieses gerade angelegten Branch-Verzeichnisses der Trunk bef\u00fcllt werden. Hierbei ist es wichtig, wirklich eine Kopie vom Branch \u00fcber SVN anzulegen, damit sp\u00e4ter im Repository beide Verzeichnisse verwand sind und somit das Zusammenf\u00fchren von Ver\u00e4nderungen vereinfacht wird. Nach dem die Kopie korrekt in der Arbeitskopie registriert wurde, noch einmal committen und wir haben ein einfach manage-bares WordPress.<\/p>\n<p>Fehlen noch die Plugins: Diese m\u00fcssen IMMER zuerst im Branch eingepflegt werden (durch Reinkopieren), bevor diese mit einem svn merge in die Server-Kopie \u00fcbernommen werden k\u00f6nnen. dies ist n\u00f6tig, damit immer in eine Richtung von der unver\u00e4nderten zur ver\u00e4nderten 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 \u00c4nderungen aus dem Branch in den Trunk mergen (in die Server-Kopie) &#8211; fertig!<\/p>\n<p>Und nun zum Interessanten Teil, wo sich dieser Mehraufwand pl\u00f6tzlich eindrucksvoll auszahlt. Nehmen wir nun an, WordPress st\u00fcrzt 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\u00fcr jedes WordPress-Update erneut einen Patch einspielen zu m\u00fcssen, 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\u00dferdem 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.<\/p>\n<p>Wer mir jetzt nicht glaubt, dass das wirklich so einfach geht, f\u00fcr den hab ich ein sch\u00f6nes 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???<\/p>\n<p>Bliebe noch ein letzter Punkt zu kl\u00e4ren, denn ich habe preg_replace mit \/e-Modifier nicht umsonst oben angesprochen. Auf meinem Server habe ich n\u00e4mlich genau dieses Problem und zwar ganz einfach deshlab, weil viele PHP-Autoren noch nie etwas von preg_replace_callback geh\u00f6rt 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 \u00c4nderungen sind relativ unspektakul\u00e4r, der Effekt ist aber in Sachen Sicherheit nicht zu verkennen, da mit preg_replace mit \/e beliebiger PHP-Code ausgef\u00fchrt werden kann, da es keine M\u00f6glichkeit 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:<\/p>\n<pre lang=\"diff\">\r\nIndex: .\/wp-includes\/kses.php\r\n===================================================================\r\n--- .\/wp-includes\/kses.php\t(Revision 5)\r\n+++ .\/wp-includes\/kses.php\t(Revision 6)\r\n@@ -381,6 +381,9 @@\r\n \treturn '0.2.2';\r\n }\r\n \r\n+$wp_kses_split_allowed_html = null;\r\n+$wp_kses_split_allowed_protocols = null;\r\n+\r\n \/**\r\n  * wp_kses_split() - Searches for HTML tags, no matter how malformed\r\n  *\r\n@@ -394,10 +397,18 @@\r\n  * @return string Content with fixed HTML tags\r\n  *\/\r\n function wp_kses_split($string, $allowed_html, $allowed_protocols) {\r\n-\treturn preg_replace('%((<!--.*?(-->|$))|(< [^>]*(>|$)|>))%e',\r\n-\t\"wp_kses_split2('\\\\1', \\$allowed_html, \".'$allowed_protocols)', $string);\r\n+    global $wp_kses_split_allowed_html, $wp_kses_split_allowed_protocols;\r\n+    $wp_kses_split_allowed_html = $allowed_html;\r\n+    $wp_kses_split_allowed_protocols = $allowed_protocols;\r\n+\treturn preg_replace_callback('%((<!--.*?(-->|$))|(< [^>]*(>|$)|>))%',\r\n+\t   'wp_kses_split_cbwrap', $string);\r\n }\r\n \r\n+function wp_kses_split_cbwrap($match) {\r\n+    global $wp_kses_split_allowed_html, $wp_kses_split_allowed_protocols;\r\n+    return wp_kses_split2($match[1], $wp_kses_split_allowed_html, $wp_kses_split_allowed_protocols);\r\n+}\r\n+\r\n \/**\r\n  * wp_kses_split2() - Callback for wp_kses_split for fixing malformed HTML tags\r\n  *\r\n<\/pre>\n<p>und<\/p>\n<pre lang=\"diff\">\r\nIndex: .\/wp-includes\/class-phpmailer.php\r\n===================================================================\r\n--- .\/wp-includes\/class-phpmailer.php\t(Revision 10)\r\n+++ .\/wp-includes\/class-phpmailer.php\t(Revision 11)\r\n@@ -1180,6 +1180,10 @@\r\n       return $encoded;\r\n     }\r\n \r\n+    function EncodeQ_callback($match) {\r\n+        return '='.sprintf('%02X', ord($match[1]));\r\n+    }\r\n+\r\n     \/**\r\n      * Encode string to quoted-printable.\r\n      * @access private\r\n@@ -1191,11 +1195,11 @@\r\n             $encoded .= $this->LE;\r\n \r\n         \/\/ Replace every high ascii, control and = characters\r\n-        $encoded = preg_replace('\/([\\000-\\010\\013\\014\\016-\\037\\075\\177-\\377])\/e',\r\n-                  \"'='.sprintf('%02X', ord('\\\\1'))\", $encoded);\r\n+        $encoded = preg_replace_callback('\/([\\000-\\010\\013\\014\\016-\\037\\075\\177-\\377])\/',\r\n+                  'EncodeQ_callback', $encoded);\r\n         \/\/ Replace every spaces and tabs when it's the last character on a line\r\n-        $encoded = preg_replace(\"\/([\\011\\040])\".$this->LE.\"\/e\",\r\n-                  \"'='.sprintf('%02X', ord('\\\\1')).'\".$this->LE.\"'\", $encoded);\r\n+        $encoded = preg_replace_callback(\"\/([\\011\\040])(?=\".$this->LE.\")\/\",\r\n+                  'EncodeQ_callback', $encoded);\r\n \r\n         \/\/ Maximum line length of 76 characters before CRLF (74 + space + '=')\r\n         $encoded = $this->WrapText($encoded, 74, true);\r\n@@ -1214,15 +1218,15 @@\r\n \r\n         switch (strtolower($position)) {\r\n           case \"phrase\":\r\n-            $encoded = preg_replace(\"\/([^A-Za-z0-9!*+\\\/ -])\/e\", \"'='.sprintf('%02X', ord('\\\\1'))\", $encoded);\r\n+            $encoded = preg_replace_callback(\"\/([^A-Za-z0-9!*+\\\/ -])\/\", 'EncodeQ_callback', $encoded);\r\n             break;\r\n           case \"comment\":\r\n-            $encoded = preg_replace(\"\/([\\(\\)\\\"])\/e\", \"'='.sprintf('%02X', ord('\\\\1'))\", $encoded);\r\n+            $encoded = preg_replace_callback(\"\/([\\(\\)\\\"])\/\", 'EncodeQ_callback', $encoded);\r\n           case \"text\":\r\n           default:\r\n             \/\/ Replace every high ascii, control =, ? and _ characters\r\n-            $encoded = preg_replace('\/([\\000-\\011\\013\\014\\016-\\037\\075\\077\\137\\177-\\377])\/e',\r\n-                  \"'='.sprintf('%02X', ord('\\\\1'))\", $encoded);\r\n+            $encoded = preg_replace_callback('\/([\\000-\\011\\013\\014\\016-\\037\\075\\077\\137\\177-\\377])\/',\r\n+                  'EncodeQ_callback', $encoded);\r\n             break;\r\n         }\r\n \r\n<\/pre>\n<p>Bevor ich aber diesen Post f\u00fcr 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\u00fcckg\u00e4ngig gemacht werden (wenn es denn n\u00f6tig w\u00e4re). Diese Methode kann aber eigentlich noch mehr, denn theoretisch l\u00e4sst sich auf diese Art nicht nur ein WordPress schnell und unkompliziert updaten, sondern sogar das f\u00fcr seine Inline-Hacks bekannte phpBB und andere Software-Systeme, an denen man unabh\u00e4ngig vom Distributor eigene Ver\u00e4nderungen vornehmen m\u00f6chte. Wer also mit einem Versionsverwaltungssystem noch nicht viel am Hut hatte, dem bietet sich hiermit eine einfache M\u00f6glichkeit, eine ganze Reihe von Funktionen kennenzulernen.<\/p>\n<p>Ich freu mich schon auf eure Kommentare!<\/p>\n<p class=\"wp-flattr-button\"><a href=\"https:\/\/blog.benny-baumann.de\/?flattrss_redirect&amp;id=26&amp;md5=11b7bd5e219aa353cc40f19fd2b0862c\" title=\"Flattr\" target=\"_blank\"><img src=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" srcset=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" alt=\"Flattr this!\"\/><\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>Die Jungs von WordPress haben wieder mal ganze Arbeit geleistet: Wieder ist eine neue Version drau\u00dfen. Und nun stellt sich die Frage: Wie am einfachsten aktualisieren, ohne die in der eigenen Installation vorhandenen Patches erneut einpflegen zu m\u00fcssen?<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[4],"tags":[21,19,20,18],"class_list":["post-26","post","type-post","status-publish","format-standard","hentry","category-server","tag-php","tag-svn","tag-update","tag-wp"],"_links":{"self":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/26","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=26"}],"version-history":[{"count":2,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/26\/revisions"}],"predecessor-version":[{"id":28,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/26\/revisions\/28"}],"wp:attachment":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=26"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=26"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=26"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}