PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


TLS 1.0/1.1 Abschaltung: Eigene Versionsverteilung herausfinden und serverseitig abschalten

without comments

Browserhersteller planen, ab 2020 die TLS-Versionen 1.0 und 1.1 nicht mehr zu unterstützen:

https://www.heise.de/security/meldung/Verschluesselung-im-Web-Chrome-Firefox-Co-verabschieden-sich-von-TLS-1-0-1-1-4191864.html
https://www.golem.de/news/https-browser-wollen-alte-tls-versionen-2020-abschalten-1810-137135.html

Mit den richtigen Einstellungen und Ciphers ist TLS 1.0 noch sicher zu betreiben, aber man muss es eben richtig konfigurieren, wenn man alles beachten will: BEAST, POODLE, Sloth, DROWN, CRIME und BREACH, RC4, MD5, ROBOT, Sweet32, Bleichenbacher, Heartbleed, FREAK und Logjam, …

Da es schon ein Dutzend Probleme gab in den letzten Jahren, möchte man sich des Problems lieber früher als später entledigen, gern bevor es zum großen Knall kommt. TLS 1.2 ist nicht gegen all diese Probleme gewappnet, man muss nach wie vor aufpassen wie man die Ciphers konfiguriert. Aber man kann weniger Fehler machen. Und das Ziel ist es, TLS 1.3 zu nutzen, wo all dieses Probleme gelöst sind, da alles unsichere radikal entfernt wurde, und nicht mehr 100 Ciphers zur Auswahl stehen, sondern nur noch eine Handvoll. Weniger Auswahl ist eben manchmal besser.

Ich schrieb 2014 über die Abschaltung von SSLv3, und im Dezember 2017 darüber, dass ab dem 30. Juni 2018 im Kreditkarten-/Payment-Bereich TLS 1.2 als Minimum genutzt werden muss.

Weiterlesen »

Written by Michael Kliewe

Oktober 17th, 2018 at 7:06 pm

Performanceboost durch temporäres Abschalten des PHP Garbage Collectors

without comments

Auf der Suche nach einfachen Möglichkeiten, die Performance eines CPU-bound PHP-Scripts zu steigern, fiel mir wieder ein, wie der Composer Installer einen drastischen Performanceboost hinbekommen hat. Selbst ausprobiert, und siehe da: Statt 7 Sekunden Laufzeit nur noch 2,7 Sekunden. Whao!

Wie macht man sowas mit nur 1-3 Zeilenänderungen?

Garbage Collection

Ein paar kurze Worte zum Garbage Collector. Am Ende dieses Blogartikels sind ein paar Links für diejenigen, die mehr wissen wollen. Ich versuche es einfach darzustellen.

Der Garbage Collector läuft im Hintergrund eines PHP-Scripts in der PHP-Engine, seine Aufgabe ist es, ungenutzten, nicht mehr gebrauchten Arbeitsspeicher wieder frei zu machen. Dazu durchläuft er alle Variablen und Datenstrukturen, um zu schauen ob sie noch gebraucht werden. Wenn ein Speicherbereich noch gebraucht wird, dann gibt es eine Referenz darauf (eine Variable im einfachsten Fall). Er findet also alle Speicherbereiche, zu denen es keine Variable mehr gibt, und gibt den Speicher wieder frei.

Das ist nur der einfachste Fall, sehr simpel erklärt. Im Detail muss man auch über Objekte nachdenken, Ressourcen, zyklische Referenzen (wenn X Variablen sich „im Kreis“ referenzieren), und so weiter. Es ist sogar so, dass es beim Garbage Collector von PHP nur um die zyklischen Referenzen geht, normale Variablen werden beim Verlassen eines Scopes (einer Funktion/Methode) schon wieder freigegeben, problematisch sind aber die komplizierteren Referenzen zwischen Objekten und mehreren Variablen, die gegenseitig auf sich zeigen.

Garbage Collection gibt es in allen Programmiersprachen, bei denen der Programmierer sich nicht manuell selbst drum kümmern muss/soll, Speicher wieder freizugeben. In C beispielsweise muss sich der Programmierer selbst drum kümmern, und das geht häufig schief und führt zu Memory Leaks, Sicherheitsproblemen, „double-free“ Fehlern und so weiter. Deshalb nehmen moderne/sicherere Hochsprachen einem Programmierer diese Arbeit ab, die aller meisten modernen Programmiersprachen haben Garbage Collectoren.

Garbage Collectoren laufen also im Hintergrund mit, und versuchen „ab und zu“ Speicher freizubekommen. Dabei durchsucht er alle existierenden Variablen/Datenstrukturen, ob eine davon verworfen werden kann, weil sie nicht mehr gebraucht wird. Hat man sehr viele (Millionen) Objekte, dauert solch ein Durchlauf entsprechend lang, und im schlimmsten Fall ist das Ergebnis: Alle Speicherbereiche werden noch benötigt, es gibt nichts zu tun.

Wie gesagt, recht vereinfacht, in den letzten Jahren gab es sehr viele verbesserte Garbage Collectoren, die nicht immer alle Datenstrukturen durchsuchen, und deren Laufzeit beschränkt wird wenn es zu viel zu durchsuchen gibt, usw. Stichworte: „Serial collector“, „Parallel collector“, „Concurrent Mark Sweep (CMS) Collector“, „Generational Garbage Collector“.

Garbage Collector temporär abschalten

Wie kommt man auf die Idee, die Garbage Collection temporär zu deaktivieren? Es gibt einen bekannten Fall im PHP-Universum: Der Composer Installer. Er war berühmt-berüchtigt für seine Langsamkeit, da die Berechnung der Dependency-Bäume sehr langsam war. Durch eine einzige Zeilenänderung (gc_disable();) konnte der Installer um 30-90% beschleunigt werden.
https://tideways.com/profiler/blog/how-to-optimize-the-php-garbage-collector-usage-to-improve-memory-and-performance
https://blog.blackfire.io/performance-impact-of-the-php-garbage-collector.html

Wenn man als Programmierer weiß, dass in einem bestimmten Code-Block, oder einer Methode, oder gar einem ganzen PHP-Script, der Garbage Collector nur unnötig versucht, Speicher frei zu machen, dann kann man ihn deaktivieren, um der Engine die unnötige Arbeit zu ersparen. Bei PHP-Scripten, die sehr viel CPU benötigen, und die mit vielen Objekten und Speicher arbeiten, kann das Wunder bewirken.

Erst heute morgen habe ich es beim DomPDF Projekt ausprobiert. Mit DomPDF kann man sehr einfach aus (einfachem) HTML ein PDF rendern. Doch DomPDF ist recht langsam bei großen, mehrseitigen Dokumenten, da dauert es gern mal mehrere Hundert Millisekunden oder gar Sekunden. Da gerade in einem Issue über Performance diskutiert wurde, habe ich in der render() Methode den Garbage Collector am Anfang deaktiviert, und am Ende wieder aktiviert. Ein (künstliches) Test-HTML-Dokument benötigt nur noch 2.7 Sekunden statt 7 Sekunden, also eine ähnliche Performancesteigerung wie beim Composer Installer. Und das mit nur 3 Zeilen Code.

$ git diff
diff --git a/src/Dompdf.php b/src/Dompdf.php
index d031938..df37e8d 100644
--- a/src/Dompdf.php
+++ b/src/Dompdf.php
@@ -701,6 +701,8 @@ class Dompdf
      */
     public function render()
     {
+        gc_disable();
+
         $this->saveLocale();
         $options = $this->options;

@@ -864,6 +866,9 @@ class Dompdf
         }

         $this->restoreLocale();
+
+        gc_enable();
+        gc_collect_cycles();
     }

Vorher:

$ php test_performance.php break_tag 10000
Profiling PDF generation using 'break_tag' over 10000 iterations.
STEP          MEMORY USE    PEAK MEMORY   EXECUTION TIME
Start         2,528,280     2,883,608     -
Load          2,553,104     2,883,608     0.0082650184631348
Render        36,158,096    49,725,776    6.9973478317261     <======
Output        36,168,776    49,725,776    0.00060415267944336
End           36,169,232

Nachher:

$ php test_performance.php break_tag 10000
Profiling PDF generation using 'break_tag' over 10000 iterations.
STEP          MEMORY USE    PEAK MEMORY   EXECUTION TIME
Start         2,528,584     2,883,912     -
Load          2,553,408     2,883,912     0.0081119537353516
Render        36,158,432    49,719,360    2.7755401134491    <======
Output        36,169,112    49,719,360    0.00069785118103027
End           36,169,568

Es kommt, wie häufig, auf den Anwendungsfall an, ob dieses temporäre Abschalten des Garbage Collectors etwas bringt oder nicht. Man sollte dabei beachten, dass man dadurch eventuell den Speicherverbrauch erhöht, da eben kein Speicher mehr freigemacht wird wenn der Garbage Collector abgeschaltet ist. Man sollte es also nur nutzen, wenn man dadurch nicht in Speicherprobleme gerät.

Ob man den Garbage Collector am Ende wieder aktiviert, oder bis zum Scriptende ausgeschaltet lässt, kommt drauf an: Wenn man das Script komplett unter der eigenen Kontrolle hat, und es sich nicht um einen langlaufenden Daemon handelt, dann kann man ihn eventuell deaktiviert lassen. Im Falle von DomPDF ist es aber eine Library, die eventuell in einem Daemon genutzt wird, man sollte also unbedingt am Ende den Garbage Collector wieder aktivieren, sonst wundert sich der Nutzer der Library über einen sehr hohen Speicherverbrauch in seinem Script. Deshalb wird in DomPDF der Garbage Collector wieder aktiviert, der Composer Installer jedoch lässt ihn bis zum Ende ausgeschaltet.

Probiert es mal aus in euren langsamen Scripten, die CPU-bound sind und mit vielen Objekten/Referenzen etc. arbeiten. Vielleicht habt ihr dann ähnliche Erfolgserlebnisse 🙂

Und hier die versprochenen Links zu Details des (PHP) Garbage Collectors:

https://blog.ircmaxell.com/2014/12/what-about-garbage.html
https://react-etc.net/entry/improvements-to-garbage-collection-gc-php-7-3-boosts-performance-in-benchmark
https://www.sitepoint.com/better-understanding-phps-garbage-collection/
http://php.net/manual/de/features.gc.performance-considerations.php

Written by Michael Kliewe

Oktober 12th, 2018 at 10:46 am

Der Unterschied zwischen „||“ und „or“ bzw. „&&“ und „and“

without comments

Wenn man eine if-Anweisung in PHP schreiben möchte, und dabei 2 Bedingungen mit einem „und“ verknüpfen möchte, kann man entweder „&&“ nutzen oder „and“ schreiben. Richtig?

if ($a > 0 && $b < 100) {
if ($a > 0 and $b < 100) {

Das ist das selbe, oder? Ja, ist es. Beides funktioniert, beides ist syntaktisch korrekt, und beides ist äquivalent.

Kopieren wir nun die Bedingungen in eine temporäre Variable $c: Weiterlesen »

Written by Michael Kliewe

September 29th, 2018 at 7:33 pm

Posted in PHP

Tagged with ,

igphp – Interessengemeinschaft PHP e.V.

without comments

Ich mag PHP. Ich möchte es auch in Zukunft nutzen, denn man kann sehr effektiv Software schreiben, große wie kleine Projekte umsetzen, und einfach alles machen was man will: Webseiten, Daemons, Cronjobs, Chatbots, IoT-Steuerungen, neuronale Netze, einfach alles. Dazu tragen kontinuierliche Verbesserungen und Erweiterungen der Sprache selbst, aber auch das Ökosystem (Frameworks, Tools, Bibliotheken…) bei. Seit PHP 7 ist PHP mit an der Spitze der performantesten Scriptsprachen. Es gibt eine Menge PHP-User-Groups weltweit, Dutzende Konferenzen jedes Jahr, Foren, eine Menge Möglichkeiten sich auszutauschen. Aber es fehlte noch etwas…

Anfang 2017 wurde die Interessengemein​schaft PHP e.V. (igphp) gegründet, eine gemeinnützige Organisation, ein Verein, dessen Aufgabe und Arbeit sich darum dreht, PHP weiter zu stärken, weiterzuentwickeln, die Akzeptanz zu steigern, und es in Forschung, Ausbildung und Wissenschaft zu verbreiten. Es sollen quelloffene Projekte unterstützt werden, die Vernetzung soll vorangetrieben werden in Forschung, Lehre, und Industrie. Hohe Ziele, für die es Mitstreiter braucht, Unterstüzung, Geld.

Seit Ende Juli 2018 ist igphp öffentlich, und nimmt Mitglieder auf. Seit dem 30.07.2018 bin ich Mitglied #000014, möchte helfen bei dem, was PHP weiter voran bringt, denn PHP ist zu großen Teilen mein Hobby und Beruf, und das soll auch gern so bleiben.

Da hier viele sind, die wie ich mit PHP ihre Brötchen verdienen, möchte ich dafür werben, sich die igphp anzuschauen, und sie im Idealfall tatkräftig zu unterstützen. Eine (Förder)Mitgliedschaft ist sowohl für Privatleute als auch Firmen möglich.

Ich würde mich sehr freuen, mit euch im Verein zusammenzuarbeiten.

Weitere Infos findet ihr hier:

https://igphp.de/

Written by Michael Kliewe

September 1st, 2018 at 10:50 pm

Posted in PHP

Tagged with ,

PHP, curl und TLS 1.2 als Minimum

with 2 comments

TLS 1.2 ist im Payment-Bereich weiter auf dem Vormarsch, immer mehr Zahlungsanbieter setzen TLS 1.2 als Minimumversion fest. Das Payment Card Industry Security Standards Council (PCI SSC) hat die Frist von 2016 auf 2018 verschoben. PayPal wird am 30. Juni 2018 TLS 1.0 und 1.1 abschalten. Paysafecard wird selbiges bereits im Februar 2018 tun.

Wer einen Zahlungsanbieter eingebunden hat, und deren API nutzt, sollte baldmöglichst prüfen ob seine Systeme TLS 1.2 beherrschen. Für halbwegs aktuelle Systeme sollte das gelten, Ubuntu 14.04 geht so gerade noch. Doch seht selbst.

Folgendes Script testet die TLS-Einstellungen von PHP (curl) mit Hilfe der Webseite https://www.howsmyssl.com:

<?php
$ch = curl_init('https://www.howsmyssl.com/a/check');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
curl_close($ch);

$json = json_decode($data);
var_dump($json);

Die Ergebnisse:

Weiterlesen »

Written by Michael Kliewe

Dezember 4th, 2017 at 11:43 pm

Posted in PHP,Server-Software