{"id":334,"date":"2009-07-10T13:05:40","date_gmt":"2009-07-10T11:05:40","guid":{"rendered":"http:\/\/blog.benny-baumann.de\/?p=334"},"modified":"2009-07-10T13:07:29","modified_gmt":"2009-07-10T11:07:29","slug":"konsequent-inkonsistent","status":"publish","type":"post","link":"https:\/\/blog.benny-baumann.de\/?p=334","title":{"rendered":"Konsequent inkonsistent"},"content":{"rendered":"<p>PHP ist eine wunderbare Programmiersprache &#8230; zumindest f\u00fcr Masochisten. Wer zudem noch auf Inkonsistenz steht, hat sp\u00e4testens mit PHP eine verl\u00e4ssliche Quelle f\u00fcr t\u00e4gliche \u00dcberraschungen zur Verf\u00fcgung. Wer das nicht glaubt, sollte sich PHP einmal anschauen: Hier also einmal ein Einsteiger-Kurs, f\u00fcr alle die, die schon immer eine Sprache haben wollten, die mehr Ausnahmen wie das deutsche Steuerrecht besitzt und komplizierter wie Brainfuck zu programmieren ist. Gut: Beides war vor PHP da, von daher k\u00f6nnte man maximal schlechte Immitation konstatieren, aber selbst das passt zur Sprache an sich ja bereits mehr als treffend.<!--more--><\/p>\n<p>Als erstes schauen wir uns einmal an, wie Funktionen arbeiten. Ja, Funktionen: Diese Dinge, die PHP mitliefert, um aus Parametern Ergebnisse zu generieren. Das einfachste Beispiel f\u00fcr eine solche ist strpos. Diese liefert f\u00fcr einen gegebenen Suchstring die Angabe, wo in einem Quellstring das erste Vorkommen anzutreffen ist. Der R\u00fcckgabewert ist hierbei der Offset des ersten Zeichens des Vorkommens, was viele veranlasst, nach dem Vorhandensein mal eben so zu fragen:<\/p>\n<pre lang=\"php\" escaped=\"true\">if($p = strpos($a,$b)) {\r\n    echo \"Gefunden an Position $p.\";\r\n}<\/pre>\n<p>Das ist doch mal richtig elegant! Naja, und falsch, da wir nie &#8222;Hallo&#8220; in &#8222;Hallo Welt!&#8220; finden werden &#8211; zumindest nicht mit diesem Source. Viele werden jetzt sagen, dass da was fehlt: Ja, die explizite Typ-Pr\u00fcfung:<\/p>\n<pre lang=\"php\" escaped=\"true\">if(false !== ($p = strpos($a,$b))) {\r\n    echo \"Gefunden an Position $p.\";\r\n}<\/pre>\n<p>Das w\u00e4ren dann aber auch gleich die schlimmsten Abarten verschiedenster Sprachen \u00fcbernommen: String-Indizierung von C, Weak-Typing und Inline-Assignments &#8211; zumindest wenn man sauberen Quelltext schreiben m\u00f6chte, ist solcher syntaktischer Zucker Gift. Aber das ist eine andere Geschichte. Genauso wie das Einf\u00fcgen von Variablen in geparste Strings. Die im obigen Beispiel bereits verwendete M\u00f6glichkeit, Variablen direkt in einen String einzubetten mag f\u00fcr einfache F\u00e4lle zwar ausreichen, verfehlt aber mindestens die M\u00f6glichkeit, Escaping gleich mit zu erledigen. Wer so seine Strings ausgibt hat zumindestens eine neue Stelle geschaffen, bei der unkontrolliert gef\u00e4hrliche Daten an die Welt gelangen k\u00f6nnten. Aber lassen wir das vorerst, da hier weniger die Art der Ausgabe, als vielmehr die \u00fcbergebenen Daten Schuld w\u00e4ren. Aber einwas sch\u00f6nes hat diese Syntax schon: Man kann auch direkt Arrays einbetten:<\/p>\n<pre lang=\"php\" escaped=\"true\">$a = array(\"test\");\r\necho \"\\$a[0] = $a[0]\";<\/pre>\n<p>Soweit klar. Aber wehe man will verschachtelte Arrays nutzen, denn dann liefert<\/p>\n<pre lang=\"php\" escaped=\"true\">$a = array(array(\"test\"));\r\necho \"\\$a[0][0] = $a[0][0]\";<\/pre>\n<p>nicht etwa die gew\u00fcnschte Ausgabe &#8218;$a[0][0] = test&#8216;, sondern &#8218;Array[0]&#8216;. Hups? Was ist da passiert? PHP parst Arrays in Strings zwar, jedoch nicht deren Verschachtelungen. M\u00f6chte man dies erreichen, muss man dies markieren:<\/p>\n<pre lang=\"php\" escaped=\"true\">$a = array(array(\"test\"));\r\necho \"\\$a[0][0] = {$a[0][0]}\";<\/pre>\n<p>Dann kann man aber auch gleich \u00fcbertreiben:<\/p>\n<pre lang=\"php\" escaped=\"true\">$a = array(array(0));\r\necho \"\\$a[0][0] = {$a[$a[0][0]][$a[0][0]]}\";<\/pre>\n<p>Gelle?<\/p>\n<p>Okay. Zugegebenerma\u00dfen ist die Variablen-Syntax innerhalb von Strings nicht ganz logisch. Die Ecken und Kanten von Heredoc und PHPDoc spare ich mir jetzt aber einmal &#8211; etwas so schlecht von Perl abgeschautes muss man nicht auch noch kommentieren. <\/p>\n<p>Von daher lassen wir das und schauen uns daf\u00fcr einmal Referenzen an. Referenzen sollen in PHP in etwa das erm\u00f6glichen, wof\u00fcr es in anderen Programmiersprachen Pointer gibt &#8211; nur halt etwas weniger gef\u00e4hrlich. Naja, eine Gefahr ist PHP ja bereits an sich, also brauch es der User nicht auch noch erweitern. Aber zur\u00fcck zu Referenzen. Was macht folgender Code?<\/p>\n<pre lang=\"php\" escaped=\"true\">$a[] =& $a = array();<\/pre>\n<p>Je nach PHP-Version entweder ein in sich rekursives Array erzeugen, oder ein Array, in dem ein rekursives Array anzutreffen ist. Halt je nach PHP-Version, aktueller Weltraum-Wetterlage und derzeitigem Ladestatus des beiliegenden Flux-Kompensators.<\/p>\n<p>Ach ja: Rekursive Arrays, da war ja noch was: wenn man Spa\u00df haben will, versucht man obiges Array einmal zu serialisieren. Dies wird einem von PHP mit dem Hinweis &#8222;Out of Memory&#8220; oder &#8222;Stack Overflow&#8220; (wieder je nach Weltraumwetterlage) quittiert. Korrekt w\u00e4re &#8222;a:{i:0;r:0;};&#8220; Was? r ist noch niemandem aufgefallen beim Serialisieren? Vermutlich deshalb, weil unserialize Daten lesen kann, die serialize nicht einmal generieren kann &#8211; einmal ganz abgesehen davon, dass die Rekursions-Pr\u00fcfung zur Kreis-Erkennung im Serialisierungsgraphen fehlt&#8230;<\/p>\n<p>Witzig ist \u00fcbrigens auch die Abwandlung &#8222;a:{i:0;r:1;};&#8220;. Diese liefert nicht etwa einen Fehler wie &#8222;ung\u00fcltige Referenz&#8220; zur\u00fcck, sondern erzeugt einfach ein neues Array, was dann in das bestehende eingeh\u00e4ngt wird (und in dem dann die korrekte Rekursion auf sich selbst stattfindet). Wobei Serialisierung, da war ja noch PHP 6 &#8230; Ja! Da soll das mit der Serialisierung, den __wakeup- und den __sleep-Methoden abgeschafft werden! Aber nicht ohne im gleichen Atemzug Serialisierung nach XML einzuf\u00fchren. Zumal __wakeup und __sleep ja gerade erst in der 5er Version eingef\u00fchrt wurden. Naja. War halt eine der Irrungen der Kindheit.<\/p>\n<p>Genauso kindlich, wie das Type-Hinting in PHP4. Ja, man konnte PHP4 sagen, welchen Datentyp man erwartet und sich dann eine Meldung generieren lassen, sollte dies nicht der Fall sein. Nunja, eben dieses Feature, was nur Basis-Typen in PHP4 und nur Klassen in PHP5 unterst\u00fctzt. Bessere Kompatibilit\u00e4t kann man gar nicht gew\u00e4hrleisten. Doch: Array geht in beiden Versionen! Wahrscheinlich ein Grund mehr, das in PHP6 endlich mal zu \u00e4ndern, damit wenigstens Type Hinting nicht mehr interoperabel ist. Aber gut: Daf\u00fcr l\u00e4sst sich das ja seit PHP5 \u00fcber einen Error Handler emulieren &#8211; wenn auch die Performance dabei arg in die Knie geht; aber was soll&#8217;s: Wir ham&#8217;s ja!<\/p>\n<p>Ja, wir haben es: Endlich sind sie da: Anonyme Funktionen! Zumindest f\u00fcr all jene, die PHP 5.3 einsetzen. Diese Funktion, die es endlich erlaubt, ohne mit create_function unkontrollierbare Speicherl\u00f6scher aufzurei\u00dfen, syntaktisch pr\u00fcfbare Quelltext-Bl\u00f6cke an der Stelle einzubauen, wo sie hingeh\u00f6ren. Wie? Was soll an create_function Speicherl\u00f6scher rei\u00dfen? Glaubt ihr nicht? Wohl noch keinen Code, wie folgendes Beispiel gesehen?<\/p>\n<pre lang=\"php\" escaped=\"true\">$result = preg_replace_callback(\"\/a\/\", create_function(\"return 'b';\"), $text);<\/pre>\n<p>M\u00f6glichst in einer Schleife, damit es sich auch lohnt \ud83d\ude09 Ja, sowas geht heute effizienter:<\/p>\n<pre lang=\"php\" escaped=\"true\">$result = preg_replace_callback(\"\/a\/\", function($m) { return 'b'; }, $text);<\/pre>\n<p>und da wir gerade dabei sind, f\u00fchren wir auch gleich noch Closures ein &#8211; und erg\u00e4nzen f\u00fcr den Spa\u00dffaktor gleich noch die n\u00e4chste Inkonsistenz:<\/p>\n<pre lang=\"php\" escaped=\"true\">$answer = 0;\r\n$foo = function($bar) use (&$answer) { $answer = $bar; };\r\n$foo(42);\r\necho $answer;<\/pre>\n<p>Was soll daran inkonsistent sein? Nunja &#8230; Passing By-Ref wurde eben erst deprecated. Ein Grund mehr, es bei Closures frisch neu einzuf\u00fchren. W\u00e4re ja sonst logisch&#8230;<\/p>\n<p>Wer&#8217;s nicht kennt: Pass-By-Ref ist das, was so undurchsichtig gehalten ist, dass es nicht nur auf jeder PHP-Version anders funktioniert, sondern zudem sogar noch unterschiedlich angefordert werden muss. Schrieb man also in PHP4 im Aufruf das &#038; vor die Variable, so geh\u00f6rt es in PHP5 in die Parameterzeile &#8211; oder so. Und w\u00e4hrend PHP4 Objekte per Default kopiert, sorgt PHP5 bei Angabe des Referenz-Operators f\u00fcr das Kopieren. Ich habe nicht erst eine Klasse zwischen PHP4 und PHP5 umgeschrieben, weil sich dieses Verhalten grundlegend umgekehrt hat. Wenigstens darauf kann man sich verlassen &#8230;<\/p>\n<p>Eigentlich nicht mal darauf. Manche Fehler werden wenigstens konsequent fortgef\u00fchrt. Autoloading w\u00e4re da ein Beispiel. Wenn einmal ein Script eine __autoload-Methode enthalten hatte, konnte sich keine weitere Datei einen eigenen Autoloader leisten, au\u00dfer diese haben kooperiert. Dies mag f\u00fcr kleinere Skripte durchaus gehen, ben\u00f6tigt man jedoch ein oder mehrere Frameworks, so schie\u00dft man sich damit effektiv ins Knie. Also \u00e4rgenzen wir doch einfach einmal eine SPL-Bibliothek, die dieses Autoloading regelt. Nur gut, dass wir nun die H\u00e4lfte vergessen und man somit wieder f\u00fcr jede PHP-Version Sonderbehandlungen anstellen darf. Was aber wenigstens bleibt, ist die fehlende M\u00f6glichkeit, ohne Exception-Workarounds PHP darauf hinzuweisen, dass eine Klasse nicht geladen werden kann, ohne dass PHP gleich darauf durch diverse Speicherfehler wegschmiert. Dies ist die einzige Stelle, an der ich ernsthaft die Verwendung von eval ben\u00f6tige &#8211; was bei entsprechender Policy das Script zwar auch zum Absturz bringt, aber das w\u00fcrde es ja sowieso &#8230; Von daher ja kein Verlust!<\/p>\n<p>Apropro kein Verlust: schon jemand einmal versucht die Sicherheits-Funktionen von PHP verstanden? Ja, ich meine diese Kr\u00fccken, die wohl besser unter Black Magic h\u00e4tten bekannt gemacht werden sollen, statt sie Safe Mode und Magic Quotes zu nennen. Eben diese Kr\u00fccken haben extra erst daf\u00fcr gesorgt, dass hunderte von Anwendern erst recht richtige Sicherheitsl\u00fccken bei sich aufgerissen haben, weil durch das verworrene Verhalten dieser Funktionen alles M\u00f6gliche, nur nicht das vom Anwender spezifizierte Verhalten aufgezeigt haben. So geh\u00f6ren SQL-Statements escaped. Laut PHP mit einem Backslash &#8211; je nach DBMS aber mit was ganz anderem. Dabei wollen wir mal noch nicht darauf herumhacken, dass nicht einmal MySQL sich einig ist, was denn nun einen Backslash verdient. Wie soll das dann wohl PHP erraten. Ganz magisch halt, indem es einfach mal vor alles, was suspekt erscheint einen Backslash pflastert. Wer dann aus Versehen franz\u00f6sische Backticks und andere falsch escapete Unicode-Sonderzeichen seiner Eingabe spendiert, hat seinen Payload schon fast durchgebracht. Und da dieses Escaping nicht nur f\u00fcr Datenbank-Befehle operiert, sondern auch f\u00fcr eine Reihe anderer Kommandos verliert man schnell mal die \u00dcbersicht. Wenn man dann noch nicht einmal zuverl\u00e4ssig erkennen kann, ob dieses Escaping auch funktioniert, ist das Chaos perfekt.<\/p>\n<p>Die Open Basedir Restriction jetzt zu flamen liegt mir fern. Dieses Feature funktioniert zur Ausnahme ja \u00f6fters sogar mal. Zumindest meist dann, wenn man das Funktionieren gerade nicht gebrauchen kann. F\u00fcr den umgekehrten Fall gibt es cURL und diverse andere Bibliotheken, die diesen Schwachsinn nicht ganz so ernst nehmen.<\/p>\n<p>Wer also eine Sprache sucht, die in ihrem Design nicht einmal f\u00fcr Gewinner des IOCCC verst\u00e4ndlich wird, sollte sofort einen Blick auf PHP werfen. Komprimierter kann man Designfehler nicht zusammenfassen: Selbst Oracle ist gr\u00f6\u00dfer \ud83d\ude09<\/p>\n<p class=\"wp-flattr-button\"><a href=\"https:\/\/blog.benny-baumann.de\/?flattrss_redirect&amp;id=334&amp;md5=63f7ee4ef00c187b4d84cca742f19d1d\" 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>PHP ist eine wunderbare Programmiersprache &#8230; zumindest f\u00fcr Masochisten. Wer zudem noch auf Inkonsistenz steht, hat sp\u00e4testens mit PHP eine verl\u00e4ssliche Quelle f\u00fcr t\u00e4gliche \u00dcberraschungen zur Verf\u00fcgung. Wer das nicht glaubt, sollte sich PHP einmal anschauen: Hier also einmal ein Einsteiger-Kurs, f\u00fcr alle die, die schon immer eine Sprache haben wollten, die mehr Ausnahmen wie [&hellip;]<\/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":[29],"tags":[98,21,346],"class_list":["post-334","post","type-post","status-publish","format-standard","hentry","category-software","tag-developement","tag-php","tag-server"],"_links":{"self":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/334","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=334"}],"version-history":[{"count":4,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/334\/revisions"}],"predecessor-version":[{"id":345,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/334\/revisions\/345"}],"wp:attachment":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=334"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=334"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=334"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}