Archive for the ‘PHP’ Category
Das Y2K38 Problem
Wer viel mit Terminen und Datumsangaben arbeitet kennt das Problem vielleicht, aber häufig fällt uns das Problem jetzt noch nicht auf, und in einigen Jahren werden wir dann Probleme bekommen.
Es geht um den Unix Timestamp, also die Anzahl der Sekunden seit 1970. In PHP arbeiten Funktionen wie time() und strtotime() mit diesem Timestamp, aktuell heute liegt diese Zahl bei ca. 1,3 Milliarden (1307428397). Wenn wir nun mit Geburtsdaten arbeiten und jemand hat vor 1970 Geburtstag, dann können wir bekannterweise nicht den Timestamp nutzen. Aber es gibt auch eine obere Grenze, und kaum jemand weiß wo diese liegt. PHP arbeitet im 32-bit-Modus mit 4-Byte signed Integers, also vorzeichenbehaftete Zahlen zwischen -2.147.483.647 und 2.147.483.647, aktuell sind wir mit 1,3 Milliarden bereits über die Hälfte vorangeschritten. Exakt am 19.01.2038 um 03:14:07 werden wir einen Überlauf haben, der Timestamp wird also von 2.147.483.647 auf -2.147.483.647 umspringen, und negative Timestamps bedeuten immer 01.01.1970.
Mit einem Zweizeiler können wir zeigen dass wir bei Timestamps größer 2038 ein Problem bekommen:
<? $date = strtotime('2037-02-01'); echo date('d.m.Y H:i', $date);
Die Ausgabe in diesem Fall lautet 01.02.2037 00:00.
<? $date = strtotime('2039-02-01'); echo date('d.m.Y H:i', $date);
Hier haben wir das Maximum überschritten, es wird ausgegeben: 01.01.1970 01:00.
Aber nicht nur PHP hat Probleme damit, sehr viele Programmiersprachen, Programme und Betriebssysteme sind betroffen. Und da wir alle wissen wie lang einige Programme laufen werden (na, wer muss noch mit alten Cobol-Programmen arbeiten, oder Intranetseiten von 1995 nutzen?), oder man Termine für die Zukunft plant, sollte man schon jetzt mit dem Problem vertraut sein, um nicht schwer zu findende Bugs zu produzieren.
Es gibt mehrere Lösungen um das Problem zu umgehen. Entweder man arbeitet mit 64-bit Systemen und Software, die 8-Byte signed Integers nutzen, um damit das Problem effektiv zu beseitigen. Eine zweite Möglichkeit ist die Zeit in einem String zu speichern, also einfach „2045-05-27“ speichern und dann mit Hilfe der DateTime Klassen diesen String umwandeln und mit ihm rechnen:
$date = new DateTime('2045-05-27'); echo $date->format('d.m.Y H:i');
Gibt aus: 27.05.2045 00:00.
Also kurz drüber nachdenken wenn ihr das nächste Mal Unix Timestamps nutzt die in der Vergangenheit oder der Zukunft liegen, oder falls euer Programm evtl. auch noch in 27 Jahren laufen wird.
Slides der Dutch PHP Conference 2011
In unserem Nachbarland gab es vorletztes Wochenende wieder viel wissenswertes auf der Dutch PHP Conference 2011 zu hören, an 3 Tagen gab es 35 Talks und 7 Tutorials auf die Ohren. Da ich leider dieses Jahr nicht dort sein konnte hier die Liste der Talks inklusive Slides soweit vorhanden:
19. Mai 2011
ZCE 5.3 Exam Preparation
Lorna Mitchell
Optimizing MySQL Essentials
Ligaya Turmelle
Caching on the edge
Fabien Potencier
Think like an ant, distribute the workload
Helgi Þormar Þorbjörnsson
XP Principles and Practices
Sebastian Schürmann
Doctrine 2
Juozas Kaziukėnas
Isolation for your tests
Giorgio Sironi
Eine Rechenaufgabe lösen mit PHP
Ich bastle gerade an einem kleinen Script, das aus einer Reihe Zahlen und arithmetischen Operatoren eine Rechenaufgabe erstellt und löst. Die Rechenaufgabe besteht nicht nur aus Additionen oder Subtraktionen, sondern enthält im einfachen Beispiel auch Multiplikationen, wobei dann auf die Punkt-vor-Strichrechung geachtet werden muss, was das ganze doch etwas erschwert.
Zuerst Beispielcode, damit ihr versteht was ich vorhabe:
<?php $numbers = array(5, 19, 45, 6, 7, 21); $operators = array('*', '+', '-', '*', '+'); // String bauen $mathString = ''; foreach ($numbers as $id => $number) { if ($id < count($numbers)-1) { $mathString .= $number . $operators[$id]; } else { $mathString .= $number; } } // $mathString ist nun '5*19+45-6*7+21'
Nun ist die Aufgabe, aus dem String $mathString das Ergebnis auszurechnen. Die einfachste und schnellste Lösung ist natürlich eval() (oder vergleichbare Funktionen wie create_function() oder assert() ). Folgender Code löst die Rechenaufgabe und gibt das Ergebnis aus:
eval('echo ' . $mathString . ';');
Wenn man nun eval() und Konsorten nicht benutzen möchte oder darf oder kann, wie lautet dann der PHP Code, um eine solche Rechenaufgabe zu lösen? Die beiden oben gezeigten Arrays sind natürlich nur Beispiele, der Algorithmus sollte auch mit anderen Zahlen funktionieren.
Folgende Dinge sind zu beachten:
- $numbers ist ein Array aus unbekannt vielen Zahlen. Im einfachen Fall nur positive Zahlen, im etwas schwierigeren Fall auch negative
- $operators beinhaltet so viele Operatoren wie nötig sind für die Rechnung (also count($numbers)-1 viele). Um es nicht allzu komplex zu machen beschränken wir uns auf die Addition, Subtraktion und Multiplikation (+, – und *)
- Es gilt die Punkt vor Strichrechung zu beachten
- In unserem Fall hier kommen keine Klammern vor.
Wie sieht das ganze nun aus wenn auf die einfache, aber unschöne eval() Lösung verzichtet wird? eval() ist deshalb unschön weil die Zahlen und Operatoren oder gar der ganze $mathString aus Usereingaben kommen könnten, dann muss man sehr gut filtern um keine Sicherheitslücke beim Einsatz von eval() zu erstellen. Oder auf manchen Systemen ist eval() sogar verboten (disabled_functions).
create_function() genauso übel wie eval()?
Heute mal eine Sonntagsfrage:
Ich überlege gerade wie ich ein Problem löse, bei dem ich wohl nur mit viel Aufwand drumherum komme, eval() zu benutzen. Auf der Suche nach einer Lösung fiel mir auch die Funktion create_function() ein, der man ähnlich wie eval() einen String übergeben kann, der dann beim Aufruf der erstellten Funktion ausgeführt wird.
Und nun meine Frage an euch: Sind die beiden Funktionen in der Gefährlichkeit gleichzusetzen wenn man beide mit einem String füllt, der zusammengesetzt wurde aus Usereingaben? Bei beiden kann böses passieren wenn man die Usereingaben nicht ordentlich filtert, sehe ich doch richtig oder? Seht ihr einen Vor- oder Nachteil von create_function() gegenüber eval()?
Ich frage weil eval() überall auf der Welt als böse angesehen wird, aber über create_function() redet niemand, und ich glaube bei unvorsichtiger Nutzung ist sie genauso gefährlich.
Was ist phar und wie nutze ich es?
Phar ist ein Applikations-Archiv-Format genauso wie Jar es für Java ist. Ein Phar-Archiv enthält Dateien und Ordnerstrukturen, und diese Dateien können dann genutzt werden ohne die Phar-Datei zu entpacken. Man kann so seine ganze Applikation oder auch Frameworks in Phar-Dateien packen und verteilen. Phar ist seit 5.2 als PECL Erweiterung verfügbar, seit 5.3 ist es fest eingebaut.
Die Tatsache dass es dann nur noch eine Datei ist hat mehrere Vorteile. Einerseits ist der Upload auf einen FTP schneller, aber auch beispielsweise der Download ist einfacher, anstatt einer zip/tar.gz Datei die danach noch entpackt werden muss lädt man einfach die Phar-Datei und kann loslegen. Viele kleine Dateien bedeuten auch viele Dateisystem-Zugriffe, und wie wir alle wissen ist die Festplatte langsam, Phar bringt also Performance. Wenn man bereits einen Byte-Code-Cache aktiviert hat ist der Performance-Vorteil nur noch gering, aber vorhanden.
Wenn ich beispielsweise in einer phar-Datei meine komplette Applikation habe, starte ich diese folgendermaßen:
php application.phar
Wenn ein Phar-File auf diese Weise gestartet wird, wird das sogenannte Stub-File aufgerufen, quasi der Einstiegspunkt. Das Stub-File ist eine normale PHP-Datei innerhalb des Phar-Archives.
Alternativ kann ich auch aus einem PHP-Script heraus ein Phar-Archiv inkludieren: