PHP Gangsta – Der PHP Blog mit Praxisbezug https://phpgangsta.de Ein PHP Blog mit Themen aller Art. Manchmal vergewaltige ich PHP... Mon, 04 Nov 2019 20:15:26 +0000 de hourly 1 https://wordpress.org/?v=6.8.3 PHP 7.4.0 RC 5: Selbst kompilieren und testen https://phpgangsta.de/php-7-4-0-rc-5-selbst-kompilieren-und-testen https://phpgangsta.de/php-7-4-0-rc-5-selbst-kompilieren-und-testen#comments Mon, 04 Nov 2019 20:15:25 +0000 https://www.phpgangsta.de/?p=6882 <p>Letzte Woche Donnerstag ist der <a href="https://wiki.php.net/todo/php74">nach Plan</a> fünfte Release-Candidate von PHP 7.4 erschienen: RC5. Es wird noch einen weiteren Release-Candidate geben, bevor hoffentlich am 28. November 2019 das finale PHP 7.4.0 GA erscheinen wird.</p> <p>Es ist also höchste Zeit, dem PHP-Team dabei zu helfen, Bugs zu finden. Eigentlich sollte man das schon früher getan haben, aber besser spät als nie!</p> <p>PHP 7.4 bringt einige interessante neue Features (Array Spread Operator, Typed Properties, Preloading, FFI, Improved Type Variance, Arrow Functions, …), aber auch wieder <a href="https://www.phoronix.com/scan.php?page=news_item&amp;px=PHP-7.4-RC1-Released">ein paar Prozent mehr Performance</a>. Eine komplette Liste aller neuen Funktionen, Änderungen, Deprecations, backwards-incompatible Changes etc. befindet sich in der <a href="https://github.com/php/php-src/blob/php-7.4.0RC5/UPGRADING">UPGRADING Datei</a>.</p> <h3 class="wp-block-heading">Selbst kompilieren</h3> <p>Um die PHP Tests durchlaufen zu lassen, kompilieren wir PHP 7.4 RC5 selbst. Natürlich kann das dann entstandene PHP auch genutzt werden, beispielsweise um die PHPUnit Tests seiner Projekte durchlaufen zu lassen, oder mal einen Test-Webserver zu konfigurieren (Apache, PHP-FPM).</p> <span id="more-6882"></span> <pre class="brush: bash; title: ; notranslate" title="">cd /tmp wget https://downloads.php.net/~derick/php-7.4.0RC5.tar.gz tar -xzvf php-7.4.0RC5.tar.gz cd php-7.4.0RC5/ ./configure --prefix=/usr/local/php7.4.0rc5 --with-zlib --with-config-file-path=/usr/local/php7.4.0rc5/etc --enable-mbstring --with-zip --with-imap --with-kerberos --with-imap-ssl --with-openssl --enable-gd --with-gettext --enable-ftp --with-pspell --with-curl make make test</pre> <p>Falls beim configure Fehler auftreten, guckt unten in der Liste am Ende dieses Artikels, da habe ich die aufgeschrieben, die bei mir aufgetreten sind. Es fehlten Developer-Pakete zum Kompilieren einiger Features und/oder Extensions.</p> <p>Im Gegensatz zu alten configure-Befehlen hat sich etwas geändert:</p> <pre class="wp-block-preformatted">früher: --enable-zip Seit 7.4: --with-zip früher: --with-gd Seit 7.4 --enable-gd</pre> <p></p> <p>Am Ende des &#8222;make test&#8220;-Durchlaufs der über 12.300 Tests erhaltet ihr das Ergebnis. Falls Fehler aufgetreten sind, könnt ihr den Fehlerbericht direkt an das QA-Team schicken indem ihr Y drückt und eure E-Mail-Adresse eingebt zwecks eventueller Rückfragen. Eine Liste aller fehlgeschlagenen Tests von allen Testern gibt es auf <a href="http://qa.php.net/reports/run_tests.php">qa.php.net</a>.</p> <p>Bei mir sind beispielsweise 3 Tests fehlgeschlagen:</p> <pre class="brush: plain; title: ; notranslate" title="">===================================================================== FAILED TEST SUMMARY --------------------------------------------------------------------- Bug #61948 (CURLOPT_COOKIEFILE '' raises open_basedir restriction) &#x5B;ext/curl/tests/bug61948-unix.phpt] Bug #41655 (open_basedir bypass via glob()) 1/2 &#x5B;ext/standard/tests/file/bug41655_1.phpt] Test glob() function: ensure no platform difference, variation 3 &#x5B;ext/standard/tests/file/glob_variation5.phpt] =====================================================================</pre> <p>Nach &#8222;make&#8220; bzw. &#8222;make test&#8220; kann PHP genutzt werden, beispielsweise kann man damit seine PHPUnit-Tests mal durchlaufen lassen.</p> <pre class="brush: plain; title: ; notranslate" title="">$ /tmp/php-7.4.0RC5/sapi/cli/php -v PHP 7.4.0RC5 (cli) (built: Nov 4 2019 20:58:52) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0-dev, Copyright (c) Zend Technologies</pre> <p>Um nach den ganzen Tests wieder aufzuräumen, kann der Ordner /tmp/php-7.4.0RC5/ einfach wieder gelöscht werden. Oder wenn man es länger behalten möchte, installiert man die PHP-Version nach /usr/local/php7.4.0rc5 (siehe prefix Parameter beim configure):</p> <pre class="brush: bash; title: ; notranslate" title="">sudo make install</pre> <p>Sollte man auf einem Testsystem machen, je nach Parametern (&#8211;with-apxs2) verändert/zerstört ihr eventuell euren laufenden Apache.</p> <p>Bis zum &#8222;make test&#8220; macht ihr auf jeden Fall nichts kaputt, und ihr könnt in Ruhe testen.</p> <p>Viel Spass beim Testen und Bugs melden!</p> <hr class="wp-block-separator"/> <h3 class="wp-block-heading">Mögliche Fehlermeldungen beim Kompilieren</h3> <p>Hier sind die Fehlermeldungen, die auf meinem Ubuntu 18.04 aufgetreten sind, inklusive der Lösungen:</p> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Package requirements (sqlite3 &gt; 3.7.4) were not met: No package 'sqlite3' found sudo apt-get install libsqlite3-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Package requirements (oniguruma) were not met: No package 'oniguruma' found sudo apt-get install libonig-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Package requirements (libpng) were not met: No package 'libpng' found sudo apt-get install libpng-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Package requirements (libzip &gt;= 0.11) were not met: No package 'libzip' found sudo apt-get install libzip-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: xml2-config not found. Please check your libxml2 installation. sudo apt-get install libxml2-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find OpenSSL's &lt;evp.h&gt; sudo apt-get install libssl-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">checking for cURL 7.15.5 or greater… configure: error: cURL version 7.15.5 or later is required to compile php with cURL support sudo apt-get install libcurl4-openssl-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find OpenSSL's libraries sudo apt-get install pkg-config</pre> <pre class="wp-block-preformatted">-------- </pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find zlib sudo apt-get install zlib1g-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">checking whether to enable JIS-mapped Japanese font support in GD… no If configure fails try --with-webp-dir=&lt;DIR&gt; configure: error: jpeglib.h not found. sudo apt-get install libjpeg-turbo8-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: png.h not found. sudo apt-get install libpng-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: freetype-config not found. sudo apt-get install libfreetype6-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: utf8_mime2text() has new signature, but U8T_CANONICAL is missing. This should not happen. Check config.log for additional information. sudo apt-get install libc-client2007e-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Kerberos libraries not found. Check the path given to --with-kerberos (if no path is given, searches in /usr/kerberos, /usr/local and /usr ) sudo apt-get install libkrb5-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find pspell sudo apt-get install libpspell-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Please reinstall the libzip distribution sudo apt-get install libzip-dev</pre> <p>Letzte Woche Donnerstag ist der <a href="https://wiki.php.net/todo/php74">nach Plan</a> fünfte Release-Candidate von PHP 7.4 erschienen: RC5. Es wird noch einen weiteren Release-Candidate geben, bevor hoffentlich am 28. November 2019 das finale PHP 7.4.0 GA erscheinen wird.</p> <p>Es ist also höchste Zeit, dem PHP-Team dabei zu helfen, Bugs zu finden. Eigentlich sollte man das schon früher getan haben, aber besser spät als nie!</p> <p>PHP 7.4 bringt einige interessante neue Features (Array Spread Operator, Typed Properties, Preloading, FFI, Improved Type Variance, Arrow Functions, …), aber auch wieder <a href="https://www.phoronix.com/scan.php?page=news_item&amp;px=PHP-7.4-RC1-Released">ein paar Prozent mehr Performance</a>. Eine komplette Liste aller neuen Funktionen, Änderungen, Deprecations, backwards-incompatible Changes etc. befindet sich in der <a href="https://github.com/php/php-src/blob/php-7.4.0RC5/UPGRADING">UPGRADING Datei</a>.</p> <h3 class="wp-block-heading">Selbst kompilieren</h3> <p>Um die PHP Tests durchlaufen zu lassen, kompilieren wir PHP 7.4 RC5 selbst. Natürlich kann das dann entstandene PHP auch genutzt werden, beispielsweise um die PHPUnit Tests seiner Projekte durchlaufen zu lassen, oder mal einen Test-Webserver zu konfigurieren (Apache, PHP-FPM).</p> <span id="more-6882"></span> <pre class="brush: bash; title: ; notranslate" title="">cd /tmp wget https://downloads.php.net/~derick/php-7.4.0RC5.tar.gz tar -xzvf php-7.4.0RC5.tar.gz cd php-7.4.0RC5/ ./configure --prefix=/usr/local/php7.4.0rc5 --with-zlib --with-config-file-path=/usr/local/php7.4.0rc5/etc --enable-mbstring --with-zip --with-imap --with-kerberos --with-imap-ssl --with-openssl --enable-gd --with-gettext --enable-ftp --with-pspell --with-curl make make test</pre> <p>Falls beim configure Fehler auftreten, guckt unten in der Liste am Ende dieses Artikels, da habe ich die aufgeschrieben, die bei mir aufgetreten sind. Es fehlten Developer-Pakete zum Kompilieren einiger Features und/oder Extensions.</p> <p>Im Gegensatz zu alten configure-Befehlen hat sich etwas geändert:</p> <pre class="wp-block-preformatted">früher: --enable-zip Seit 7.4: --with-zip früher: --with-gd Seit 7.4 --enable-gd</pre> <p></p> <p>Am Ende des &#8222;make test&#8220;-Durchlaufs der über 12.300 Tests erhaltet ihr das Ergebnis. Falls Fehler aufgetreten sind, könnt ihr den Fehlerbericht direkt an das QA-Team schicken indem ihr Y drückt und eure E-Mail-Adresse eingebt zwecks eventueller Rückfragen. Eine Liste aller fehlgeschlagenen Tests von allen Testern gibt es auf <a href="http://qa.php.net/reports/run_tests.php">qa.php.net</a>.</p> <p>Bei mir sind beispielsweise 3 Tests fehlgeschlagen:</p> <pre class="brush: plain; title: ; notranslate" title="">===================================================================== FAILED TEST SUMMARY --------------------------------------------------------------------- Bug #61948 (CURLOPT_COOKIEFILE '' raises open_basedir restriction) &#x5B;ext/curl/tests/bug61948-unix.phpt] Bug #41655 (open_basedir bypass via glob()) 1/2 &#x5B;ext/standard/tests/file/bug41655_1.phpt] Test glob() function: ensure no platform difference, variation 3 &#x5B;ext/standard/tests/file/glob_variation5.phpt] =====================================================================</pre> <p>Nach &#8222;make&#8220; bzw. &#8222;make test&#8220; kann PHP genutzt werden, beispielsweise kann man damit seine PHPUnit-Tests mal durchlaufen lassen.</p> <pre class="brush: plain; title: ; notranslate" title="">$ /tmp/php-7.4.0RC5/sapi/cli/php -v PHP 7.4.0RC5 (cli) (built: Nov 4 2019 20:58:52) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0-dev, Copyright (c) Zend Technologies</pre> <p>Um nach den ganzen Tests wieder aufzuräumen, kann der Ordner /tmp/php-7.4.0RC5/ einfach wieder gelöscht werden. Oder wenn man es länger behalten möchte, installiert man die PHP-Version nach /usr/local/php7.4.0rc5 (siehe prefix Parameter beim configure):</p> <pre class="brush: bash; title: ; notranslate" title="">sudo make install</pre> <p>Sollte man auf einem Testsystem machen, je nach Parametern (&#8211;with-apxs2) verändert/zerstört ihr eventuell euren laufenden Apache.</p> <p>Bis zum &#8222;make test&#8220; macht ihr auf jeden Fall nichts kaputt, und ihr könnt in Ruhe testen.</p> <p>Viel Spass beim Testen und Bugs melden!</p> <hr class="wp-block-separator"/> <h3 class="wp-block-heading">Mögliche Fehlermeldungen beim Kompilieren</h3> <p>Hier sind die Fehlermeldungen, die auf meinem Ubuntu 18.04 aufgetreten sind, inklusive der Lösungen:</p> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Package requirements (sqlite3 &gt; 3.7.4) were not met: No package 'sqlite3' found sudo apt-get install libsqlite3-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Package requirements (oniguruma) were not met: No package 'oniguruma' found sudo apt-get install libonig-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Package requirements (libpng) were not met: No package 'libpng' found sudo apt-get install libpng-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Package requirements (libzip &gt;= 0.11) were not met: No package 'libzip' found sudo apt-get install libzip-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: xml2-config not found. Please check your libxml2 installation. sudo apt-get install libxml2-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find OpenSSL's &lt;evp.h&gt; sudo apt-get install libssl-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">checking for cURL 7.15.5 or greater… configure: error: cURL version 7.15.5 or later is required to compile php with cURL support sudo apt-get install libcurl4-openssl-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find OpenSSL's libraries sudo apt-get install pkg-config</pre> <pre class="wp-block-preformatted">-------- </pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find zlib sudo apt-get install zlib1g-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">checking whether to enable JIS-mapped Japanese font support in GD… no If configure fails try --with-webp-dir=&lt;DIR&gt; configure: error: jpeglib.h not found. sudo apt-get install libjpeg-turbo8-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: png.h not found. sudo apt-get install libpng-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: freetype-config not found. sudo apt-get install libfreetype6-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: utf8_mime2text() has new signature, but U8T_CANONICAL is missing. This should not happen. Check config.log for additional information. sudo apt-get install libc-client2007e-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Kerberos libraries not found. Check the path given to --with-kerberos (if no path is given, searches in /usr/kerberos, /usr/local and /usr ) sudo apt-get install libkrb5-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find pspell sudo apt-get install libpspell-dev</pre> <pre class="wp-block-preformatted">--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Please reinstall the libzip distribution sudo apt-get install libzip-dev</pre> https://phpgangsta.de/php-7-4-0-rc-5-selbst-kompilieren-und-testen/feed 2 Applikationen migrieren von PHP 5.6 auf PHP 7.3 https://phpgangsta.de/applikationen-migirieren-von-php-5-6-auf-php-7-3 https://phpgangsta.de/applikationen-migirieren-von-php-5-6-auf-php-7-3#comments Thu, 19 Sep 2019 21:56:45 +0000 https://www.phpgangsta.de/?p=6741 <p>PHP 7.0 ist nun schon über drei Jahre verfügbar, 7.3 ist auch schon wieder 9 Monate alt. PHP 7.4 wird Ende diesen Jahres erscheinen.</p> <p>In den letzten 2 Jahren habe ich mehrere Projekte von PHP 5.6 auf eine 7er Version bringen dürfen. Zwei davon waren etwas größer, von denen möchte ich hier berichten.</p> <p>Ich hatte in einem Artikel &#8222;<a href="https://www.phpgangsta.de/php-7-migration-eines-projekts">PHP 7: Migration eines Projekts</a>&#8222;, der kurz vor dem Release von PHP 7.0 erschien, schon einige kleine Tipps gegeben wie man einen Überblick bekommen kann über die zu bearbeitenden Baustellen. Heute soll es etwas mehr ins Eingemachte gehen.</p> <p>Die 2 Projekte haben jeweils über 100.000 Zeilen &#8222;eigenen Code&#8220;, also ohne externe Libraries, so dass ich sie als &#8222;groß&#8220; bezeichnen möchte. Das eine Projekt wurde zu Zeiten von PHP 5.3 gestartet und entwickelt, hat in den letzten 9 Jahren auch einiges an Pflege und Aktualisierungen erfahren. Externe Bibliotheken wurden ab und zu erneuert, es wurde teils auf Composer umgestellt, und hat auch in den letzten Jahren das ein oder andere PHP 5.4, 5.5 und 5.6 Feature erhalten.<br>Das andere Projekt ist etwas älter und stammt aus dem Jahr 2009, d.h. PHP 5.2 war damals aktuell, und es wurde noch kompatibel zu PHP 4 erstellt, da noch nicht alle Welt PHP 5 nutzte. Außerdem hat das Projekt seitdem kaum Aktualisierungen bekommen, quasi alles stammt noch aus der damaligen Zeit, ihr werdet später hier im Artikel sehen was ich damit meinen könnte 🙂</p> <h3 class="wp-block-heading">PHPStorm &#8222;Deprecated&#8220;-Inspection</h3> <p>Also gut, zuerst wollte ich mir jeweils einen Überblick verschaffen, und haben diverse Analyse-Tools über die Projekte laufen lassen. Als erstes ließ ich die &#8222;Deprecated&#8220;-Inspection von PHPStorm laufen. Dazu habe ich die genutzte PHP-Version auf 7.3 gestellt, und danach mittels Code-&gt;&#8220;Run inspection by name&#8220;-&gt;&#8220;Deprecated&#8220; laufen lassen. Im ersten Projekt waren es nur 14 Einträge, recht übersichtlich und schnell zu beheben.<br>Im zweiten Projekt jedoch wurden 79 Probleme erkannt. Die häufigsten waren:</p> <span id="more-6741"></span> <ul class="wp-block-list"><li>Function &#8222;ereg&#8220; is deprecated</li><li>Function &#8222;eregi&#8220; is deprecated</li><li>Function &#8222;ereg_replace&#8220; is deprecated</li><li>Function &#8222;eregi_replace&#8220; is deprecated</li><li>Function &#8222;split&#8220; is deprecated</li><li>Function &#8222;set_socket_blocking&#8220; is deprecated</li><li>Function &#8222;set_magic_quotes_runtime&#8220; is deprecated</li><li>Function &#8222;mysql_*&#8220; is deprecated</li></ul> <h3 class="wp-block-heading">ereg(), eregi(), ereg_replace(), eregi_replace()</h3> <p><a href="http://php.net/manual/en/function.ereg.php">ereg()</a> ist leicht zu ersetzen durch <a href="http://php.net/preg_match">preg_match()</a>, der Name der Funktion muss geändert werden, und dem Pattern fügt man Begrenzungszeichen (Delimiter) hinzu (meistens /, | oder #).<br>Aus</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">ereg('&#x5B;a-z]', $string)</pre></pre> <p>wird also</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">preg_match('/&#x5B;a-z]/', $string)</pre></pre> <p><a href="http://php.net/manual/en/function.eregi.php">eregi()</a> wird ebenfalls durch <a href="http://php.net/manual/en/function.preg-match.php">preg_match()</a> ersetzt, Begrenzungszeichen hinzugefügt, und hinter dem hinteren Begrenzungszeichen der <a href="http://php.net/manual/en/reference.pcre.pattern.modifiers.php">Modifikator</a> i eingesetzt.</p> <p>Aus</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">eregi('&#x5B;a-z]', $string)</pre></pre> <p>wird also</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">preg_match('/&#x5B;a-z]/i', $string)</pre></pre> <p>Selbiges gilt für <a href="http://php.net/manual/en/function.ereg-replace.php">ereg_replace()</a> und <a href="http://php.net/manual/en/function.eregi-replace.php">eregi_replace()</a>.</p> <h3 class="wp-block-heading">split(), set_socket_blocking(), set_magic_quotes_runtime()</h3> <p><a href="http://php.net/manual/en/function.split.php">split()</a> kann durch <a href="http://php.net/manual/en/function.explode.php">explode()</a> ersetzt werden wenn kein Regex im Suchbegriff enthalten ist, sondern nur &#8222;normale Strings&#8220; (Literals). Ansonsten muss <a href="http://php.net/manual/en/function.preg-split.php">preg_split()</a> genutzt werden.</p> <p><a href="http://php.net/manual/en/function.set-socket-blocking.php">set_socket_blocking()</a> kann in den meisten (oder gar allen?) Fällen durch <a href="http://php.net/manual/en/function.stream-set-blocking.php">stream_set_blocking()</a> ersetzt werden.</p> <p><a href="http://php.net/manual/en/function.set-magic-quotes-runtime.php">set_magic_quotes_runtime()</a> war im Code dankenswerterweise eh an allen Stellen bereits in einem if-Konstrukt verschachtelt, so dass set_magic_quotes_runtime() seit PHP 5.4 nie aufgerufen wurde:</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">if (get_magic_quotes_runtime()) { @set_magic_quotes_runtime(0); }</pre></pre> <p>Seit PHP 5.3 ist set_magic_quotes_runtime() deprecated, in PHP 7.0 wurde es entfernt.<br>Seit PHP 5.4 liefert <a href="http://php.net/manual/en/function.get-magic-quotes-runtime.php">get_magic_quotes_runtime()</a> immer FALSE, und ist bis 7.3 immer noch verfügbar.</p> <h3 class="wp-block-heading">mysql_* Funktionen</h3> <p>Hier gilt es, eine Langzeitbaustelle endlich zu beackern. Im &#8222;moderneren&#8220; Projekt haben wir das die letzten Jahre kontinuierlich erledigt, und alles auf PDO umgestellt, bzw. neue Scripte immer direkt mit PDO geschrieben. Hier gab es nichts zu tun.</p> <p>Im zweiten, älteren Projekt war dankenswerterweise die Wahl zwischen mysql_* und mysqli_* bereits vorhanden, man konnte es einfach per Konfiguration umschalten (es wurde dann die Datenbank-Abstraktionsklasse &#8222;project_mysqli extends project_database&#8220; statt &#8222;project_mysql extends project_database&#8220; genutzt). ABER: Beim Durchgehen fiel auf, dass der ursprüngliche Entwickler nicht an allen Stellen mysql_* und mysqli_* variabel programmiert hatte, denn an einigen wenigen Stellen wurde noch</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">return mysql_result($res, 0, &quot;col&quot;);</pre></pre> <p>im Code genutzt. Wenn mysqli genutzt wird, nutze ich nun:</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">return mysqli_fetch_array($res, MYSQLI_ASSOC)&#x5B;'col'];</pre></pre> <h3 class="wp-block-heading">php7mar</h3> <p>Nachdem diese ersten Schritte gemacht sind, und alle Deprecated-Meldungen aus PHPStorm berichtigt wurden, ließ ich <a href="https://github.com/Alexia/php7mar">php7mar</a> nochmal laufen. Dort wurden mir dann &#8222;nur noch&#8220; folgende Probleme angezeigt:</p> <ul class="wp-block-list"><li>oldClassConstructors</li><li>funcGetArg</li><li>variableInterpolation</li></ul> <h3 class="wp-block-heading">PHP4-Style Konstruktoren</h3> <p>Ersteres sind Überbleibsel aus der PHP4 Zeit, da das alte Projekt vermutlich zu PHP4-Zeiten begonnen wurde, oder zumindest noch kompatibel und mit alten PHP4-Versionen lauffähig sein sollte.</p> <p>Diese alten Konstruktoren sind schnell ersetzt durch die modernen __construct() Konstruktoren, jedoch gibt es dabei ein Problem, bzw. eine Sache, auf die geachtet werden sollte:</p> <p>Die alten Konstruktor-Funktionen könnten explizit aufgerufen werden in Kindklassen.&nbsp; Beispielsweise gibt es eine Vaterklasse &#8222;database&#8220; und eine Kindklasse &#8222;mysql&#8220;, die folgendermaßen aussehen:</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">class database { function database() { } } class mysql extends database { .... function do() { $this-&gt;database(); } }</pre></pre> <p>Nun gibt es 2 Möglichkeiten:<br>1. Einfach den Namen aller Konstruktoren ändern auf __construct(), und danach im ganzen Projekt suchen nach expliziten Aufrufen der alten Methode &#8222;database()&#8220;. Diese werden dann auch durch parent::__construct() ersetzt.<br>2. Man lässt die alte Methode der Vaterklasse bestehen, und fügt zusätzlich noch einen neuen Konstruktor __construct() hinzu. In diesem Fall müsste man nur die Vaterklasse &#8222;database&#8220; ändern, und die Kindklasse &#8222;mysql&#8220; könnte so belassen werden wie sie ist, denn die alte Methode &#8222;database()&#8220; gibt es nach wie vor, und sie funktioniert.</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">class database { function __construct() { // neu hinzugefügt, VOR dem alten PHP4-Style Konstruktor } function database() { $this-&gt;__construct(); } }</pre></pre> <p>Für welche der beiden Möglichkeiten man sich entscheidet, hängt vielleicht auch von der Anzahl an Kindklassen ab. Oder falls es eine öffentlich verfügbare und von fremden Leuten genutzte Bibliothek ist, sollte man vielleicht auch die zweite Methode wählen, so dass bestehender Fremdcode (Kindklassen) weiterhin ohne Änderungen funktionieren.</p> <h3 class="wp-block-heading">func_get_arg() + variableInterpolation</h3> <p>Zu <a href="http://php.net/manual/en/function.func-get-arg.php">func_get_arg()</a> hatte ich bereits etwas geschrieben. Man kann schnell prüfen ob die Verhaltensänderung eintritt oder nicht, in den aller meisten Fällen kann man es so lassen wie es ist.</p> <p>Eine der gefährlichsten Änderungen an PHP 7.0 ist die Änderung der <a href="https://www.phpgangsta.de/php-7-migration-eines-projekts">Uniform Variablen Syntax</a>. Darüber hatte ich im letzten Artikel bereits ausführlich geschrieben. Da es keine Warnungen, Deprecation-Meldungen, oder &#8222;undefined function&#8220;-Errors gibt, sondern der Bug evtl. unsichtbar ausgeführt wird, finde ich ihn gefährlich.<br>Dankenwerterweise gibt php7mar einige mögliche Stellen aus, die man sich angucken sollte. Es sind evtl. auch einige Falschmeldungen dabei, aber auch welche, bei denen man aktiv werden muss.</p> <h3 class="wp-block-heading">Zwischenfazit</h3> <p>Nachdem nun all diese Fehler berichtigt wurden, sind die meisten Fehler verschwunden, das Error-Log bleibt leer, und die Webseiten und Scripte funktionieren. Aber fertig sind wir noch nicht, denn die bisherigen Tools haben noch nicht alles gefunden. Ich habe ein drittes Tool genutzt, um die beiden Projekte zu analysieren und mir weitere PHP 7.x Probleme anzeigen zu lassen.</p> <h3 class="wp-block-heading">Exakat</h3> <p>PHP 7.0 ist nun schon über drei Jahre verfügbar, 7.3 ist auch schon wieder 9 Monate alt. PHP 7.4 wird Ende diesen Jahres erscheinen.</p> <p>In den letzten 2 Jahren habe ich mehrere Projekte von PHP 5.6 auf eine 7er Version bringen dürfen. Zwei davon waren etwas größer, von denen möchte ich hier berichten.</p> <p>Ich hatte in einem Artikel &#8222;<a href="https://www.phpgangsta.de/php-7-migration-eines-projekts">PHP 7: Migration eines Projekts</a>&#8222;, der kurz vor dem Release von PHP 7.0 erschien, schon einige kleine Tipps gegeben wie man einen Überblick bekommen kann über die zu bearbeitenden Baustellen. Heute soll es etwas mehr ins Eingemachte gehen.</p> <p>Die 2 Projekte haben jeweils über 100.000 Zeilen &#8222;eigenen Code&#8220;, also ohne externe Libraries, so dass ich sie als &#8222;groß&#8220; bezeichnen möchte. Das eine Projekt wurde zu Zeiten von PHP 5.3 gestartet und entwickelt, hat in den letzten 9 Jahren auch einiges an Pflege und Aktualisierungen erfahren. Externe Bibliotheken wurden ab und zu erneuert, es wurde teils auf Composer umgestellt, und hat auch in den letzten Jahren das ein oder andere PHP 5.4, 5.5 und 5.6 Feature erhalten.<br>Das andere Projekt ist etwas älter und stammt aus dem Jahr 2009, d.h. PHP 5.2 war damals aktuell, und es wurde noch kompatibel zu PHP 4 erstellt, da noch nicht alle Welt PHP 5 nutzte. Außerdem hat das Projekt seitdem kaum Aktualisierungen bekommen, quasi alles stammt noch aus der damaligen Zeit, ihr werdet später hier im Artikel sehen was ich damit meinen könnte 🙂</p> <h3 class="wp-block-heading">PHPStorm &#8222;Deprecated&#8220;-Inspection</h3> <p>Also gut, zuerst wollte ich mir jeweils einen Überblick verschaffen, und haben diverse Analyse-Tools über die Projekte laufen lassen. Als erstes ließ ich die &#8222;Deprecated&#8220;-Inspection von PHPStorm laufen. Dazu habe ich die genutzte PHP-Version auf 7.3 gestellt, und danach mittels Code-&gt;&#8220;Run inspection by name&#8220;-&gt;&#8220;Deprecated&#8220; laufen lassen. Im ersten Projekt waren es nur 14 Einträge, recht übersichtlich und schnell zu beheben.<br>Im zweiten Projekt jedoch wurden 79 Probleme erkannt. Die häufigsten waren:</p> <span id="more-6741"></span> <ul class="wp-block-list"><li>Function &#8222;ereg&#8220; is deprecated</li><li>Function &#8222;eregi&#8220; is deprecated</li><li>Function &#8222;ereg_replace&#8220; is deprecated</li><li>Function &#8222;eregi_replace&#8220; is deprecated</li><li>Function &#8222;split&#8220; is deprecated</li><li>Function &#8222;set_socket_blocking&#8220; is deprecated</li><li>Function &#8222;set_magic_quotes_runtime&#8220; is deprecated</li><li>Function &#8222;mysql_*&#8220; is deprecated</li></ul> <h3 class="wp-block-heading">ereg(), eregi(), ereg_replace(), eregi_replace()</h3> <p><a href="http://php.net/manual/en/function.ereg.php">ereg()</a> ist leicht zu ersetzen durch <a href="http://php.net/preg_match">preg_match()</a>, der Name der Funktion muss geändert werden, und dem Pattern fügt man Begrenzungszeichen (Delimiter) hinzu (meistens /, | oder #).<br>Aus</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">ereg('&#x5B;a-z]', $string)</pre></pre> <p>wird also</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">preg_match('/&#x5B;a-z]/', $string)</pre></pre> <p><a href="http://php.net/manual/en/function.eregi.php">eregi()</a> wird ebenfalls durch <a href="http://php.net/manual/en/function.preg-match.php">preg_match()</a> ersetzt, Begrenzungszeichen hinzugefügt, und hinter dem hinteren Begrenzungszeichen der <a href="http://php.net/manual/en/reference.pcre.pattern.modifiers.php">Modifikator</a> i eingesetzt.</p> <p>Aus</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">eregi('&#x5B;a-z]', $string)</pre></pre> <p>wird also</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">preg_match('/&#x5B;a-z]/i', $string)</pre></pre> <p>Selbiges gilt für <a href="http://php.net/manual/en/function.ereg-replace.php">ereg_replace()</a> und <a href="http://php.net/manual/en/function.eregi-replace.php">eregi_replace()</a>.</p> <h3 class="wp-block-heading">split(), set_socket_blocking(), set_magic_quotes_runtime()</h3> <p><a href="http://php.net/manual/en/function.split.php">split()</a> kann durch <a href="http://php.net/manual/en/function.explode.php">explode()</a> ersetzt werden wenn kein Regex im Suchbegriff enthalten ist, sondern nur &#8222;normale Strings&#8220; (Literals). Ansonsten muss <a href="http://php.net/manual/en/function.preg-split.php">preg_split()</a> genutzt werden.</p> <p><a href="http://php.net/manual/en/function.set-socket-blocking.php">set_socket_blocking()</a> kann in den meisten (oder gar allen?) Fällen durch <a href="http://php.net/manual/en/function.stream-set-blocking.php">stream_set_blocking()</a> ersetzt werden.</p> <p><a href="http://php.net/manual/en/function.set-magic-quotes-runtime.php">set_magic_quotes_runtime()</a> war im Code dankenswerterweise eh an allen Stellen bereits in einem if-Konstrukt verschachtelt, so dass set_magic_quotes_runtime() seit PHP 5.4 nie aufgerufen wurde:</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">if (get_magic_quotes_runtime()) { @set_magic_quotes_runtime(0); }</pre></pre> <p>Seit PHP 5.3 ist set_magic_quotes_runtime() deprecated, in PHP 7.0 wurde es entfernt.<br>Seit PHP 5.4 liefert <a href="http://php.net/manual/en/function.get-magic-quotes-runtime.php">get_magic_quotes_runtime()</a> immer FALSE, und ist bis 7.3 immer noch verfügbar.</p> <h3 class="wp-block-heading">mysql_* Funktionen</h3> <p>Hier gilt es, eine Langzeitbaustelle endlich zu beackern. Im &#8222;moderneren&#8220; Projekt haben wir das die letzten Jahre kontinuierlich erledigt, und alles auf PDO umgestellt, bzw. neue Scripte immer direkt mit PDO geschrieben. Hier gab es nichts zu tun.</p> <p>Im zweiten, älteren Projekt war dankenswerterweise die Wahl zwischen mysql_* und mysqli_* bereits vorhanden, man konnte es einfach per Konfiguration umschalten (es wurde dann die Datenbank-Abstraktionsklasse &#8222;project_mysqli extends project_database&#8220; statt &#8222;project_mysql extends project_database&#8220; genutzt). ABER: Beim Durchgehen fiel auf, dass der ursprüngliche Entwickler nicht an allen Stellen mysql_* und mysqli_* variabel programmiert hatte, denn an einigen wenigen Stellen wurde noch</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">return mysql_result($res, 0, &quot;col&quot;);</pre></pre> <p>im Code genutzt. Wenn mysqli genutzt wird, nutze ich nun:</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">return mysqli_fetch_array($res, MYSQLI_ASSOC)&#x5B;'col'];</pre></pre> <h3 class="wp-block-heading">php7mar</h3> <p>Nachdem diese ersten Schritte gemacht sind, und alle Deprecated-Meldungen aus PHPStorm berichtigt wurden, ließ ich <a href="https://github.com/Alexia/php7mar">php7mar</a> nochmal laufen. Dort wurden mir dann &#8222;nur noch&#8220; folgende Probleme angezeigt:</p> <ul class="wp-block-list"><li>oldClassConstructors</li><li>funcGetArg</li><li>variableInterpolation</li></ul> <h3 class="wp-block-heading">PHP4-Style Konstruktoren</h3> <p>Ersteres sind Überbleibsel aus der PHP4 Zeit, da das alte Projekt vermutlich zu PHP4-Zeiten begonnen wurde, oder zumindest noch kompatibel und mit alten PHP4-Versionen lauffähig sein sollte.</p> <p>Diese alten Konstruktoren sind schnell ersetzt durch die modernen __construct() Konstruktoren, jedoch gibt es dabei ein Problem, bzw. eine Sache, auf die geachtet werden sollte:</p> <p>Die alten Konstruktor-Funktionen könnten explizit aufgerufen werden in Kindklassen.&nbsp; Beispielsweise gibt es eine Vaterklasse &#8222;database&#8220; und eine Kindklasse &#8222;mysql&#8220;, die folgendermaßen aussehen:</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">class database { function database() { } } class mysql extends database { .... function do() { $this-&gt;database(); } }</pre></pre> <p>Nun gibt es 2 Möglichkeiten:<br>1. Einfach den Namen aller Konstruktoren ändern auf __construct(), und danach im ganzen Projekt suchen nach expliziten Aufrufen der alten Methode &#8222;database()&#8220;. Diese werden dann auch durch parent::__construct() ersetzt.<br>2. Man lässt die alte Methode der Vaterklasse bestehen, und fügt zusätzlich noch einen neuen Konstruktor __construct() hinzu. In diesem Fall müsste man nur die Vaterklasse &#8222;database&#8220; ändern, und die Kindklasse &#8222;mysql&#8220; könnte so belassen werden wie sie ist, denn die alte Methode &#8222;database()&#8220; gibt es nach wie vor, und sie funktioniert.</p> <pre class="wp-block-preformatted"><pre class="brush: plain; title: ; notranslate" title="">class database { function __construct() { // neu hinzugefügt, VOR dem alten PHP4-Style Konstruktor } function database() { $this-&gt;__construct(); } }</pre></pre> <p>Für welche der beiden Möglichkeiten man sich entscheidet, hängt vielleicht auch von der Anzahl an Kindklassen ab. Oder falls es eine öffentlich verfügbare und von fremden Leuten genutzte Bibliothek ist, sollte man vielleicht auch die zweite Methode wählen, so dass bestehender Fremdcode (Kindklassen) weiterhin ohne Änderungen funktionieren.</p> <h3 class="wp-block-heading">func_get_arg() + variableInterpolation</h3> <p>Zu <a href="http://php.net/manual/en/function.func-get-arg.php">func_get_arg()</a> hatte ich bereits etwas geschrieben. Man kann schnell prüfen ob die Verhaltensänderung eintritt oder nicht, in den aller meisten Fällen kann man es so lassen wie es ist.</p> <p>Eine der gefährlichsten Änderungen an PHP 7.0 ist die Änderung der <a href="https://www.phpgangsta.de/php-7-migration-eines-projekts">Uniform Variablen Syntax</a>. Darüber hatte ich im letzten Artikel bereits ausführlich geschrieben. Da es keine Warnungen, Deprecation-Meldungen, oder &#8222;undefined function&#8220;-Errors gibt, sondern der Bug evtl. unsichtbar ausgeführt wird, finde ich ihn gefährlich.<br>Dankenwerterweise gibt php7mar einige mögliche Stellen aus, die man sich angucken sollte. Es sind evtl. auch einige Falschmeldungen dabei, aber auch welche, bei denen man aktiv werden muss.</p> <h3 class="wp-block-heading">Zwischenfazit</h3> <p>Nachdem nun all diese Fehler berichtigt wurden, sind die meisten Fehler verschwunden, das Error-Log bleibt leer, und die Webseiten und Scripte funktionieren. Aber fertig sind wir noch nicht, denn die bisherigen Tools haben noch nicht alles gefunden. Ich habe ein drittes Tool genutzt, um die beiden Projekte zu analysieren und mir weitere PHP 7.x Probleme anzeigen zu lassen.</p> <h3 class="wp-block-heading">Exakat</h3> https://phpgangsta.de/applikationen-migirieren-von-php-5-6-auf-php-7-3/feed 1 PHP 7.3.0 RC 4: Performanceboost und bitte testen! https://phpgangsta.de/php-7-3-0-rc-4-performanceboost-und-bitte-testen https://phpgangsta.de/php-7-3-0-rc-4-performanceboost-und-bitte-testen#comments Sat, 27 Oct 2018 20:23:43 +0000 https://www.phpgangsta.de/?p=6849 <p>Vor 3 Tagen ist der <a href="https://wiki.php.net/todo/php73">nach Plan</a> drittletzte Release-Candidate von PHP 7.3 erschienen: RC4. Es wird noch einen RC5 und RC6 geben, bevor hoffentlich pünktlich zu Nikolaus am 06.12.2018 das finale PHP 7.3.0 GA erscheinen wird.</p> <p>Es ist also höchste Zeit, dem PHP-Team dabei zu helfen, Bugs zu finden. Eigentlich sollte man das schon früher getan haben, aber besser spät als nie!</p> <p>PHP 7.3 bringt <a href="https://github.com/php/php-src/pull/3165#pullrequestreview-100399813">erstaunliche Performanceverbesserungen im Bereich des Garbage-Collectors</a>. Früher konnte man einiges an Performance gewinnen, indem man stellenweise den Garbage-Collector deaktiviert. Vor allem wenn mit vielen Objekten gearbeitet wird, hat das Deaktivieren einiges an Performance gebracht (teilweise &gt;70%, siehe <a href="https://github.com/dompdf/dompdf/issues/1813#issuecomment-429228260">DomPDF</a> oder <a href="https://blog.blackfire.io/performance-impact-of-the-php-garbage-collector.html">Composer</a>). Mit PHP 7.3 ist das nicht mehr nötig, man bekommt die Performanceverbesserungen frei Haus, man muss den GC nicht mehr deaktivieren. Gratis Performanceboost ohne eine Zeile Code zu ändern!</p> <h3>Selbst kompilieren</h3> <p>Also los, wir kompilieren PHP 7.3.0 RC4 selbst, in diesem Fall auf einem Ubuntu 18.04 Server. Damit es nicht langweilig wird, nehmen wir diverse Extensions mit dazu, ihr nehmt am besten eure, die ihr so braucht für eure Applikationen.<span id="more-6849"></span></p> <pre class="brush: bash; title: ; notranslate" title="">cd /tmp wget https://downloads.php.net/~cmb/php-7.3.0RC4.tar.gz tar -xzvf php-7.3.0RC4.tar.gz cd php-7.3.0RC4/ ./configure --prefix=/usr/local/php7.3.0RC4 --with-zlib --with-config-file-path=/usr/local/php7.3.0RC4/etc --enable-mbstring --enable-zip --with-imap --with-kerberos --with-imap-ssl --with-openssl --with-jpeg-dir --with-gd --with-gettext --with-freetype-dir --enable-ftp --with-pspell --with-curl make make test</pre> <p>Falls beim configure Fehler auftreten, guckt unten in der Liste am Ende dieses Artikels, da habe ich die aufgeschrieben, die bei mir aufgetreten sind. In allen Fällen fehlten Developer-Pakete zum Kompilieren einiger Extensions.</p> <p>Am Ende des &#8222;make test&#8220;-Durchlaufs der über 13.000 Tests erhaltet ihr das Ergebnis. Falls Fehler aufgetreten sind, könnt ihr den Fehlerbericht direkt an das QA-Team schicken indem ihr Y drückt und eure E-Mail-Adresse eingebt zwecks eventueller Rückfragen. Eine Liste aller fehlgeschlagenen Tests von allen Testern gibt es auf <a href="http://qa.php.net/reports/run_tests.php">qa.php.net</a>.</p> <p>Bei mir sind beispielsweise 6 Tests fehlgeschlagen:</p> <pre class="brush: plain; title: ; notranslate" title="">FAILED TEST SUMMARY --------------------------------------------------------------------- Bug #61948 (CURLOPT_COOKIEFILE '' raises open_basedir restriction) &#x5B;ext/curl/tests/bug61948.phpt] Bug #72333: fwrite() on non-blocking SSL sockets doesn't work &#x5B;ext/openssl/tests/bug72333.phpt] Bug #41655 (open_basedir bypass via glob()) 1/2 &#x5B;ext/standard/tests/file/bug41655_1.phpt] Test glob() function: ensure no platform difference, variation 3 &#x5B;ext/standard/tests/file/glob_variation5.phpt] int stream_socket_sendto ( resource $socket , string $data &#x5B;, int $flags = 0 &#x5B;, string $address ]] ); &#x5B;ext/standard/tests/streams/stream_socket_sendto.phpt] file upload greater than 2G &#x5B;sapi/cli/tests/upload_2G.phpt]</pre> <p>Nach &#8222;make&#8220; kann PHP genutzt werden, beispielsweise kann man damit seine PHPUnit-Tests mal durchlaufen lassen.</p> <pre class="brush: plain; title: ; notranslate" title="">$ /tmp/php-7.3.0RC4/sapi/cli/php -v PHP 7.3.0RC4 (cli) (built: Oct 27 2018 19:15:31) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.3.0-dev, Copyright (c) 1998-2018 Zend Technologies</pre> <p>Um nach den ganzen Tests wieder aufzuräumen, kann der Ordner /tmp/php-7.3.0RC4/ einfach wieder gelöscht werden. Oder wenn man es länger behalten möchte, installiert man die PHP-Version nach /usr/local/php7.3.0RC4 (siehe prefix Parameter beim configure):</p> <pre class="brush: bash; title: ; notranslate" title="">sudo make install</pre> <p>Sollte man auf einem Testsystem machen, je nach Parametern (&#8211;with-apxs2) verändert/zerstört ihr eventuell euren laufenden Apache.</p> <p>Bis zum &#8222;make test&#8220; macht ihr auf jeden Fall nichts kaputt, und ihr könnt in Ruhe testen.</p> <p>Viel Spass beim Testen, und beim Messen der Performanceboosts eurer Applikationen! 🙂</p> <hr /> <h3>Mögliche Fehlermeldungen beim Kompilieren</h3> <p>Hier sind die Fehlermeldungen, die auf meinem Ubuntu 18.04 aufgetreten sind, inklusive der Lösungen:</p> <pre class="brush: bash; title: ; notranslate" title="">configure: error: xml2-config not found. Please check your libxml2 installation. sudo apt-get install libxml2-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find OpenSSL's &lt;evp.h&gt; sudo apt-get install libssl-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">checking for cURL 7.15.5 or greater... configure: error: cURL version 7.15.5 or later is required to compile php with cURL support sudo apt-get install libcurl4-openssl-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find OpenSSL's libraries sudo apt-get install pkg-config</pre> <pre>-------- </pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find zlib sudo apt-get install zlib1g-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">checking whether to enable JIS-mapped Japanese font support in GD... no If configure fails try --with-webp-dir=&lt;DIR&gt; configure: error: jpeglib.h not found. sudo apt-get install libjpeg-turbo8-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: png.h not found. sudo apt-get install libpng-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: freetype-config not found. sudo apt-get install libfreetype6-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: utf8_mime2text() has new signature, but U8T_CANONICAL is missing. This should not happen. Check config.log for additional information. sudo apt-get install libc-client2007e-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Kerberos libraries not found. Check the path given to --with-kerberos (if no path is given, searches in /usr/kerberos, /usr/local and /usr ) sudo apt-get install libkrb5-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find pspell sudo apt-get install libpspell-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Please reinstall the libzip distribution sudo apt-get install libzip-dev</pre> <p>Vor 3 Tagen ist der <a href="https://wiki.php.net/todo/php73">nach Plan</a> drittletzte Release-Candidate von PHP 7.3 erschienen: RC4. Es wird noch einen RC5 und RC6 geben, bevor hoffentlich pünktlich zu Nikolaus am 06.12.2018 das finale PHP 7.3.0 GA erscheinen wird.</p> <p>Es ist also höchste Zeit, dem PHP-Team dabei zu helfen, Bugs zu finden. Eigentlich sollte man das schon früher getan haben, aber besser spät als nie!</p> <p>PHP 7.3 bringt <a href="https://github.com/php/php-src/pull/3165#pullrequestreview-100399813">erstaunliche Performanceverbesserungen im Bereich des Garbage-Collectors</a>. Früher konnte man einiges an Performance gewinnen, indem man stellenweise den Garbage-Collector deaktiviert. Vor allem wenn mit vielen Objekten gearbeitet wird, hat das Deaktivieren einiges an Performance gebracht (teilweise &gt;70%, siehe <a href="https://github.com/dompdf/dompdf/issues/1813#issuecomment-429228260">DomPDF</a> oder <a href="https://blog.blackfire.io/performance-impact-of-the-php-garbage-collector.html">Composer</a>). Mit PHP 7.3 ist das nicht mehr nötig, man bekommt die Performanceverbesserungen frei Haus, man muss den GC nicht mehr deaktivieren. Gratis Performanceboost ohne eine Zeile Code zu ändern!</p> <h3>Selbst kompilieren</h3> <p>Also los, wir kompilieren PHP 7.3.0 RC4 selbst, in diesem Fall auf einem Ubuntu 18.04 Server. Damit es nicht langweilig wird, nehmen wir diverse Extensions mit dazu, ihr nehmt am besten eure, die ihr so braucht für eure Applikationen.<span id="more-6849"></span></p> <pre class="brush: bash; title: ; notranslate" title="">cd /tmp wget https://downloads.php.net/~cmb/php-7.3.0RC4.tar.gz tar -xzvf php-7.3.0RC4.tar.gz cd php-7.3.0RC4/ ./configure --prefix=/usr/local/php7.3.0RC4 --with-zlib --with-config-file-path=/usr/local/php7.3.0RC4/etc --enable-mbstring --enable-zip --with-imap --with-kerberos --with-imap-ssl --with-openssl --with-jpeg-dir --with-gd --with-gettext --with-freetype-dir --enable-ftp --with-pspell --with-curl make make test</pre> <p>Falls beim configure Fehler auftreten, guckt unten in der Liste am Ende dieses Artikels, da habe ich die aufgeschrieben, die bei mir aufgetreten sind. In allen Fällen fehlten Developer-Pakete zum Kompilieren einiger Extensions.</p> <p>Am Ende des &#8222;make test&#8220;-Durchlaufs der über 13.000 Tests erhaltet ihr das Ergebnis. Falls Fehler aufgetreten sind, könnt ihr den Fehlerbericht direkt an das QA-Team schicken indem ihr Y drückt und eure E-Mail-Adresse eingebt zwecks eventueller Rückfragen. Eine Liste aller fehlgeschlagenen Tests von allen Testern gibt es auf <a href="http://qa.php.net/reports/run_tests.php">qa.php.net</a>.</p> <p>Bei mir sind beispielsweise 6 Tests fehlgeschlagen:</p> <pre class="brush: plain; title: ; notranslate" title="">FAILED TEST SUMMARY --------------------------------------------------------------------- Bug #61948 (CURLOPT_COOKIEFILE '' raises open_basedir restriction) &#x5B;ext/curl/tests/bug61948.phpt] Bug #72333: fwrite() on non-blocking SSL sockets doesn't work &#x5B;ext/openssl/tests/bug72333.phpt] Bug #41655 (open_basedir bypass via glob()) 1/2 &#x5B;ext/standard/tests/file/bug41655_1.phpt] Test glob() function: ensure no platform difference, variation 3 &#x5B;ext/standard/tests/file/glob_variation5.phpt] int stream_socket_sendto ( resource $socket , string $data &#x5B;, int $flags = 0 &#x5B;, string $address ]] ); &#x5B;ext/standard/tests/streams/stream_socket_sendto.phpt] file upload greater than 2G &#x5B;sapi/cli/tests/upload_2G.phpt]</pre> <p>Nach &#8222;make&#8220; kann PHP genutzt werden, beispielsweise kann man damit seine PHPUnit-Tests mal durchlaufen lassen.</p> <pre class="brush: plain; title: ; notranslate" title="">$ /tmp/php-7.3.0RC4/sapi/cli/php -v PHP 7.3.0RC4 (cli) (built: Oct 27 2018 19:15:31) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.3.0-dev, Copyright (c) 1998-2018 Zend Technologies</pre> <p>Um nach den ganzen Tests wieder aufzuräumen, kann der Ordner /tmp/php-7.3.0RC4/ einfach wieder gelöscht werden. Oder wenn man es länger behalten möchte, installiert man die PHP-Version nach /usr/local/php7.3.0RC4 (siehe prefix Parameter beim configure):</p> <pre class="brush: bash; title: ; notranslate" title="">sudo make install</pre> <p>Sollte man auf einem Testsystem machen, je nach Parametern (&#8211;with-apxs2) verändert/zerstört ihr eventuell euren laufenden Apache.</p> <p>Bis zum &#8222;make test&#8220; macht ihr auf jeden Fall nichts kaputt, und ihr könnt in Ruhe testen.</p> <p>Viel Spass beim Testen, und beim Messen der Performanceboosts eurer Applikationen! 🙂</p> <hr /> <h3>Mögliche Fehlermeldungen beim Kompilieren</h3> <p>Hier sind die Fehlermeldungen, die auf meinem Ubuntu 18.04 aufgetreten sind, inklusive der Lösungen:</p> <pre class="brush: bash; title: ; notranslate" title="">configure: error: xml2-config not found. Please check your libxml2 installation. sudo apt-get install libxml2-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find OpenSSL's &lt;evp.h&gt; sudo apt-get install libssl-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">checking for cURL 7.15.5 or greater... configure: error: cURL version 7.15.5 or later is required to compile php with cURL support sudo apt-get install libcurl4-openssl-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find OpenSSL's libraries sudo apt-get install pkg-config</pre> <pre>-------- </pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find zlib sudo apt-get install zlib1g-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">checking whether to enable JIS-mapped Japanese font support in GD... no If configure fails try --with-webp-dir=&lt;DIR&gt; configure: error: jpeglib.h not found. sudo apt-get install libjpeg-turbo8-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: png.h not found. sudo apt-get install libpng-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: freetype-config not found. sudo apt-get install libfreetype6-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: utf8_mime2text() has new signature, but U8T_CANONICAL is missing. This should not happen. Check config.log for additional information. sudo apt-get install libc-client2007e-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Kerberos libraries not found. Check the path given to --with-kerberos (if no path is given, searches in /usr/kerberos, /usr/local and /usr ) sudo apt-get install libkrb5-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Cannot find pspell sudo apt-get install libpspell-dev</pre> <pre>--------</pre> <pre class="brush: bash; title: ; notranslate" title="">configure: error: Please reinstall the libzip distribution sudo apt-get install libzip-dev</pre> https://phpgangsta.de/php-7-3-0-rc-4-performanceboost-und-bitte-testen/feed 4 TLS 1.0/1.1 Abschaltung: Eigene Versionsverteilung herausfinden und serverseitig abschalten https://phpgangsta.de/tls-1-0-1-1-abschaltung-eigene-versionsverteilung-herausfinden-und-serverseitig-abschalten https://phpgangsta.de/tls-1-0-1-1-abschaltung-eigene-versionsverteilung-herausfinden-und-serverseitig-abschalten#respond Wed, 17 Oct 2018 17:06:52 +0000 https://www.phpgangsta.de/?p=6831 <p>Browserhersteller planen, ab 2020 die TLS-Versionen 1.0 und 1.1 nicht mehr zu unterstützen:</p> <p><a href="https://www.heise.de/security/meldung/Verschluesselung-im-Web-Chrome-Firefox-Co-verabschieden-sich-von-TLS-1-0-1-1-4191864.html">https://www.heise.de/security/meldung/Verschluesselung-im-Web-Chrome-Firefox-Co-verabschieden-sich-von-TLS-1-0-1-1-4191864.html</a><br /> <a href="https://www.golem.de/news/https-browser-wollen-alte-tls-versionen-2020-abschalten-1810-137135.html">https://www.golem.de/news/https-browser-wollen-alte-tls-versionen-2020-abschalten-1810-137135.html</a></p> <p>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, &#8230;</p> <p>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.</p> <p>Ich schrieb 2014 über die <a href="https://www.phpgangsta.de/sslv3-uralt-broeckelig-abschalten">Abschaltung von SSLv3</a>, und im Dezember 2017 darüber, dass ab dem 30. Juni 2018 im <a href="https://www.phpgangsta.de/php-curl-und-tls-1-2-als-minimum">Kreditkarten-/Payment-Bereich TLS 1.2 als Minimum</a> genutzt werden muss.</p> <p><span id="more-6831"></span>Auch das <a href="https://www.heise.de/security/artikel/Das-BSI-und-der-Elfenbeinturm-2589893.html">BSI fordert bzw. empfiehlt</a> den Behörden, TLS 1.2 als Minimum zu nutzen (&#8222;fordert&#8220; bei Neusystemen, &#8222;empfiehlt&#8220; bei Altsystemen, aber auch nur wenn es den Bürgern zugemutet werden kann&#8230; Also recht schwammig das ganze).</p> <p>Nun ist es Zeit, sich über TLS 1.0 und 1.1 Gedanken zu machen, auch für Seiten, die nicht durch Kreditkartenkonsortien dadurch gezwungen werden. Und es ist gut, sich damit zu beschäftigen: TLS 1.0 stammt aus dem Jahr 1999, TLS 1.1 aus 2006, und TLS 1.2 aus 2008.</p> <h3>Prozentuale Verteilung von TLS 1.0, 1.1 und 1.2 herausfinden</h3> <p>Einige Browserhersteller nennen Daten ihrer Nutzer:</p> <p>Mozilla:<br /> &#8211; TLS 1.3: 5%<br /> &#8211; TLS 1.2: 93%<br /> &#8211; TLS 1.0: 1,1%<br /> &#8211; TLS 1.1: 0,09%</p> <p>Chrome:<br /> &#8211; TLS 1.0 + 1.1: 0,5%</p> <p>Safari:<br /> &#8211; TLS 1.0 + 1.1: 0,36%</p> <p>Eine weitere Statistik bietet <a href="https://caniuse.com/#feat=tls1-2">caniuse.com</a>, bei der auch mobile Browser einbezogen werden:</p> <p><a href="https://caniuse.com/#feat=tls1-2"><img fetchpriority="high" decoding="async" class="wp-image-6841 alignnone" src="https://www.phpgangsta.de/wp-content/uploads/caniusetls1.2-1024x460.png" alt="" width="699" height="314" srcset="https://phpgangsta.de/wp-content/uploads/caniusetls1.2-1024x460.png 1024w, https://phpgangsta.de/wp-content/uploads/caniusetls1.2-150x67.png 150w, https://phpgangsta.de/wp-content/uploads/caniusetls1.2-300x135.png 300w, https://phpgangsta.de/wp-content/uploads/caniusetls1.2-768x345.png 768w, https://phpgangsta.de/wp-content/uploads/caniusetls1.2.png 1072w" sizes="(max-width: 699px) 100vw, 699px" /></a></p> <p>NICHT kompatibel mit TLS 1.2 sind (<a href="https://maxcluster.de/blog/2018/04/19/tls-1-0-gefaehrdet-pci-dss-compliance/">Quelle</a>):</p> <p>Desktop IE Versionen 8, 9, und 10 auf Windows Vista und älter<br /> Desktop IE Versionen 7 und darunter<br /> Mobile IE Versionen 10 und darunter<br /> Firefox 26 und darunter<br /> Google Chrome 22 bis 37 auf Windows XP SP2 und älter<br /> Google Chrome 21 und darunter<br /> Android 4.4 (KitKat), je nach Gerät<br /> Android 4.3 (Jelly Bean) und darunter<br /> Desktop Safari Versionen 6 und darunter für OS X 10.8 (Mountain Lion) und darunter</p> <p>Eigentlich alles Browser bzw. Betriebssysteme, die niemand mehr nutzen sollte 🙂</p> <p>Wer den Verdacht hat, dass sein Browser kein TLS 1.2 unterstützt, kann den <a href="https://www.ssllabs.com/ssltest/viewMyClient.html">Client-Test von Qualys</a> nutzen, und sich die Sicherheitsfeatures des eigenen Browsers anzeigen lassen.</p> <p>Am einfachsten prüft man die aktuelle Verteilung der TLS-Versionen der eigenen Webseitenbesucher mit Hilfe des Webserver-Logs. Im nginx Webserver beispielsweise so:</p> <pre class="brush: plain; title: ; notranslate" title="">log_format tls '$remote_addr - $remote_user &#x5B;$time_local] &quot;$request&quot; ' '$status $body_bytes_sent &quot;$http_referer&quot; ' '&quot;$http_user_agent&quot; $http_host - $upstream_status - $upstream_addr &#x5B;$request_time/$upstream_response_time] ' '&#x5B;SSL]: $ssl_protocol $ssl_cipher'; access_log /var/log/nginx/access_tls.log tls;</pre> <p>Im &#8222;log_format&#8220; werden Variablen genutzt, um die SSL-Protokoll-Version und den genutzten Cipher in jeder Logzeile hinzuzufügen. Mit Hilfe der &#8222;access_log&#8220; Zeile wird das gerade angelegte Format &#8222;tls&#8220; in eine access_tls.log Datei geschrieben. Das Format der Original access.log zu ändern kann problematisch sein, wenn man mit Auswertungstools darauf zugreift, dann passt das Format evtl. nicht mehr. Deshalb mag es sinnvoller sein, es wie hier im Beispiel in eine separate Datei zu schreiben, die man auch nur einige Tage mitlaufen lässt, denn im Normalfall benötigt man diese Informationen nicht (außer man interessiert sich dafür 🙂 )</p> <p>Mit ein paar grep-Befehlen oder einem kurzen PHP-Analyse-Script sollte sich nun herausfinden lassen, wie sich der Traffic auf die jeweiligen TLS-Versionen verteilt.</p> <p>Man kann es auch mittels Javascript herausfinden, und das Ergebnis an den Server senden. Mehr dazu unten.</p> <p>Sind es nur sehr wenige Nutzer, oder alte Bots auf der Suche nach E-Mail-Adressen, die noch TLS 1.0 nutzen, kann man TLS abschalten, eventuell nach vorheriger Ankündigung für die Nutzer. Doch was tun, wenn es zu viele Nutzer sind, die es noch nutzen?</p> <h3>Eine Warnung anzeigen via Javascript</h3> <p>Mit einem kleinen Javascript kann Nutzern angezeigt werden, dass ihr Browser noch kein TLS 1.2 beherrscht (also die Webseite via TLS 1.0/1.1 aufruft). Hier ein Beispiel:</p> <pre class="brush: plain; title: ; notranslate" title="">&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js&quot; integrity=&quot;sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt; &lt;script type=&quot;application/javascript&quot;&gt; jQuery('&lt;img /&gt;').on({ load: function() { alert(&quot;This browser supports TSL 1.2&quot;); }, error: function() { alert('This browser does not support TSL 1.2'); } }).attr('src','https://tls1.2.only.host.de/some.png'); &lt;/script&gt;</pre> <p>(Aufgabe an die Leser: browserübergreifende Umsetzung ohne das überfrachtete jQuery zu nutzen 🙂 )</p> <p>Das Script muss natürlich angepasst werden, ein &#8222;alert()&#8220; ist keine schöne Anzeige. Besser wäre es, eine auffällige Box anzuzeigen mit einer ausführlichen Erklärung, Links zu Test- und Hilfeseiten usw.</p> <p>Außerdem muss für die URL des Bildes eine Domain genommen werden, die nur TLS 1.2 unterstützt. Entweder man hat bereits eine, oder fragt jemanden der eine solche Domain hat, oder schaltet beispielsweise Cloudflare vor eine Domain, und setzt dort die TLS-Minimum-Version auf TLS 1.2. Man sollte darauf achten, einen TLS1.2-only-Webserver zu nehmen, der 24/7 online ist, denn wenn der Webserver nicht antwortet und das Bild nicht geladen werden kann, gibt es sonst falsche Ergebnisse bzw. Warnungen.</p> <p>Statt dem User die Warnung anzuzeigen, kann der Javascript-Code auch zur Ermittlung der TLS 1.2 Unterstützung genutzt werden. Ein (ungetestetes) Beispiel:</p> <pre class="brush: plain; title: ; notranslate" title="">&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js&quot; integrity=&quot;sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt; &lt;script type=&quot;application/javascript&quot;&gt; jQuery('&lt;img /&gt;').on({ load: function() { jQuery('&lt;img /&gt;').attr('src','https://meinewebsite.de/tlsinfo.php?v=1.2'); }, error: function() { jQuery('&lt;img /&gt;').attr('src','https://meinewebsite.de/tlsinfo.php?v=no1.2'); } }).attr('src','https://tls1.2.only.host.de/some.png'); &lt;/script&gt;</pre> <p>meinewebsite.de sollte natürlich TLS 1.0 und 1.2 unterstützen, sonst klappt es nicht. In der tlsinfo.php schreibt man den erhaltenen &#8222;v&#8220; Parameter z.B. in eine Datenbank, und zählt die Vorkommnisse (man sollte doppelte Requests von IP-Adressen vermutlich rausfiltern).</p> <p>OK, wir haben nur noch wenige Nutzer, die noch TLS 1.0/1.1 benötigen, wir schalten es ab.</p> <h3>TLS 1.0 und 1.1 im Webserver abschalten</h3> <p>Kurz und bündig:</p> <blockquote><p>nginx:<br /> ssl_protocols TLSv1.2;</p> <p>Apache:<br /> SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1</p></blockquote> <p>Obiges ist besser als<br /> SSLProtocol TLSv1.2<br /> denn wenn in Zukunft TLSv1.3 in &#8222;All&#8220; aufgenommen wird, ist es bereits frühestmöglich aktiv, und muss nicht manuell hinzugefügt werden.</p> <p>Man sollte sich natürlich sicher sein, dass dann noch TLS 1.2 übrig bleibt, das Betriebssystem bzw. OpenSSL sollte nicht zu alt sein (OpenSSL &gt;= 1.0.1 bietet TLS 1.2). Ein kurzer Test vorher und nachher ist eine gute Idee:<br /> <a href="https://www.ssllabs.com/ssltest/">https://www.ssllabs.com/ssltest/</a><br /> <a href="https://sslanalyzer.comodoca.com/">https://sslanalyzer.comodoca.com/</a></p> <p>Besonders zu beachten sind die unterstützten TLS-Versionen und die Ciphers. Natürlich bietet es sich auch an, alle anderen verbesserungswürdigen Einstellungen anzupassen, aber das sollte man eh ab und zu mal prüfen.</p> <p>Noch ist das ganze nicht wirklich dringend, selbst 2020 wird es keine Probleme geben wenn man bis dahin TLS 1.2 unterstützt. Doch ich finde, es ist langsam an der Zeit, TLS 1.0 und 1.1 den Laufpass zu geben, und das lieber kontrolliert zu tun, als überhastet im Notfall. Wer weiß, vielleicht ist TLS 1.0 ja auch bereits gebrochen, nur wissen das bisher allein die Geheimdienste&#8230;</p> <p>Browserhersteller planen, ab 2020 die TLS-Versionen 1.0 und 1.1 nicht mehr zu unterstützen:</p> <p><a href="https://www.heise.de/security/meldung/Verschluesselung-im-Web-Chrome-Firefox-Co-verabschieden-sich-von-TLS-1-0-1-1-4191864.html">https://www.heise.de/security/meldung/Verschluesselung-im-Web-Chrome-Firefox-Co-verabschieden-sich-von-TLS-1-0-1-1-4191864.html</a><br /> <a href="https://www.golem.de/news/https-browser-wollen-alte-tls-versionen-2020-abschalten-1810-137135.html">https://www.golem.de/news/https-browser-wollen-alte-tls-versionen-2020-abschalten-1810-137135.html</a></p> <p>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, &#8230;</p> <p>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.</p> <p>Ich schrieb 2014 über die <a href="https://www.phpgangsta.de/sslv3-uralt-broeckelig-abschalten">Abschaltung von SSLv3</a>, und im Dezember 2017 darüber, dass ab dem 30. Juni 2018 im <a href="https://www.phpgangsta.de/php-curl-und-tls-1-2-als-minimum">Kreditkarten-/Payment-Bereich TLS 1.2 als Minimum</a> genutzt werden muss.</p> <p><span id="more-6831"></span>Auch das <a href="https://www.heise.de/security/artikel/Das-BSI-und-der-Elfenbeinturm-2589893.html">BSI fordert bzw. empfiehlt</a> den Behörden, TLS 1.2 als Minimum zu nutzen (&#8222;fordert&#8220; bei Neusystemen, &#8222;empfiehlt&#8220; bei Altsystemen, aber auch nur wenn es den Bürgern zugemutet werden kann&#8230; Also recht schwammig das ganze).</p> <p>Nun ist es Zeit, sich über TLS 1.0 und 1.1 Gedanken zu machen, auch für Seiten, die nicht durch Kreditkartenkonsortien dadurch gezwungen werden. Und es ist gut, sich damit zu beschäftigen: TLS 1.0 stammt aus dem Jahr 1999, TLS 1.1 aus 2006, und TLS 1.2 aus 2008.</p> <h3>Prozentuale Verteilung von TLS 1.0, 1.1 und 1.2 herausfinden</h3> <p>Einige Browserhersteller nennen Daten ihrer Nutzer:</p> <p>Mozilla:<br /> &#8211; TLS 1.3: 5%<br /> &#8211; TLS 1.2: 93%<br /> &#8211; TLS 1.0: 1,1%<br /> &#8211; TLS 1.1: 0,09%</p> <p>Chrome:<br /> &#8211; TLS 1.0 + 1.1: 0,5%</p> <p>Safari:<br /> &#8211; TLS 1.0 + 1.1: 0,36%</p> <p>Eine weitere Statistik bietet <a href="https://caniuse.com/#feat=tls1-2">caniuse.com</a>, bei der auch mobile Browser einbezogen werden:</p> <p><a href="https://caniuse.com/#feat=tls1-2"><img fetchpriority="high" decoding="async" class="wp-image-6841 alignnone" src="https://www.phpgangsta.de/wp-content/uploads/caniusetls1.2-1024x460.png" alt="" width="699" height="314" srcset="https://phpgangsta.de/wp-content/uploads/caniusetls1.2-1024x460.png 1024w, https://phpgangsta.de/wp-content/uploads/caniusetls1.2-150x67.png 150w, https://phpgangsta.de/wp-content/uploads/caniusetls1.2-300x135.png 300w, https://phpgangsta.de/wp-content/uploads/caniusetls1.2-768x345.png 768w, https://phpgangsta.de/wp-content/uploads/caniusetls1.2.png 1072w" sizes="(max-width: 699px) 100vw, 699px" /></a></p> <p>NICHT kompatibel mit TLS 1.2 sind (<a href="https://maxcluster.de/blog/2018/04/19/tls-1-0-gefaehrdet-pci-dss-compliance/">Quelle</a>):</p> <p>Desktop IE Versionen 8, 9, und 10 auf Windows Vista und älter<br /> Desktop IE Versionen 7 und darunter<br /> Mobile IE Versionen 10 und darunter<br /> Firefox 26 und darunter<br /> Google Chrome 22 bis 37 auf Windows XP SP2 und älter<br /> Google Chrome 21 und darunter<br /> Android 4.4 (KitKat), je nach Gerät<br /> Android 4.3 (Jelly Bean) und darunter<br /> Desktop Safari Versionen 6 und darunter für OS X 10.8 (Mountain Lion) und darunter</p> <p>Eigentlich alles Browser bzw. Betriebssysteme, die niemand mehr nutzen sollte 🙂</p> <p>Wer den Verdacht hat, dass sein Browser kein TLS 1.2 unterstützt, kann den <a href="https://www.ssllabs.com/ssltest/viewMyClient.html">Client-Test von Qualys</a> nutzen, und sich die Sicherheitsfeatures des eigenen Browsers anzeigen lassen.</p> <p>Am einfachsten prüft man die aktuelle Verteilung der TLS-Versionen der eigenen Webseitenbesucher mit Hilfe des Webserver-Logs. Im nginx Webserver beispielsweise so:</p> <pre class="brush: plain; title: ; notranslate" title="">log_format tls '$remote_addr - $remote_user &#x5B;$time_local] &quot;$request&quot; ' '$status $body_bytes_sent &quot;$http_referer&quot; ' '&quot;$http_user_agent&quot; $http_host - $upstream_status - $upstream_addr &#x5B;$request_time/$upstream_response_time] ' '&#x5B;SSL]: $ssl_protocol $ssl_cipher'; access_log /var/log/nginx/access_tls.log tls;</pre> <p>Im &#8222;log_format&#8220; werden Variablen genutzt, um die SSL-Protokoll-Version und den genutzten Cipher in jeder Logzeile hinzuzufügen. Mit Hilfe der &#8222;access_log&#8220; Zeile wird das gerade angelegte Format &#8222;tls&#8220; in eine access_tls.log Datei geschrieben. Das Format der Original access.log zu ändern kann problematisch sein, wenn man mit Auswertungstools darauf zugreift, dann passt das Format evtl. nicht mehr. Deshalb mag es sinnvoller sein, es wie hier im Beispiel in eine separate Datei zu schreiben, die man auch nur einige Tage mitlaufen lässt, denn im Normalfall benötigt man diese Informationen nicht (außer man interessiert sich dafür 🙂 )</p> <p>Mit ein paar grep-Befehlen oder einem kurzen PHP-Analyse-Script sollte sich nun herausfinden lassen, wie sich der Traffic auf die jeweiligen TLS-Versionen verteilt.</p> <p>Man kann es auch mittels Javascript herausfinden, und das Ergebnis an den Server senden. Mehr dazu unten.</p> <p>Sind es nur sehr wenige Nutzer, oder alte Bots auf der Suche nach E-Mail-Adressen, die noch TLS 1.0 nutzen, kann man TLS abschalten, eventuell nach vorheriger Ankündigung für die Nutzer. Doch was tun, wenn es zu viele Nutzer sind, die es noch nutzen?</p> <h3>Eine Warnung anzeigen via Javascript</h3> <p>Mit einem kleinen Javascript kann Nutzern angezeigt werden, dass ihr Browser noch kein TLS 1.2 beherrscht (also die Webseite via TLS 1.0/1.1 aufruft). Hier ein Beispiel:</p> <pre class="brush: plain; title: ; notranslate" title="">&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js&quot; integrity=&quot;sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt; &lt;script type=&quot;application/javascript&quot;&gt; jQuery('&lt;img /&gt;').on({ load: function() { alert(&quot;This browser supports TSL 1.2&quot;); }, error: function() { alert('This browser does not support TSL 1.2'); } }).attr('src','https://tls1.2.only.host.de/some.png'); &lt;/script&gt;</pre> <p>(Aufgabe an die Leser: browserübergreifende Umsetzung ohne das überfrachtete jQuery zu nutzen 🙂 )</p> <p>Das Script muss natürlich angepasst werden, ein &#8222;alert()&#8220; ist keine schöne Anzeige. Besser wäre es, eine auffällige Box anzuzeigen mit einer ausführlichen Erklärung, Links zu Test- und Hilfeseiten usw.</p> <p>Außerdem muss für die URL des Bildes eine Domain genommen werden, die nur TLS 1.2 unterstützt. Entweder man hat bereits eine, oder fragt jemanden der eine solche Domain hat, oder schaltet beispielsweise Cloudflare vor eine Domain, und setzt dort die TLS-Minimum-Version auf TLS 1.2. Man sollte darauf achten, einen TLS1.2-only-Webserver zu nehmen, der 24/7 online ist, denn wenn der Webserver nicht antwortet und das Bild nicht geladen werden kann, gibt es sonst falsche Ergebnisse bzw. Warnungen.</p> <p>Statt dem User die Warnung anzuzeigen, kann der Javascript-Code auch zur Ermittlung der TLS 1.2 Unterstützung genutzt werden. Ein (ungetestetes) Beispiel:</p> <pre class="brush: plain; title: ; notranslate" title="">&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js&quot; integrity=&quot;sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt; &lt;script type=&quot;application/javascript&quot;&gt; jQuery('&lt;img /&gt;').on({ load: function() { jQuery('&lt;img /&gt;').attr('src','https://meinewebsite.de/tlsinfo.php?v=1.2'); }, error: function() { jQuery('&lt;img /&gt;').attr('src','https://meinewebsite.de/tlsinfo.php?v=no1.2'); } }).attr('src','https://tls1.2.only.host.de/some.png'); &lt;/script&gt;</pre> <p>meinewebsite.de sollte natürlich TLS 1.0 und 1.2 unterstützen, sonst klappt es nicht. In der tlsinfo.php schreibt man den erhaltenen &#8222;v&#8220; Parameter z.B. in eine Datenbank, und zählt die Vorkommnisse (man sollte doppelte Requests von IP-Adressen vermutlich rausfiltern).</p> <p>OK, wir haben nur noch wenige Nutzer, die noch TLS 1.0/1.1 benötigen, wir schalten es ab.</p> <h3>TLS 1.0 und 1.1 im Webserver abschalten</h3> <p>Kurz und bündig:</p> <blockquote><p>nginx:<br /> ssl_protocols TLSv1.2;</p> <p>Apache:<br /> SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1</p></blockquote> <p>Obiges ist besser als<br /> SSLProtocol TLSv1.2<br /> denn wenn in Zukunft TLSv1.3 in &#8222;All&#8220; aufgenommen wird, ist es bereits frühestmöglich aktiv, und muss nicht manuell hinzugefügt werden.</p> <p>Man sollte sich natürlich sicher sein, dass dann noch TLS 1.2 übrig bleibt, das Betriebssystem bzw. OpenSSL sollte nicht zu alt sein (OpenSSL &gt;= 1.0.1 bietet TLS 1.2). Ein kurzer Test vorher und nachher ist eine gute Idee:<br /> <a href="https://www.ssllabs.com/ssltest/">https://www.ssllabs.com/ssltest/</a><br /> <a href="https://sslanalyzer.comodoca.com/">https://sslanalyzer.comodoca.com/</a></p> <p>Besonders zu beachten sind die unterstützten TLS-Versionen und die Ciphers. Natürlich bietet es sich auch an, alle anderen verbesserungswürdigen Einstellungen anzupassen, aber das sollte man eh ab und zu mal prüfen.</p> <p>Noch ist das ganze nicht wirklich dringend, selbst 2020 wird es keine Probleme geben wenn man bis dahin TLS 1.2 unterstützt. Doch ich finde, es ist langsam an der Zeit, TLS 1.0 und 1.1 den Laufpass zu geben, und das lieber kontrolliert zu tun, als überhastet im Notfall. Wer weiß, vielleicht ist TLS 1.0 ja auch bereits gebrochen, nur wissen das bisher allein die Geheimdienste&#8230;</p> https://phpgangsta.de/tls-1-0-1-1-abschaltung-eigene-versionsverteilung-herausfinden-und-serverseitig-abschalten/feed 0 Performanceboost durch temporäres Abschalten des PHP Garbage Collectors https://phpgangsta.de/performanceboost-durch-temporaeres-abschalten-des-php-garbage-collectors https://phpgangsta.de/performanceboost-durch-temporaeres-abschalten-des-php-garbage-collectors#comments Fri, 12 Oct 2018 08:46:27 +0000 https://www.phpgangsta.de/?p=6819 <p><strong>Update 27.10.2018</strong>: Mit PHP 7.3 ist das selektive <a href="https://www.phpgangsta.de/php-7-3-0-rc-4-performanceboost-und-bitte-testen">Abschalten des Garbage Collectors wohl nicht mehr nötig</a>.</p> <p>Auf der Suche nach einfachen Möglichkeiten, die Performance eines CPU-bound PHP-Scripts zu steigern, fiel mir wieder ein, wie der <a href="https://getcomposer.org/">Composer Installer</a> einen drastischen Performanceboost hinbekommen hat. Selbst ausprobiert, und siehe da: Statt 7 Sekunden Laufzeit nur noch 2,7 Sekunden. Whao!</p> <p>Wie macht man sowas mit nur 1-3 Zeilenänderungen?</p> <h3>Garbage Collection</h3> <p>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.</p> <p>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.<span id="more-6819"></span></p> <p>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 &#8222;im Kreis&#8220; 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.</p> <p>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, &#8222;double-free&#8220; Fehlern und so weiter. Deshalb nehmen moderne/sicherere Hochsprachen einem Programmierer diese Arbeit ab, die aller meisten modernen Programmiersprachen haben Garbage Collectoren.</p> <p>Garbage Collectoren laufen also im Hintergrund mit, und versuchen &#8222;ab und zu&#8220; 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.</p> <p>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: &#8222;Serial collector&#8220;, &#8222;Parallel collector&#8220;, &#8222;Concurrent Mark Sweep (CMS) Collector&#8220;, &#8222;Generational Garbage Collector&#8220;.</p> <h3>Garbage Collector temporär abschalten</h3> <p>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.<br /> <a href="https://tideways.com/profiler/blog/how-to-optimize-the-php-garbage-collector-usage-to-improve-memory-and-performance">https://tideways.com/profiler/blog/how-to-optimize-the-php-garbage-collector-usage-to-improve-memory-and-performance</a><br /> <a href="https://blog.blackfire.io/performance-impact-of-the-php-garbage-collector.html">https://blog.blackfire.io/performance-impact-of-the-php-garbage-collector.html</a></p> <p>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.</p> <p>Erst heute morgen habe ich es beim <a href="https://github.com/dompdf/dompdf">DomPDF Projekt</a> 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 <a href="https://github.com/dompdf/dompdf/issues/1813">Issue über Performance</a> 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.</p> <pre class="brush: plain; title: ; notranslate" title="">$ 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-&gt;saveLocale(); $options = $this-&gt;options; @@ -864,6 +866,9 @@ class Dompdf } $this-&gt;restoreLocale(); + + gc_enable(); + gc_collect_cycles(); }</pre> <p>Vorher:</p> <pre class="brush: plain; title: ; notranslate" title="">$ 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 &lt;====== Output 36,168,776 49,725,776 0.00060415267944336 End 36,169,232</pre> <p>Nachher:</p> <pre class="brush: plain; title: ; notranslate" title="">$ 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 &lt;====== Output 36,169,112 49,719,360 0.00069785118103027 End 36,169,568</pre> <p>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.</p> <p>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.</p> <p>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 🙂</p> <p>Und hier die versprochenen Links zu Details des (PHP) Garbage Collectors:</p> <p><a href="https://blog.ircmaxell.com/2014/12/what-about-garbage.html">https://blog.ircmaxell.com/2014/12/what-about-garbage.html</a><br /> <a href="https://react-etc.net/entry/improvements-to-garbage-collection-gc-php-7-3-boosts-performance-in-benchmark">https://react-etc.net/entry/improvements-to-garbage-collection-gc-php-7-3-boosts-performance-in-benchmark</a><br /> <a href="https://www.sitepoint.com/better-understanding-phps-garbage-collection/">https://www.sitepoint.com/better-understanding-phps-garbage-collection/</a><br /> <a href="http://php.net/manual/de/features.gc.performance-considerations.php">http://php.net/manual/de/features.gc.performance-considerations.php</a></p> <p><strong>Update 27.10.2018</strong>: Mit PHP 7.3 ist das selektive <a href="https://www.phpgangsta.de/php-7-3-0-rc-4-performanceboost-und-bitte-testen">Abschalten des Garbage Collectors wohl nicht mehr nötig</a>.</p> <p>Auf der Suche nach einfachen Möglichkeiten, die Performance eines CPU-bound PHP-Scripts zu steigern, fiel mir wieder ein, wie der <a href="https://getcomposer.org/">Composer Installer</a> einen drastischen Performanceboost hinbekommen hat. Selbst ausprobiert, und siehe da: Statt 7 Sekunden Laufzeit nur noch 2,7 Sekunden. Whao!</p> <p>Wie macht man sowas mit nur 1-3 Zeilenänderungen?</p> <h3>Garbage Collection</h3> <p>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.</p> <p>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.<span id="more-6819"></span></p> <p>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 &#8222;im Kreis&#8220; 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.</p> <p>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, &#8222;double-free&#8220; Fehlern und so weiter. Deshalb nehmen moderne/sicherere Hochsprachen einem Programmierer diese Arbeit ab, die aller meisten modernen Programmiersprachen haben Garbage Collectoren.</p> <p>Garbage Collectoren laufen also im Hintergrund mit, und versuchen &#8222;ab und zu&#8220; 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.</p> <p>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: &#8222;Serial collector&#8220;, &#8222;Parallel collector&#8220;, &#8222;Concurrent Mark Sweep (CMS) Collector&#8220;, &#8222;Generational Garbage Collector&#8220;.</p> <h3>Garbage Collector temporär abschalten</h3> <p>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.<br /> <a href="https://tideways.com/profiler/blog/how-to-optimize-the-php-garbage-collector-usage-to-improve-memory-and-performance">https://tideways.com/profiler/blog/how-to-optimize-the-php-garbage-collector-usage-to-improve-memory-and-performance</a><br /> <a href="https://blog.blackfire.io/performance-impact-of-the-php-garbage-collector.html">https://blog.blackfire.io/performance-impact-of-the-php-garbage-collector.html</a></p> <p>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.</p> <p>Erst heute morgen habe ich es beim <a href="https://github.com/dompdf/dompdf">DomPDF Projekt</a> 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 <a href="https://github.com/dompdf/dompdf/issues/1813">Issue über Performance</a> 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.</p> <pre class="brush: plain; title: ; notranslate" title="">$ 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-&gt;saveLocale(); $options = $this-&gt;options; @@ -864,6 +866,9 @@ class Dompdf } $this-&gt;restoreLocale(); + + gc_enable(); + gc_collect_cycles(); }</pre> <p>Vorher:</p> <pre class="brush: plain; title: ; notranslate" title="">$ 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 &lt;====== Output 36,168,776 49,725,776 0.00060415267944336 End 36,169,232</pre> <p>Nachher:</p> <pre class="brush: plain; title: ; notranslate" title="">$ 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 &lt;====== Output 36,169,112 49,719,360 0.00069785118103027 End 36,169,568</pre> <p>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.</p> <p>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.</p> <p>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 🙂</p> <p>Und hier die versprochenen Links zu Details des (PHP) Garbage Collectors:</p> <p><a href="https://blog.ircmaxell.com/2014/12/what-about-garbage.html">https://blog.ircmaxell.com/2014/12/what-about-garbage.html</a><br /> <a href="https://react-etc.net/entry/improvements-to-garbage-collection-gc-php-7-3-boosts-performance-in-benchmark">https://react-etc.net/entry/improvements-to-garbage-collection-gc-php-7-3-boosts-performance-in-benchmark</a><br /> <a href="https://www.sitepoint.com/better-understanding-phps-garbage-collection/">https://www.sitepoint.com/better-understanding-phps-garbage-collection/</a><br /> <a href="http://php.net/manual/de/features.gc.performance-considerations.php">http://php.net/manual/de/features.gc.performance-considerations.php</a></p> https://phpgangsta.de/performanceboost-durch-temporaeres-abschalten-des-php-garbage-collectors/feed 1 Der Unterschied zwischen „||“ und „or“ bzw. „&&“ und „and“ https://phpgangsta.de/der-unterschied-zwischen-und-or-bzw-und-and https://phpgangsta.de/der-unterschied-zwischen-und-or-bzw-und-and#respond Sat, 29 Sep 2018 17:33:43 +0000 https://www.phpgangsta.de/?p=6813 <p>Wenn man eine if-Anweisung in PHP schreiben möchte, und dabei 2 Bedingungen mit einem &#8222;und&#8220; verknüpfen möchte, kann man entweder &#8222;&amp;&amp;&#8220; nutzen oder &#8222;and&#8220; schreiben. Richtig?</p> <pre class="brush: php; title: ; notranslate" title="">if ($a &gt; 0 &amp;&amp; $b &lt; 100) {</pre> <pre class="brush: php; title: ; notranslate" title="">if ($a &gt; 0 and $b &lt; 100) {</pre> <p>Das ist das selbe, oder? Ja, ist es. Beides funktioniert, beides ist syntaktisch korrekt, und beides ist äquivalent.</p> <p>Kopieren wir nun die Bedingungen in eine temporäre Variable $c:<span id="more-6813"></span></p> <pre class="brush: php; title: ; notranslate" title="">$c = $a &gt; 0 &amp;&amp; $b &lt; 100; if ($c) {</pre> <pre class="brush: php; title: ; notranslate" title="">$c = $a &gt; 0 and $b &lt; 100; if ($c) {</pre> <p><strong>DAS ist nun nicht mehr das selbe!</strong></p> <p>Schauen wir uns das in einer einfacheren Zuweisung an:</p> <pre class="brush: php; title: ; notranslate" title="">$a = true; $b = false; $bool = $a &amp;&amp; $b; var_dump($bool); // false, wie erwartet $bool = $a and $b; var_dump($bool); // true ?!?</pre> <p>Mir war der Unterschied nicht bekannt, bis vor einigen Wochen auf der <a href="https://externals.io/message/102679">PHP-Internals-Liste über das Thema Unifying logical operators</a> diskutiert wurde. Ryan &#8222;Iggy&#8220; Volz schlägt vor, diesen nicht erwarteten Unterschied zu entfernen, &#8222;and&#8220; solle in Zukunft ein Alias für &#8222;&amp;&amp;&#8220; sein, &#8222;or&#8220; ein Alias für &#8222;||&#8220;. Einen <a href="https://github.com/iggyvolz/Unifying-Operators-RFC">Entwurf eines RFC</a> hat er vorbereitet.</p> <h3>Doch woher kommt der Unterschied?</h3> <p>Schuld daran ist die <a href="http://php.net/manual/en/language.operators.precedence.php">Operator precedence</a>:</p> <p><strong>&amp;&amp; bzw. || sind höher in der Reihenfolge als das Gleichheitszeichen &#8222;=&#8220;. &#8222;and&#8220; bzw. &#8222;or&#8220; sind niedriger als &#8222;=&#8220;. Das führt zur beobachteten unterschiedlichen Gruppierung der Operanden.</strong></p> <p>Hier eine <a href="https://stackoverflow.com/a/34848592">schöne Übersicht</a>:</p> <pre class="brush: plain; title: ; notranslate" title="">$bool = FALSE || TRUE; - interpreted as ($bool = (FALSE || TRUE)) - value of $bool is TRUE $bool = FALSE OR TRUE; - interpreted as (($bool = FALSE) OR TRUE) - value of $bool is FALSE $bool = TRUE &amp;&amp; FALSE; - interpreted as ($bool = (TRUE &amp;&amp; FALSE)) - value of $bool is FALSE $bool = TRUE AND FALSE; - interpreted as (($bool = TRUE) AND FALSE) - value of $bool is TRUE</pre> <p>Der Unterschied ist in der &#8222;interpreted as&#8220; Zeile zu sehen: Einmal werden erst die beiden linken Operanden verarbeitet, dann bei Bedarf der rechte, und einmal werden erst die beiden rechten Operanden verarbeitet, und dann per Zuweisung in die Variable geschrieben.</p> <p>Ich muss zugeben, sehr selten ein &#8222;or&#8220; bzw. &#8222;and&#8220; in PHP-Code zu sehen, aber in altem Code sieht man es ab und zu. Entweder weil es jemand schöner findet, oder weil er mit anderen Sprachen durcheinander gekommen ist, in denen &#8222;and&#8220; bzw. &#8222;or&#8220; genutzt werden (SQL ist ein bekanntes Beispiel). Häufig funktioniert es ohne Probleme, z.B. in if-Anweisungen, aber bei Zuweisungen ist Vorsicht angesagt.</p> <p>Ich glaube nicht, dass eine Änderung des aktuellen Verhaltens angegangen wird, die Diskussion ist zum Erliegen gekommen, sie ging eher hin zu &#8222;das war noch nie ein großes Problem&#8220;, &#8222;es wird genutzt in diversen Projekten, die Änderung macht alle diese Projekte unnötigerweise kaputt&#8220;, und &#8222;ich finde es toll, dass es diese beiden Schreibweisen gibt&#8220;. Es wird also vermutlich kein Aliasing geben, und alles bleibt so wie es ist.</p> <p>Wenn man eine if-Anweisung in PHP schreiben möchte, und dabei 2 Bedingungen mit einem &#8222;und&#8220; verknüpfen möchte, kann man entweder &#8222;&amp;&amp;&#8220; nutzen oder &#8222;and&#8220; schreiben. Richtig?</p> <pre class="brush: php; title: ; notranslate" title="">if ($a &gt; 0 &amp;&amp; $b &lt; 100) {</pre> <pre class="brush: php; title: ; notranslate" title="">if ($a &gt; 0 and $b &lt; 100) {</pre> <p>Das ist das selbe, oder? Ja, ist es. Beides funktioniert, beides ist syntaktisch korrekt, und beides ist äquivalent.</p> <p>Kopieren wir nun die Bedingungen in eine temporäre Variable $c:<span id="more-6813"></span></p> <pre class="brush: php; title: ; notranslate" title="">$c = $a &gt; 0 &amp;&amp; $b &lt; 100; if ($c) {</pre> <pre class="brush: php; title: ; notranslate" title="">$c = $a &gt; 0 and $b &lt; 100; if ($c) {</pre> <p><strong>DAS ist nun nicht mehr das selbe!</strong></p> <p>Schauen wir uns das in einer einfacheren Zuweisung an:</p> <pre class="brush: php; title: ; notranslate" title="">$a = true; $b = false; $bool = $a &amp;&amp; $b; var_dump($bool); // false, wie erwartet $bool = $a and $b; var_dump($bool); // true ?!?</pre> <p>Mir war der Unterschied nicht bekannt, bis vor einigen Wochen auf der <a href="https://externals.io/message/102679">PHP-Internals-Liste über das Thema Unifying logical operators</a> diskutiert wurde. Ryan &#8222;Iggy&#8220; Volz schlägt vor, diesen nicht erwarteten Unterschied zu entfernen, &#8222;and&#8220; solle in Zukunft ein Alias für &#8222;&amp;&amp;&#8220; sein, &#8222;or&#8220; ein Alias für &#8222;||&#8220;. Einen <a href="https://github.com/iggyvolz/Unifying-Operators-RFC">Entwurf eines RFC</a> hat er vorbereitet.</p> <h3>Doch woher kommt der Unterschied?</h3> <p>Schuld daran ist die <a href="http://php.net/manual/en/language.operators.precedence.php">Operator precedence</a>:</p> <p><strong>&amp;&amp; bzw. || sind höher in der Reihenfolge als das Gleichheitszeichen &#8222;=&#8220;. &#8222;and&#8220; bzw. &#8222;or&#8220; sind niedriger als &#8222;=&#8220;. Das führt zur beobachteten unterschiedlichen Gruppierung der Operanden.</strong></p> <p>Hier eine <a href="https://stackoverflow.com/a/34848592">schöne Übersicht</a>:</p> <pre class="brush: plain; title: ; notranslate" title="">$bool = FALSE || TRUE; - interpreted as ($bool = (FALSE || TRUE)) - value of $bool is TRUE $bool = FALSE OR TRUE; - interpreted as (($bool = FALSE) OR TRUE) - value of $bool is FALSE $bool = TRUE &amp;&amp; FALSE; - interpreted as ($bool = (TRUE &amp;&amp; FALSE)) - value of $bool is FALSE $bool = TRUE AND FALSE; - interpreted as (($bool = TRUE) AND FALSE) - value of $bool is TRUE</pre> <p>Der Unterschied ist in der &#8222;interpreted as&#8220; Zeile zu sehen: Einmal werden erst die beiden linken Operanden verarbeitet, dann bei Bedarf der rechte, und einmal werden erst die beiden rechten Operanden verarbeitet, und dann per Zuweisung in die Variable geschrieben.</p> <p>Ich muss zugeben, sehr selten ein &#8222;or&#8220; bzw. &#8222;and&#8220; in PHP-Code zu sehen, aber in altem Code sieht man es ab und zu. Entweder weil es jemand schöner findet, oder weil er mit anderen Sprachen durcheinander gekommen ist, in denen &#8222;and&#8220; bzw. &#8222;or&#8220; genutzt werden (SQL ist ein bekanntes Beispiel). Häufig funktioniert es ohne Probleme, z.B. in if-Anweisungen, aber bei Zuweisungen ist Vorsicht angesagt.</p> <p>Ich glaube nicht, dass eine Änderung des aktuellen Verhaltens angegangen wird, die Diskussion ist zum Erliegen gekommen, sie ging eher hin zu &#8222;das war noch nie ein großes Problem&#8220;, &#8222;es wird genutzt in diversen Projekten, die Änderung macht alle diese Projekte unnötigerweise kaputt&#8220;, und &#8222;ich finde es toll, dass es diese beiden Schreibweisen gibt&#8220;. Es wird also vermutlich kein Aliasing geben, und alles bleibt so wie es ist.</p> https://phpgangsta.de/der-unterschied-zwischen-und-or-bzw-und-and/feed 0 igphp – Interessengemeinschaft PHP e.V. https://phpgangsta.de/igphp-interessengemeinschaft-php-e-v https://phpgangsta.de/igphp-interessengemeinschaft-php-e-v#respond Sat, 01 Sep 2018 20:50:46 +0000 https://www.phpgangsta.de/?p=6798 <p><img decoding="async" class="alignright wp-image-6801 size-full" src="https://www.phpgangsta.de/wp-content/uploads/we-love-php.png" alt="" width="316" height="84" srcset="https://phpgangsta.de/wp-content/uploads/we-love-php.png 316w, https://phpgangsta.de/wp-content/uploads/we-love-php-150x40.png 150w, https://phpgangsta.de/wp-content/uploads/we-love-php-300x80.png 300w" sizes="(max-width: 316px) 100vw, 316px" />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&#8230;) 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&#8230;</p> <p><a href="https://igphp.de/"><img decoding="async" class="alignright wp-image-6800 size-full" src="https://www.phpgangsta.de/wp-content/uploads/logo.png" alt="" width="152" height="52" srcset="https://phpgangsta.de/wp-content/uploads/logo.png 152w, https://phpgangsta.de/wp-content/uploads/logo-150x51.png 150w" sizes="(max-width: 152px) 100vw, 152px" /></a>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.</p> <p>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.</p> <p>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.</p> <p>Ich würde mich sehr freuen, mit euch im Verein zusammenzuarbeiten.</p> <p>Weitere Infos findet ihr hier:</p> <p><a href="https://igphp.de/">https://igphp.de/</a></p> <p>https://twitter.com/igphp</p> <p><img decoding="async" class="alignright wp-image-6801 size-full" src="https://www.phpgangsta.de/wp-content/uploads/we-love-php.png" alt="" width="316" height="84" srcset="https://phpgangsta.de/wp-content/uploads/we-love-php.png 316w, https://phpgangsta.de/wp-content/uploads/we-love-php-150x40.png 150w, https://phpgangsta.de/wp-content/uploads/we-love-php-300x80.png 300w" sizes="(max-width: 316px) 100vw, 316px" />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&#8230;) 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&#8230;</p> <p><a href="https://igphp.de/"><img decoding="async" class="alignright wp-image-6800 size-full" src="https://www.phpgangsta.de/wp-content/uploads/logo.png" alt="" width="152" height="52" srcset="https://phpgangsta.de/wp-content/uploads/logo.png 152w, https://phpgangsta.de/wp-content/uploads/logo-150x51.png 150w" sizes="(max-width: 152px) 100vw, 152px" /></a>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.</p> <p>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.</p> <p>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.</p> <p>Ich würde mich sehr freuen, mit euch im Verein zusammenzuarbeiten.</p> <p>Weitere Infos findet ihr hier:</p> <p><a href="https://igphp.de/">https://igphp.de/</a></p> <p>https://twitter.com/igphp</p> https://phpgangsta.de/igphp-interessengemeinschaft-php-e-v/feed 0 PHP, curl und TLS 1.2 als Minimum https://phpgangsta.de/php-curl-und-tls-1-2-als-minimum https://phpgangsta.de/php-curl-und-tls-1-2-als-minimum#comments Mon, 04 Dec 2017 22:43:35 +0000 https://www.phpgangsta.de/?p=6776 <p>TLS 1.2 ist im Payment-Bereich weiter auf dem Vormarsch, immer mehr Zahlungsanbieter setzen <strong>TLS 1.2 als Minimumversion</strong> fest. Das <a href="https://blog.pcisecuritystandards.org/migrating-from-ssl-and-early-tls">Payment Card Industry Security Standards Council (PCI SSC) hat die Frist von 2016 auf 2018 verschoben</a>. <a href="https://www.paypal.com/au/webapps/mpp/tls-http-upgrade">PayPal wird am 30. Juni 2018 TLS 1.0 und 1.1 abschalten</a>. Paysafecard wird selbiges bereits im Februar 2018 tun.</p> <p>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.</p> <p>Folgendes Script testet die TLS-Einstellungen von PHP (curl) mit Hilfe der Webseite https://www.howsmyssl.com:</p> <pre class="brush: plain; title: ; notranslate" title="">&lt;?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);</pre> <p>Die Ergebnisse:</p> <p><span id="more-6776"></span>Ubuntu 13.10: TLS 1.1 &#8222;Bad&#8220;<br /> Ubuntu 14.04: TLS 1.2 &#8222;Bad&#8220;<br /> Ubuntu 16.04: TLS 1.2 &#8222;Probably Okay&#8220;</p> <p>Ein weiterer Grund, immer up2date zu bleiben. Ubuntu 13.10 erhält seit Jahren keine Security-Updates mehr, sollte also eh nirgends mehr eingesetzt werden (besonders nicht in Payment-Systemen).</p> <p>===================================</p> <p>Hier die ausführlichen Ausgaben der 3 untersuchten Ubuntu-Versionen:</p> <p>Ausgabe Ubuntu 13.10.:</p> <pre class="brush: plain; title: ; notranslate" title="">object(stdClass)#1 (10) { &#x5B;&quot;given_cipher_suites&quot;]=&gt; array(51) { &#x5B;0]=&gt; string(34) &quot;TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;1]=&gt; string(36) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA&quot; &#x5B;2]=&gt; string(36) &quot;TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA&quot; &#x5B;3]=&gt; string(36) &quot;TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;4]=&gt; string(32) &quot;TLS_DHE_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;5]=&gt; string(32) &quot;TLS_DHE_DSS_WITH_AES_256_CBC_SHA&quot; &#x5B;6]=&gt; string(37) &quot;TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;7]=&gt; string(37) &quot;TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;8]=&gt; string(33) &quot;TLS_ECDH_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;9]=&gt; string(35) &quot;TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA&quot; &#x5B;10]=&gt; string(28) &quot;TLS_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;11]=&gt; string(33) &quot;TLS_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;12]=&gt; string(35) &quot;TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;13]=&gt; string(37) &quot;TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;14]=&gt; string(37) &quot;TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;15]=&gt; string(37) &quot;TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;16]=&gt; string(33) &quot;TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;17]=&gt; string(33) &quot;TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;18]=&gt; string(34) &quot;TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;19]=&gt; string(36) &quot;TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;20]=&gt; string(29) &quot;TLS_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;21]=&gt; string(34) &quot;TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;22]=&gt; string(36) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA&quot; &#x5B;23]=&gt; string(36) &quot;TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA&quot; &#x5B;24]=&gt; string(36) &quot;TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;25]=&gt; string(32) &quot;TLS_DHE_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;26]=&gt; string(32) &quot;TLS_DHE_DSS_WITH_AES_128_CBC_SHA&quot; &#x5B;27]=&gt; string(29) &quot;TLS_DHE_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;28]=&gt; string(29) &quot;TLS_DHE_DSS_WITH_SEED_CBC_SHA&quot; &#x5B;29]=&gt; string(37) &quot;TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;30]=&gt; string(37) &quot;TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;31]=&gt; string(33) &quot;TLS_ECDH_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;32]=&gt; string(35) &quot;TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA&quot; &#x5B;33]=&gt; string(28) &quot;TLS_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;34]=&gt; string(25) &quot;TLS_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;35]=&gt; string(33) &quot;TLS_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;36]=&gt; string(30) &quot;TLS_ECDHE_RSA_WITH_RC4_128_SHA&quot; &#x5B;37]=&gt; string(32) &quot;TLS_ECDHE_ECDSA_WITH_RC4_128_SHA&quot; &#x5B;38]=&gt; string(29) &quot;TLS_ECDH_RSA_WITH_RC4_128_SHA&quot; &#x5B;39]=&gt; string(31) &quot;TLS_ECDH_ECDSA_WITH_RC4_128_SHA&quot; &#x5B;40]=&gt; string(24) &quot;TLS_RSA_WITH_RC4_128_SHA&quot; &#x5B;41]=&gt; string(24) &quot;TLS_RSA_WITH_RC4_128_MD5&quot; &#x5B;42]=&gt; string(28) &quot;TLS_DHE_RSA_WITH_DES_CBC_SHA&quot; &#x5B;43]=&gt; string(28) &quot;TLS_DHE_DSS_WITH_DES_CBC_SHA&quot; &#x5B;44]=&gt; string(24) &quot;TLS_RSA_WITH_DES_CBC_SHA&quot; &#x5B;45]=&gt; string(37) &quot;TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA&quot; &#x5B;46]=&gt; string(37) &quot;TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA&quot; &#x5B;47]=&gt; string(33) &quot;TLS_RSA_EXPORT_WITH_DES40_CBC_SHA&quot; &#x5B;48]=&gt; string(34) &quot;TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5&quot; &#x5B;49]=&gt; string(30) &quot;TLS_RSA_EXPORT_WITH_RC4_40_MD5&quot; &#x5B;50]=&gt; string(33) &quot;TLS_EMPTY_RENEGOTIATION_INFO_SCSV&quot; } &#x5B;&quot;ephemeral_keys_supported&quot;]=&gt; bool(true) &#x5B;&quot;session_ticket_supported&quot;]=&gt; bool(false) &#x5B;&quot;tls_compression_supported&quot;]=&gt; bool(false) &#x5B;&quot;unknown_cipher_suite_supported&quot;]=&gt; bool(false) &#x5B;&quot;beast_vuln&quot;]=&gt; bool(false) &#x5B;&quot;able_to_detect_n_minus_one_splitting&quot;]=&gt; bool(false) &#x5B;&quot;insecure_cipher_suites&quot;]=&gt; object(stdClass)#2 (23) { &#x5B;&quot;TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_DHE_DSS_WITH_DES_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_DHE_RSA_WITH_DES_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDHE_ECDSA_WITH_RC4_128_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDHE_RSA_WITH_RC4_128_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDH_ECDSA_WITH_RC4_128_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDH_RSA_WITH_RC4_128_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_RSA_EXPORT_WITH_DES40_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_RSA_EXPORT_WITH_RC4_40_MD5&quot;]=&gt; array(2) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; &#x5B;1]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_RSA_WITH_DES_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_RSA_WITH_RC4_128_MD5&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_RSA_WITH_RC4_128_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } } &#x5B;&quot;tls_version&quot;]=&gt; string(7) &quot;TLS 1.1&quot; &#x5B;&quot;rating&quot;]=&gt; string(3) &quot;Bad&quot; }</pre> <p>Ausgabe Ubuntu 14.04:</p> <pre class="brush: plain; title: ; notranslate" title="">object(stdClass)#1 (10) { &#x5B;&quot;given_cipher_suites&quot;]=&gt; array(59) { &#x5B;0]=&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;1]=&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;2]=&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;3]=&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;4]=&gt; string(34) &quot;TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;5]=&gt; string(36) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA&quot; &#x5B;6]=&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_256_GCM_SHA384&quot; &#x5B;7]=&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;8]=&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_256_CBC_SHA256&quot; &#x5B;9]=&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_256_CBC_SHA256&quot; &#x5B;10]=&gt; string(32) &quot;TLS_DHE_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;11]=&gt; string(32) &quot;TLS_DHE_DSS_WITH_AES_256_CBC_SHA&quot; &#x5B;12]=&gt; string(37) &quot;TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;13]=&gt; string(37) &quot;TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;14]=&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;15]=&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;16]=&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;17]=&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;18]=&gt; string(33) &quot;TLS_ECDH_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;19]=&gt; string(35) &quot;TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA&quot; &#x5B;20]=&gt; string(31) &quot;TLS_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;21]=&gt; string(31) &quot;TLS_RSA_WITH_AES_256_CBC_SHA256&quot; &#x5B;22]=&gt; string(28) &quot;TLS_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;23]=&gt; string(33) &quot;TLS_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;24]=&gt; string(35) &quot;TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;25]=&gt; string(37) &quot;TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;26]=&gt; string(33) &quot;TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;27]=&gt; string(33) &quot;TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;28]=&gt; string(34) &quot;TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;29]=&gt; string(36) &quot;TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;30]=&gt; string(29) &quot;TLS_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;31]=&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;32]=&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;33]=&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;34]=&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;35]=&gt; string(34) &quot;TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;36]=&gt; string(36) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA&quot; &#x5B;37]=&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_128_GCM_SHA256&quot; &#x5B;38]=&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;39]=&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;40]=&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_128_CBC_SHA256&quot; &#x5B;41]=&gt; string(32) &quot;TLS_DHE_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;42]=&gt; string(32) &quot;TLS_DHE_DSS_WITH_AES_128_CBC_SHA&quot; &#x5B;43]=&gt; string(29) &quot;TLS_DHE_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;44]=&gt; string(29) &quot;TLS_DHE_DSS_WITH_SEED_CBC_SHA&quot; &#x5B;45]=&gt; string(37) &quot;TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;46]=&gt; string(37) &quot;TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;47]=&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;48]=&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;49]=&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;50]=&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;51]=&gt; string(33) &quot;TLS_ECDH_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;52]=&gt; string(35) &quot;TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA&quot; &#x5B;53]=&gt; string(31) &quot;TLS_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;54]=&gt; string(31) &quot;TLS_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;55]=&gt; string(28) &quot;TLS_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;56]=&gt; string(25) &quot;TLS_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;57]=&gt; string(33) &quot;TLS_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;58]=&gt; string(33) &quot;TLS_EMPTY_RENEGOTIATION_INFO_SCSV&quot; } &#x5B;&quot;ephemeral_keys_supported&quot;]=&gt; bool(true) &#x5B;&quot;session_ticket_supported&quot;]=&gt; bool(false) &#x5B;&quot;tls_compression_supported&quot;]=&gt; bool(false) &#x5B;&quot;unknown_cipher_suite_supported&quot;]=&gt; bool(false) &#x5B;&quot;beast_vuln&quot;]=&gt; bool(false) &#x5B;&quot;able_to_detect_n_minus_one_splitting&quot;]=&gt; bool(false) &#x5B;&quot;insecure_cipher_suites&quot;]=&gt; object(stdClass)#2 (7) { &#x5B;&quot;TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } } &#x5B;&quot;tls_version&quot;]=&gt; string(7) &quot;TLS 1.2&quot; &#x5B;&quot;rating&quot;]=&gt; string(3) &quot;Bad&quot; }</pre> <p>Ausgabe Ubuntu 16.04:</p> <pre class="brush: plain; title: ; notranslate" title="">class stdClass#1 (10) { public $given_cipher_suites =&gt; array(79) { &#x5B;0] =&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;1] =&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;2] =&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;3] =&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;4] =&gt; string(34) &quot;TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;5] =&gt; string(36) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA&quot; &#x5B;6] =&gt; string(34) &quot;TLS_DH_DSS_WITH_AES_256_GCM_SHA384&quot; &#x5B;7] =&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_256_GCM_SHA384&quot; &#x5B;8] =&gt; string(34) &quot;TLS_DH_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;9] =&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;10] =&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_256_CBC_SHA256&quot; &#x5B;11] =&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_256_CBC_SHA256&quot; &#x5B;12] =&gt; string(34) &quot;TLS_DH_RSA_WITH_AES_256_CBC_SHA256&quot; &#x5B;13] =&gt; string(34) &quot;TLS_DH_DSS_WITH_AES_256_CBC_SHA256&quot; &#x5B;14] =&gt; string(32) &quot;TLS_DHE_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;15] =&gt; string(32) &quot;TLS_DHE_DSS_WITH_AES_256_CBC_SHA&quot; &#x5B;16] =&gt; string(31) &quot;TLS_DH_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;17] =&gt; string(31) &quot;TLS_DH_DSS_WITH_AES_256_CBC_SHA&quot; &#x5B;18] =&gt; string(37) &quot;TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;19] =&gt; string(37) &quot;TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;20] =&gt; string(36) &quot;TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;21] =&gt; string(36) &quot;TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;22] =&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;23] =&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;24] =&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;25] =&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;26] =&gt; string(33) &quot;TLS_ECDH_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;27] =&gt; string(35) &quot;TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA&quot; &#x5B;28] =&gt; string(31) &quot;TLS_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;29] =&gt; string(31) &quot;TLS_RSA_WITH_AES_256_CBC_SHA256&quot; &#x5B;30] =&gt; string(28) &quot;TLS_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;31] =&gt; string(33) &quot;TLS_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;32] =&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;33] =&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;34] =&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;35] =&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;36] =&gt; string(34) &quot;TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;37] =&gt; string(36) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA&quot; &#x5B;38] =&gt; string(34) &quot;TLS_DH_DSS_WITH_AES_128_GCM_SHA256&quot; &#x5B;39] =&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_128_GCM_SHA256&quot; &#x5B;40] =&gt; string(34) &quot;TLS_DH_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;41] =&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;42] =&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;43] =&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_128_CBC_SHA256&quot; &#x5B;44] =&gt; string(34) &quot;TLS_DH_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;45] =&gt; string(34) &quot;TLS_DH_DSS_WITH_AES_128_CBC_SHA256&quot; &#x5B;46] =&gt; string(32) &quot;TLS_DHE_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;47] =&gt; string(32) &quot;TLS_DHE_DSS_WITH_AES_128_CBC_SHA&quot; &#x5B;48] =&gt; string(31) &quot;TLS_DH_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;49] =&gt; string(31) &quot;TLS_DH_DSS_WITH_AES_128_CBC_SHA&quot; &#x5B;50] =&gt; string(29) &quot;TLS_DHE_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;51] =&gt; string(29) &quot;TLS_DHE_DSS_WITH_SEED_CBC_SHA&quot; &#x5B;52] =&gt; string(28) &quot;TLS_DH_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;53] =&gt; string(28) &quot;TLS_DH_DSS_WITH_SEED_CBC_SHA&quot; &#x5B;54] =&gt; string(37) &quot;TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;55] =&gt; string(37) &quot;TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;56] =&gt; string(36) &quot;TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;57] =&gt; string(36) &quot;TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;58] =&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;59] =&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;60] =&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;61] =&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;62] =&gt; string(33) &quot;TLS_ECDH_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;63] =&gt; string(35) &quot;TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA&quot; &#x5B;64] =&gt; string(31) &quot;TLS_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;65] =&gt; string(31) &quot;TLS_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;66] =&gt; string(28) &quot;TLS_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;67] =&gt; string(25) &quot;TLS_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;68] =&gt; string(33) &quot;TLS_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;69] =&gt; string(35) &quot;TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;70] =&gt; string(37) &quot;TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;71] =&gt; string(33) &quot;TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;72] =&gt; string(33) &quot;TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;73] =&gt; string(32) &quot;TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;74] =&gt; string(32) &quot;TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;75] =&gt; string(34) &quot;TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;76] =&gt; string(36) &quot;TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;77] =&gt; string(29) &quot;TLS_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;78] =&gt; string(33) &quot;TLS_EMPTY_RENEGOTIATION_INFO_SCSV&quot; } public $ephemeral_keys_supported =&gt; bool(true) public $session_ticket_supported =&gt; bool(false) public $tls_compression_supported =&gt; bool(false) public $unknown_cipher_suite_supported =&gt; bool(false) public $beast_vuln =&gt; bool(false) public $able_to_detect_n_minus_one_splitting =&gt; bool(false) public $insecure_cipher_suites =&gt; class stdClass#2 (0) { } public $tls_version =&gt; string(7) &quot;TLS 1.2&quot; public $rating =&gt; string(13) &quot;Probably Okay&quot; }</pre> <p>&nbsp;</p> <p>TLS 1.2 ist im Payment-Bereich weiter auf dem Vormarsch, immer mehr Zahlungsanbieter setzen <strong>TLS 1.2 als Minimumversion</strong> fest. Das <a href="https://blog.pcisecuritystandards.org/migrating-from-ssl-and-early-tls">Payment Card Industry Security Standards Council (PCI SSC) hat die Frist von 2016 auf 2018 verschoben</a>. <a href="https://www.paypal.com/au/webapps/mpp/tls-http-upgrade">PayPal wird am 30. Juni 2018 TLS 1.0 und 1.1 abschalten</a>. Paysafecard wird selbiges bereits im Februar 2018 tun.</p> <p>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.</p> <p>Folgendes Script testet die TLS-Einstellungen von PHP (curl) mit Hilfe der Webseite https://www.howsmyssl.com:</p> <pre class="brush: plain; title: ; notranslate" title="">&lt;?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);</pre> <p>Die Ergebnisse:</p> <p><span id="more-6776"></span>Ubuntu 13.10: TLS 1.1 &#8222;Bad&#8220;<br /> Ubuntu 14.04: TLS 1.2 &#8222;Bad&#8220;<br /> Ubuntu 16.04: TLS 1.2 &#8222;Probably Okay&#8220;</p> <p>Ein weiterer Grund, immer up2date zu bleiben. Ubuntu 13.10 erhält seit Jahren keine Security-Updates mehr, sollte also eh nirgends mehr eingesetzt werden (besonders nicht in Payment-Systemen).</p> <p>===================================</p> <p>Hier die ausführlichen Ausgaben der 3 untersuchten Ubuntu-Versionen:</p> <p>Ausgabe Ubuntu 13.10.:</p> <pre class="brush: plain; title: ; notranslate" title="">object(stdClass)#1 (10) { &#x5B;&quot;given_cipher_suites&quot;]=&gt; array(51) { &#x5B;0]=&gt; string(34) &quot;TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;1]=&gt; string(36) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA&quot; &#x5B;2]=&gt; string(36) &quot;TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA&quot; &#x5B;3]=&gt; string(36) &quot;TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;4]=&gt; string(32) &quot;TLS_DHE_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;5]=&gt; string(32) &quot;TLS_DHE_DSS_WITH_AES_256_CBC_SHA&quot; &#x5B;6]=&gt; string(37) &quot;TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;7]=&gt; string(37) &quot;TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;8]=&gt; string(33) &quot;TLS_ECDH_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;9]=&gt; string(35) &quot;TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA&quot; &#x5B;10]=&gt; string(28) &quot;TLS_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;11]=&gt; string(33) &quot;TLS_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;12]=&gt; string(35) &quot;TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;13]=&gt; string(37) &quot;TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;14]=&gt; string(37) &quot;TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;15]=&gt; string(37) &quot;TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;16]=&gt; string(33) &quot;TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;17]=&gt; string(33) &quot;TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;18]=&gt; string(34) &quot;TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;19]=&gt; string(36) &quot;TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;20]=&gt; string(29) &quot;TLS_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;21]=&gt; string(34) &quot;TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;22]=&gt; string(36) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA&quot; &#x5B;23]=&gt; string(36) &quot;TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA&quot; &#x5B;24]=&gt; string(36) &quot;TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;25]=&gt; string(32) &quot;TLS_DHE_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;26]=&gt; string(32) &quot;TLS_DHE_DSS_WITH_AES_128_CBC_SHA&quot; &#x5B;27]=&gt; string(29) &quot;TLS_DHE_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;28]=&gt; string(29) &quot;TLS_DHE_DSS_WITH_SEED_CBC_SHA&quot; &#x5B;29]=&gt; string(37) &quot;TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;30]=&gt; string(37) &quot;TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;31]=&gt; string(33) &quot;TLS_ECDH_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;32]=&gt; string(35) &quot;TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA&quot; &#x5B;33]=&gt; string(28) &quot;TLS_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;34]=&gt; string(25) &quot;TLS_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;35]=&gt; string(33) &quot;TLS_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;36]=&gt; string(30) &quot;TLS_ECDHE_RSA_WITH_RC4_128_SHA&quot; &#x5B;37]=&gt; string(32) &quot;TLS_ECDHE_ECDSA_WITH_RC4_128_SHA&quot; &#x5B;38]=&gt; string(29) &quot;TLS_ECDH_RSA_WITH_RC4_128_SHA&quot; &#x5B;39]=&gt; string(31) &quot;TLS_ECDH_ECDSA_WITH_RC4_128_SHA&quot; &#x5B;40]=&gt; string(24) &quot;TLS_RSA_WITH_RC4_128_SHA&quot; &#x5B;41]=&gt; string(24) &quot;TLS_RSA_WITH_RC4_128_MD5&quot; &#x5B;42]=&gt; string(28) &quot;TLS_DHE_RSA_WITH_DES_CBC_SHA&quot; &#x5B;43]=&gt; string(28) &quot;TLS_DHE_DSS_WITH_DES_CBC_SHA&quot; &#x5B;44]=&gt; string(24) &quot;TLS_RSA_WITH_DES_CBC_SHA&quot; &#x5B;45]=&gt; string(37) &quot;TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA&quot; &#x5B;46]=&gt; string(37) &quot;TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA&quot; &#x5B;47]=&gt; string(33) &quot;TLS_RSA_EXPORT_WITH_DES40_CBC_SHA&quot; &#x5B;48]=&gt; string(34) &quot;TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5&quot; &#x5B;49]=&gt; string(30) &quot;TLS_RSA_EXPORT_WITH_RC4_40_MD5&quot; &#x5B;50]=&gt; string(33) &quot;TLS_EMPTY_RENEGOTIATION_INFO_SCSV&quot; } &#x5B;&quot;ephemeral_keys_supported&quot;]=&gt; bool(true) &#x5B;&quot;session_ticket_supported&quot;]=&gt; bool(false) &#x5B;&quot;tls_compression_supported&quot;]=&gt; bool(false) &#x5B;&quot;unknown_cipher_suite_supported&quot;]=&gt; bool(false) &#x5B;&quot;beast_vuln&quot;]=&gt; bool(false) &#x5B;&quot;able_to_detect_n_minus_one_splitting&quot;]=&gt; bool(false) &#x5B;&quot;insecure_cipher_suites&quot;]=&gt; object(stdClass)#2 (23) { &#x5B;&quot;TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_DHE_DSS_WITH_DES_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_DHE_RSA_WITH_DES_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDHE_ECDSA_WITH_RC4_128_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDHE_RSA_WITH_RC4_128_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDH_ECDSA_WITH_RC4_128_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDH_RSA_WITH_RC4_128_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_RSA_EXPORT_WITH_DES40_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_RSA_EXPORT_WITH_RC4_40_MD5&quot;]=&gt; array(2) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; &#x5B;1]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_RSA_WITH_DES_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(49) &quot;uses keys smaller than 128 bits in its encryption&quot; } &#x5B;&quot;TLS_RSA_WITH_RC4_128_MD5&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_RSA_WITH_RC4_128_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(48) &quot;uses RC4 which has insecure biases in its output&quot; } &#x5B;&quot;TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } } &#x5B;&quot;tls_version&quot;]=&gt; string(7) &quot;TLS 1.1&quot; &#x5B;&quot;rating&quot;]=&gt; string(3) &quot;Bad&quot; }</pre> <p>Ausgabe Ubuntu 14.04:</p> <pre class="brush: plain; title: ; notranslate" title="">object(stdClass)#1 (10) { &#x5B;&quot;given_cipher_suites&quot;]=&gt; array(59) { &#x5B;0]=&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;1]=&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;2]=&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;3]=&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;4]=&gt; string(34) &quot;TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;5]=&gt; string(36) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA&quot; &#x5B;6]=&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_256_GCM_SHA384&quot; &#x5B;7]=&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;8]=&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_256_CBC_SHA256&quot; &#x5B;9]=&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_256_CBC_SHA256&quot; &#x5B;10]=&gt; string(32) &quot;TLS_DHE_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;11]=&gt; string(32) &quot;TLS_DHE_DSS_WITH_AES_256_CBC_SHA&quot; &#x5B;12]=&gt; string(37) &quot;TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;13]=&gt; string(37) &quot;TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;14]=&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;15]=&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;16]=&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;17]=&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;18]=&gt; string(33) &quot;TLS_ECDH_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;19]=&gt; string(35) &quot;TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA&quot; &#x5B;20]=&gt; string(31) &quot;TLS_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;21]=&gt; string(31) &quot;TLS_RSA_WITH_AES_256_CBC_SHA256&quot; &#x5B;22]=&gt; string(28) &quot;TLS_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;23]=&gt; string(33) &quot;TLS_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;24]=&gt; string(35) &quot;TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;25]=&gt; string(37) &quot;TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;26]=&gt; string(33) &quot;TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;27]=&gt; string(33) &quot;TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;28]=&gt; string(34) &quot;TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;29]=&gt; string(36) &quot;TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;30]=&gt; string(29) &quot;TLS_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;31]=&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;32]=&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;33]=&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;34]=&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;35]=&gt; string(34) &quot;TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;36]=&gt; string(36) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA&quot; &#x5B;37]=&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_128_GCM_SHA256&quot; &#x5B;38]=&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;39]=&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;40]=&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_128_CBC_SHA256&quot; &#x5B;41]=&gt; string(32) &quot;TLS_DHE_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;42]=&gt; string(32) &quot;TLS_DHE_DSS_WITH_AES_128_CBC_SHA&quot; &#x5B;43]=&gt; string(29) &quot;TLS_DHE_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;44]=&gt; string(29) &quot;TLS_DHE_DSS_WITH_SEED_CBC_SHA&quot; &#x5B;45]=&gt; string(37) &quot;TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;46]=&gt; string(37) &quot;TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;47]=&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;48]=&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;49]=&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;50]=&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;51]=&gt; string(33) &quot;TLS_ECDH_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;52]=&gt; string(35) &quot;TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA&quot; &#x5B;53]=&gt; string(31) &quot;TLS_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;54]=&gt; string(31) &quot;TLS_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;55]=&gt; string(28) &quot;TLS_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;56]=&gt; string(25) &quot;TLS_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;57]=&gt; string(33) &quot;TLS_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;58]=&gt; string(33) &quot;TLS_EMPTY_RENEGOTIATION_INFO_SCSV&quot; } &#x5B;&quot;ephemeral_keys_supported&quot;]=&gt; bool(true) &#x5B;&quot;session_ticket_supported&quot;]=&gt; bool(false) &#x5B;&quot;tls_compression_supported&quot;]=&gt; bool(false) &#x5B;&quot;unknown_cipher_suite_supported&quot;]=&gt; bool(false) &#x5B;&quot;beast_vuln&quot;]=&gt; bool(false) &#x5B;&quot;able_to_detect_n_minus_one_splitting&quot;]=&gt; bool(false) &#x5B;&quot;insecure_cipher_suites&quot;]=&gt; object(stdClass)#2 (7) { &#x5B;&quot;TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } &#x5B;&quot;TLS_RSA_WITH_3DES_EDE_CBC_SHA&quot;]=&gt; array(1) { &#x5B;0]=&gt; string(113) &quot;uses 3DES which is vulnerable to the Sweet32 attack but was not configured as a fallback in the ciphersuite order&quot; } } &#x5B;&quot;tls_version&quot;]=&gt; string(7) &quot;TLS 1.2&quot; &#x5B;&quot;rating&quot;]=&gt; string(3) &quot;Bad&quot; }</pre> <p>Ausgabe Ubuntu 16.04:</p> <pre class="brush: plain; title: ; notranslate" title="">class stdClass#1 (10) { public $given_cipher_suites =&gt; array(79) { &#x5B;0] =&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;1] =&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;2] =&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;3] =&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;4] =&gt; string(34) &quot;TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;5] =&gt; string(36) &quot;TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA&quot; &#x5B;6] =&gt; string(34) &quot;TLS_DH_DSS_WITH_AES_256_GCM_SHA384&quot; &#x5B;7] =&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_256_GCM_SHA384&quot; &#x5B;8] =&gt; string(34) &quot;TLS_DH_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;9] =&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;10] =&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_256_CBC_SHA256&quot; &#x5B;11] =&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_256_CBC_SHA256&quot; &#x5B;12] =&gt; string(34) &quot;TLS_DH_RSA_WITH_AES_256_CBC_SHA256&quot; &#x5B;13] =&gt; string(34) &quot;TLS_DH_DSS_WITH_AES_256_CBC_SHA256&quot; &#x5B;14] =&gt; string(32) &quot;TLS_DHE_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;15] =&gt; string(32) &quot;TLS_DHE_DSS_WITH_AES_256_CBC_SHA&quot; &#x5B;16] =&gt; string(31) &quot;TLS_DH_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;17] =&gt; string(31) &quot;TLS_DH_DSS_WITH_AES_256_CBC_SHA&quot; &#x5B;18] =&gt; string(37) &quot;TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;19] =&gt; string(37) &quot;TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;20] =&gt; string(36) &quot;TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;21] =&gt; string(36) &quot;TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;22] =&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;23] =&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;24] =&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;25] =&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384&quot; &#x5B;26] =&gt; string(33) &quot;TLS_ECDH_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;27] =&gt; string(35) &quot;TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA&quot; &#x5B;28] =&gt; string(31) &quot;TLS_RSA_WITH_AES_256_GCM_SHA384&quot; &#x5B;29] =&gt; string(31) &quot;TLS_RSA_WITH_AES_256_CBC_SHA256&quot; &#x5B;30] =&gt; string(28) &quot;TLS_RSA_WITH_AES_256_CBC_SHA&quot; &#x5B;31] =&gt; string(33) &quot;TLS_RSA_WITH_CAMELLIA_256_CBC_SHA&quot; &#x5B;32] =&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;33] =&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;34] =&gt; string(37) &quot;TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;35] =&gt; string(39) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;36] =&gt; string(34) &quot;TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;37] =&gt; string(36) &quot;TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA&quot; &#x5B;38] =&gt; string(34) &quot;TLS_DH_DSS_WITH_AES_128_GCM_SHA256&quot; &#x5B;39] =&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_128_GCM_SHA256&quot; &#x5B;40] =&gt; string(34) &quot;TLS_DH_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;41] =&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;42] =&gt; string(35) &quot;TLS_DHE_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;43] =&gt; string(35) &quot;TLS_DHE_DSS_WITH_AES_128_CBC_SHA256&quot; &#x5B;44] =&gt; string(34) &quot;TLS_DH_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;45] =&gt; string(34) &quot;TLS_DH_DSS_WITH_AES_128_CBC_SHA256&quot; &#x5B;46] =&gt; string(32) &quot;TLS_DHE_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;47] =&gt; string(32) &quot;TLS_DHE_DSS_WITH_AES_128_CBC_SHA&quot; &#x5B;48] =&gt; string(31) &quot;TLS_DH_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;49] =&gt; string(31) &quot;TLS_DH_DSS_WITH_AES_128_CBC_SHA&quot; &#x5B;50] =&gt; string(29) &quot;TLS_DHE_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;51] =&gt; string(29) &quot;TLS_DHE_DSS_WITH_SEED_CBC_SHA&quot; &#x5B;52] =&gt; string(28) &quot;TLS_DH_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;53] =&gt; string(28) &quot;TLS_DH_DSS_WITH_SEED_CBC_SHA&quot; &#x5B;54] =&gt; string(37) &quot;TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;55] =&gt; string(37) &quot;TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;56] =&gt; string(36) &quot;TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;57] =&gt; string(36) &quot;TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;58] =&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;59] =&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;60] =&gt; string(36) &quot;TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;61] =&gt; string(38) &quot;TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;62] =&gt; string(33) &quot;TLS_ECDH_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;63] =&gt; string(35) &quot;TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA&quot; &#x5B;64] =&gt; string(31) &quot;TLS_RSA_WITH_AES_128_GCM_SHA256&quot; &#x5B;65] =&gt; string(31) &quot;TLS_RSA_WITH_AES_128_CBC_SHA256&quot; &#x5B;66] =&gt; string(28) &quot;TLS_RSA_WITH_AES_128_CBC_SHA&quot; &#x5B;67] =&gt; string(25) &quot;TLS_RSA_WITH_SEED_CBC_SHA&quot; &#x5B;68] =&gt; string(33) &quot;TLS_RSA_WITH_CAMELLIA_128_CBC_SHA&quot; &#x5B;69] =&gt; string(35) &quot;TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;70] =&gt; string(37) &quot;TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;71] =&gt; string(33) &quot;TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;72] =&gt; string(33) &quot;TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;73] =&gt; string(32) &quot;TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;74] =&gt; string(32) &quot;TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;75] =&gt; string(34) &quot;TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;76] =&gt; string(36) &quot;TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;77] =&gt; string(29) &quot;TLS_RSA_WITH_3DES_EDE_CBC_SHA&quot; &#x5B;78] =&gt; string(33) &quot;TLS_EMPTY_RENEGOTIATION_INFO_SCSV&quot; } public $ephemeral_keys_supported =&gt; bool(true) public $session_ticket_supported =&gt; bool(false) public $tls_compression_supported =&gt; bool(false) public $unknown_cipher_suite_supported =&gt; bool(false) public $beast_vuln =&gt; bool(false) public $able_to_detect_n_minus_one_splitting =&gt; bool(false) public $insecure_cipher_suites =&gt; class stdClass#2 (0) { } public $tls_version =&gt; string(7) &quot;TLS 1.2&quot; public $rating =&gt; string(13) &quot;Probably Okay&quot; }</pre> <p>&nbsp;</p> https://phpgangsta.de/php-curl-und-tls-1-2-als-minimum/feed 2 HTTP Range-Request Header in PHP parsen https://phpgangsta.de/http-range-request-header-in-php-parsen https://phpgangsta.de/http-range-request-header-in-php-parsen#comments Tue, 16 May 2017 19:44:52 +0000 https://www.phpgangsta.de/?p=6756 <p>Hört sich eigentlich nach einer einfachen Aufgabe an: HTTP-Clients können beim Download nur Teile einer Datei anfragen, beispielsweise die ersten 500 Bytes eines Videos. Der Server announced die Unterstützung dieses Partial-Downloads mit dem Response-Header:</p> <pre class="brush: plain; title: ; notranslate" title="">Accept-Ranges: bytes</pre> <p>Ein HTTP-Client, der partielle Downloads unterstützt kann nun mit dem folgenden Header die ersten 500 Bytes anfordern:</p> <pre class="brush: plain; title: ; notranslate" title="">Range: bytes=0-500</pre> <p>Ein Webserver, der direkt die Datei ausliefert, tut wie ihm befohlen. Wird die angefragte Datei jedoch von einem PHP-Script ausgeliefert, muss im PHP-Script dieser Header geparst werden, damit man in PHP weiß wie viele Bytes man ausliefern soll.</p> <p>Durchsucht man das Internet nach einer Antwort, findet man sehr häufig folgende Lösungen. <strong>Achtung</strong>, nicht dem RFC <a href="https://tools.ietf.org/html/draft-ietf-http-range-retrieval-00">https://tools.ietf.org/html/draft-ietf-http-range-retrieval-00</a> entsprechend, nicht unbedingt nutzen:</p> <p><span id="more-6756"></span>http://stackoverflow.com/questions/2209204/parsing-http-range-header-in-php</p> <pre class="brush: plain; title: ; notranslate" title="">function getRanges() { return preg_match('/^bytes=((\d*-\d*,? ?)+)$/', @$_SERVER&#x5B;'HTTP_RANGE'], $matches) ? $matches&#x5B;1] : array(); }</pre> <p>https://gist.github.com/codler/3906826</p> <pre class="brush: plain; title: ; notranslate" title="">preg_match('/bytes=(d+)-(d+)/', $_SERVER&#x5B;'HTTP_RANGE'], $matches)</pre> <pre>https://licson.net/post/stream-videos-php/</pre> <pre class="brush: plain; title: ; notranslate" title="">// Parse the range header to get the byte offset $ranges = array_map( 'intval', // Parse the parts into integer explode( '-', // The range separator substr($_SERVER&#x5B;'HTTP_RANGE'], 6) // Skip the `bytes=` part of the header ) ); // If the last range param is empty, it means the EOF (End of File) if(!$ranges&#x5B;1]){ $ranges&#x5B;1] = $size - 1; }</pre> <p>http://stackoverflow.com/questions/2209204/parsing-http-range-header-in-php</p> <pre class="brush: plain; title: ; notranslate" title="">if (isset($_SERVER&#x5B;'HTTP_RANGE'])) { if (!preg_match('^bytes=\d*-\d*(,\d*-\d*)*$', $_SERVER&#x5B;'HTTP_RANGE'])) { header('HTTP/1.1 416 Requested Range Not Satisfiable'); header('Content-Range: bytes */' . filelength); // Required in 416. exit; } $ranges = explode(',', substr($_SERVER&#x5B;'HTTP_RANGE'], 6)); foreach ($ranges as $range) { $parts = explode('-', $range); $start = $parts&#x5B;0]; // If this is empty, this should be 0. $end = $parts&#x5B;1]; // If this is empty or greater than than filelength - 1, this should be filelength - 1. if ($start &gt; $end) { header('HTTP/1.1 416 Requested Range Not Satisfiable'); header('Content-Range: bytes */' . filelength); // Required in 416. exit; } // ... } }</pre> <p>All diese Beispiele unterstützen jedoch nicht die volle Funktionalität, die der Range-Header bietet. Folgende Header sind beispielsweise möglich:</p> <p>Range: bytes=0-500                 // Die ersten 500 Bytes<br /> Range: bytes=-500                  // Die letzten 500 Bytes (nicht 0-500!)<br /> Range: bytes=500-                  // Ab Byte 500 bis zum Ende<br /> Range: bytes=0-500,1000-1499,-200  // Die ersten 500 Bytes, von Byte 1000 bis 1499, und die letzten 200 Bytes</p> <p>Die meisten Code-Snippets, die man im Internet findet, unterstützen nur Beispiel 1, bei dem ein StartByte und ein EndByte explizit hingeschrieben wird.<br /> Manche unterstützen eine fehlende Angabe, wie in Beispiel 2, und setzen es dann auf 0, was aber falsch ist!<br /> Fast kein Code-Snippet unterstützt die kommaseparierte Angabe von mehreren Ranges. Man fragt sich natürlich auch welche Clients so etwas brauchen und machen, aber theoretisch geht es, und die Applikation sollte im Idealfall damit umgehen können.</p> <p>Ich will hier nur auf die Problematik hinweisen, eine vollständige Funktion zu erstellen, die alle 4 möglichen Varianten unterstützt, bleibt dem geneigten Leser überlassen 🙂</p> <p>Wer sich mit dem Thema beschäftigt, sollte auch die <a href="https://www.stevesouders.com/blog/2013/04/21/html5-video-bytes-on-ios/">Beobachtungen von Steve Souders lesen, iOS macht ganz komische Requests bei Videos</a>&#8230;</p> <p>Hört sich eigentlich nach einer einfachen Aufgabe an: HTTP-Clients können beim Download nur Teile einer Datei anfragen, beispielsweise die ersten 500 Bytes eines Videos. Der Server announced die Unterstützung dieses Partial-Downloads mit dem Response-Header:</p> <pre class="brush: plain; title: ; notranslate" title="">Accept-Ranges: bytes</pre> <p>Ein HTTP-Client, der partielle Downloads unterstützt kann nun mit dem folgenden Header die ersten 500 Bytes anfordern:</p> <pre class="brush: plain; title: ; notranslate" title="">Range: bytes=0-500</pre> <p>Ein Webserver, der direkt die Datei ausliefert, tut wie ihm befohlen. Wird die angefragte Datei jedoch von einem PHP-Script ausgeliefert, muss im PHP-Script dieser Header geparst werden, damit man in PHP weiß wie viele Bytes man ausliefern soll.</p> <p>Durchsucht man das Internet nach einer Antwort, findet man sehr häufig folgende Lösungen. <strong>Achtung</strong>, nicht dem RFC <a href="https://tools.ietf.org/html/draft-ietf-http-range-retrieval-00">https://tools.ietf.org/html/draft-ietf-http-range-retrieval-00</a> entsprechend, nicht unbedingt nutzen:</p> <p><span id="more-6756"></span>http://stackoverflow.com/questions/2209204/parsing-http-range-header-in-php</p> <pre class="brush: plain; title: ; notranslate" title="">function getRanges() { return preg_match('/^bytes=((\d*-\d*,? ?)+)$/', @$_SERVER&#x5B;'HTTP_RANGE'], $matches) ? $matches&#x5B;1] : array(); }</pre> <p>https://gist.github.com/codler/3906826</p> <pre class="brush: plain; title: ; notranslate" title="">preg_match('/bytes=(d+)-(d+)/', $_SERVER&#x5B;'HTTP_RANGE'], $matches)</pre> <pre>https://licson.net/post/stream-videos-php/</pre> <pre class="brush: plain; title: ; notranslate" title="">// Parse the range header to get the byte offset $ranges = array_map( 'intval', // Parse the parts into integer explode( '-', // The range separator substr($_SERVER&#x5B;'HTTP_RANGE'], 6) // Skip the `bytes=` part of the header ) ); // If the last range param is empty, it means the EOF (End of File) if(!$ranges&#x5B;1]){ $ranges&#x5B;1] = $size - 1; }</pre> <p>http://stackoverflow.com/questions/2209204/parsing-http-range-header-in-php</p> <pre class="brush: plain; title: ; notranslate" title="">if (isset($_SERVER&#x5B;'HTTP_RANGE'])) { if (!preg_match('^bytes=\d*-\d*(,\d*-\d*)*$', $_SERVER&#x5B;'HTTP_RANGE'])) { header('HTTP/1.1 416 Requested Range Not Satisfiable'); header('Content-Range: bytes */' . filelength); // Required in 416. exit; } $ranges = explode(',', substr($_SERVER&#x5B;'HTTP_RANGE'], 6)); foreach ($ranges as $range) { $parts = explode('-', $range); $start = $parts&#x5B;0]; // If this is empty, this should be 0. $end = $parts&#x5B;1]; // If this is empty or greater than than filelength - 1, this should be filelength - 1. if ($start &gt; $end) { header('HTTP/1.1 416 Requested Range Not Satisfiable'); header('Content-Range: bytes */' . filelength); // Required in 416. exit; } // ... } }</pre> <p>All diese Beispiele unterstützen jedoch nicht die volle Funktionalität, die der Range-Header bietet. Folgende Header sind beispielsweise möglich:</p> <p>Range: bytes=0-500                 // Die ersten 500 Bytes<br /> Range: bytes=-500                  // Die letzten 500 Bytes (nicht 0-500!)<br /> Range: bytes=500-                  // Ab Byte 500 bis zum Ende<br /> Range: bytes=0-500,1000-1499,-200  // Die ersten 500 Bytes, von Byte 1000 bis 1499, und die letzten 200 Bytes</p> <p>Die meisten Code-Snippets, die man im Internet findet, unterstützen nur Beispiel 1, bei dem ein StartByte und ein EndByte explizit hingeschrieben wird.<br /> Manche unterstützen eine fehlende Angabe, wie in Beispiel 2, und setzen es dann auf 0, was aber falsch ist!<br /> Fast kein Code-Snippet unterstützt die kommaseparierte Angabe von mehreren Ranges. Man fragt sich natürlich auch welche Clients so etwas brauchen und machen, aber theoretisch geht es, und die Applikation sollte im Idealfall damit umgehen können.</p> <p>Ich will hier nur auf die Problematik hinweisen, eine vollständige Funktion zu erstellen, die alle 4 möglichen Varianten unterstützt, bleibt dem geneigten Leser überlassen 🙂</p> <p>Wer sich mit dem Thema beschäftigt, sollte auch die <a href="https://www.stevesouders.com/blog/2013/04/21/html5-video-bytes-on-ios/">Beobachtungen von Steve Souders lesen, iOS macht ganz komische Requests bei Videos</a>&#8230;</p> https://phpgangsta.de/http-range-request-header-in-php-parsen/feed 5 Blog mittels Let’s Encrypt dauerhaft via SSL erreichbar https://phpgangsta.de/blog-mittels-lets-encrypt-dauerhaft-via-ssl-erreichbar https://phpgangsta.de/blog-mittels-lets-encrypt-dauerhaft-via-ssl-erreichbar#comments Thu, 04 May 2017 08:04:43 +0000 https://www.phpgangsta.de/?p=6738 <p>Nach einer viel zu langen Pause habe ich wieder etwas Luft für meinen Blog. Endlich&#8230;</p> <p>Ein <a href="https://www.phpgangsta.de/client-zertifikate-als-sicherer-login-ersatz/comment-page-1#comment-2193359">Kommentar von YamYamL</a> hat mich daran erinnert, die HTTPS-Umstellung meiner Domain endlich abzuschliessen, und noch einen Endspurt einzulegen, die Domain verschlüsselt erreichbar zu machen.</p> <p>Wäre hier nur ein einfaches WordPress-Blog gehostet, wäre es vermutlich eine Sache von einer Stunde gewesen. Ein Zertifikat besorgen, WordPress umkonfigurieren (Einstellungen -&gt; Allgemein), und alle selbst gehosteten Bilder in den Posts in der Datenbank ändern von http://www.phpgangsta.de auf https://www.phpgangsta.de (ich habe das WordPress-Plugin <a href="https://de.wordpress.org/plugins/better-search-replace/">Better Search &amp; Replace</a> genutzt). Aber&#8230;</p> <p>Leider ist unter phpgangsta.de nicht nur dieser Blog erreichbar, sondern auch zig andere Projekte, selbst geschriebenes Zeug, teils 10 Jahre alt, und nicht HTTPS-fähig. Es ist also doch etwas mehr Arbeit gewesen, als &#8222;nur&#8220; den Blog auf HTTPS umzustellen.<br /> Der Port 443 war bereits seit langem offen, aber mit einem selbst signierten Zertifikat versehen. Da ich gern Let&#8217;s Encrypt (LE) verwende, LE aber keine Wildcards erlaubt (dann wäre es verhältnismäßig einfach gewesen, einfach für alle Subdomains ein zentrales Zertifikat zu hinterlegen), musste ich mein Domain-Verwaltungs-Reseller-Tool <a href="https://www.froxlor.org/">froxlor</a>, das ich hier laufen habe, erstmal updaten auf eine Version, die LE unterstützt, so dass ich nun für einzelne Subdomains SSL aktivieren kann, und die Zertifikate auch via Cronjob immer brav erneuert werden.</p> <p>Nicht vergessen darf man: In den Google Webmaster-Tools eine neue Property anlegen, den WordPress-Cache zu leeren falls man ein Cache-Plugin verwendet, Analytics umzustellen falls man es verwendet, und alle WordPress-Plugins prüfen dass sie HTTPS-fähig sind (bei mir waren sie das anscheinend dankenswerterweise).</p> <p>Ich hoffe ich habe die meisten Mixed-Content-Probleme gelöst, könnte sein dass es noch irgendwo externen Content gibt (Bilder), der noch via HTTP eingebunden ist. Meldet ihn gern bei mir, sollte das Bild via HTTPS erreichbar sein, fixe ich das schnell, oder lade es auf meinen Space.</p> <p>All in All durchaus einiges an Aufwand in den letzten Tagen und Wochen, aber seit heute ist der Blog nun via HTTPS verfügbar, incl. Let&#8217;s Encrypt Zertifikat, HTTP-&gt;HTTPS Weiterleitung und <a href="https://de.wikipedia.org/wiki/HTTP_Strict_Transport_Security">HSTS Header</a>. Diverse Subdomains und andere (kleinere) Domains muss ich in den nächsten Wochen nach und nach umstellen, das kann noch etwas dauern.</p> <p>Nach einer viel zu langen Pause habe ich wieder etwas Luft für meinen Blog. Endlich&#8230;</p> <p>Ein <a href="https://www.phpgangsta.de/client-zertifikate-als-sicherer-login-ersatz/comment-page-1#comment-2193359">Kommentar von YamYamL</a> hat mich daran erinnert, die HTTPS-Umstellung meiner Domain endlich abzuschliessen, und noch einen Endspurt einzulegen, die Domain verschlüsselt erreichbar zu machen.</p> <p>Wäre hier nur ein einfaches WordPress-Blog gehostet, wäre es vermutlich eine Sache von einer Stunde gewesen. Ein Zertifikat besorgen, WordPress umkonfigurieren (Einstellungen -&gt; Allgemein), und alle selbst gehosteten Bilder in den Posts in der Datenbank ändern von http://www.phpgangsta.de auf https://www.phpgangsta.de (ich habe das WordPress-Plugin <a href="https://de.wordpress.org/plugins/better-search-replace/">Better Search &amp; Replace</a> genutzt). Aber&#8230;</p> <p>Leider ist unter phpgangsta.de nicht nur dieser Blog erreichbar, sondern auch zig andere Projekte, selbst geschriebenes Zeug, teils 10 Jahre alt, und nicht HTTPS-fähig. Es ist also doch etwas mehr Arbeit gewesen, als &#8222;nur&#8220; den Blog auf HTTPS umzustellen.<br /> Der Port 443 war bereits seit langem offen, aber mit einem selbst signierten Zertifikat versehen. Da ich gern Let&#8217;s Encrypt (LE) verwende, LE aber keine Wildcards erlaubt (dann wäre es verhältnismäßig einfach gewesen, einfach für alle Subdomains ein zentrales Zertifikat zu hinterlegen), musste ich mein Domain-Verwaltungs-Reseller-Tool <a href="https://www.froxlor.org/">froxlor</a>, das ich hier laufen habe, erstmal updaten auf eine Version, die LE unterstützt, so dass ich nun für einzelne Subdomains SSL aktivieren kann, und die Zertifikate auch via Cronjob immer brav erneuert werden.</p> <p>Nicht vergessen darf man: In den Google Webmaster-Tools eine neue Property anlegen, den WordPress-Cache zu leeren falls man ein Cache-Plugin verwendet, Analytics umzustellen falls man es verwendet, und alle WordPress-Plugins prüfen dass sie HTTPS-fähig sind (bei mir waren sie das anscheinend dankenswerterweise).</p> <p>Ich hoffe ich habe die meisten Mixed-Content-Probleme gelöst, könnte sein dass es noch irgendwo externen Content gibt (Bilder), der noch via HTTP eingebunden ist. Meldet ihn gern bei mir, sollte das Bild via HTTPS erreichbar sein, fixe ich das schnell, oder lade es auf meinen Space.</p> <p>All in All durchaus einiges an Aufwand in den letzten Tagen und Wochen, aber seit heute ist der Blog nun via HTTPS verfügbar, incl. Let&#8217;s Encrypt Zertifikat, HTTP-&gt;HTTPS Weiterleitung und <a href="https://de.wikipedia.org/wiki/HTTP_Strict_Transport_Security">HSTS Header</a>. Diverse Subdomains und andere (kleinere) Domains muss ich in den nächsten Wochen nach und nach umstellen, das kann noch etwas dauern.</p> https://phpgangsta.de/blog-mittels-lets-encrypt-dauerhaft-via-ssl-erreichbar/feed 5 PHP 7: Migration eines Projekts https://phpgangsta.de/php-7-migration-eines-projekts https://phpgangsta.de/php-7-migration-eines-projekts#comments Sat, 24 Oct 2015 16:30:59 +0000 http://www.phpgangsta.de/?p=6697 <p><img decoding="async" class="alignright wp-image-6709" src="https://www.phpgangsta.de/wp-content/uploads/php7.png" alt="PHP 7" width="213" height="102" srcset="https://phpgangsta.de/wp-content/uploads/php7.png 238w, https://phpgangsta.de/wp-content/uploads/php7-150x72.png 150w" sizes="(max-width: 213px) 100vw, 213px" />Noch knapp einen Monat warten, dann erscheint <del>das Christkind</del> PHP7! Was gibt es also schöneres als sich damit zu beschäftigen und erste Erfahrungen zu sammeln?</p> <p>Im Januar habe ich mir speziell den <a href="https://www.phpgangsta.de/aktueller-stand-von-php-7-deutlich-geringerer-arbeitsspeicherverbrauch">Arbeitsspeicherverbrauch von PHP 7</a> angeschaut, die ChangeLogs verinnerlicht, es kompiliert und ein paar Testzeilen ausgeführt. Das lief schon sehr gut, aber um größere Projekte laufen zu lassen mangelte es noch an einigen Extensions. Außerdem wollte ich ein Zend Framework 1 Projekt testen, und ZF1 war zu dem Zeitpunkt noch nicht PHP 7-kompatibel.</p> <p>Doch das hat sich geändert. ZF1 ist seit Mai 2015 mit <a href="http://framework.zend.com/blog/zend-framework-1-12-12-released.html" target="_blank">Version 1.12.12 PHP 7 kompatibel</a>, und auch die von mir benötigten Extensions wurden umgebaut, sodass es nun PHP 7-kompatible Branches vieler Extensions auf Github gibt.</p> <p>Die Vorgehendweise: Neueste PHP 7 Version herunterladen, kompilieren, Extensions herunterladen, kompilieren, und dann SPASS HABEN!</p> <h3>Also los! PHP 7 RC5 kompilieren</h3> <p><span id="more-6697"></span></p> <pre class="brush: bash; title: ; notranslate" title="">wget https://downloads.php.net/~ab/php-7.0.0RC5.tar.gz tar -xzvf php-7.0.0RC5.tar.gz cd php-7.0.0RC5/ ./configure --prefix=/usr/local/php7.0.0RC5 --with-zlib --with-config-file-path=/usr/local/php7.0.0RC5/etc --enable-mbstring --with-mysql --with-mysqli --with-pdo-mysql --enable-zip --with-imap --with-kerberos --with-imap-ssl --with-openssl --with-jpeg-dir --with-gd --with-gettext --with-freetype-dir --enable-ftp --with-pspell --with-curl make make test sudo make install /usr/local/php7.0.0RC5/bin/php -v /usr/local/php7.0.0RC5/bin/php -m /usr/local/php7.0.0RC5/bin/php -i</pre> <p>Funktioniert wunderbar! Weiter gehts.</p> <h3>Extensions memcached, gearman und apcu</h3> <p>Diese 3 Extensions benötige ich für das Projekt. Laut <a href="http://gophp7.org/gophp7-ext/extensions-catalog.html" target="_blank">GoPHP7 extensions Catalog</a> sind sie für PHP 7 verfügbar, dann mal &#8222;Go&#8220;!</p> <p>memcached Extension:</p> <pre class="brush: bash; title: ; notranslate" title="">git clone https://github.com/php-memcached-dev/php-memcached.git --branch php7 cd php-memcached/ /usr/local/php7.0.0RC5/bin/phpize --with-php-config=/usr/local/php7.0.0RC5/bin/php-config ./configure --with-php-config=/usr/local/php7.0.0RC5/bin/php-config make make test sudo cp modules/* /usr/local/php7.0.0RC5/lib/php/extensions/no-debug-non-zts-20151012/ sudo nano /usr/local/php7.0.0RC5/etc/php.ini extension=memcached.so /usr/local/php7.0.0RC5/bin/php -m</pre> <p>gearman Extension:</p> <pre class="brush: bash; title: ; notranslate" title="">git clone https://github.com/wcgallego/pecl-gearman.git cd pecl-gearman/ /usr/local/php7.0.0RC5/bin/phpize --with-php-config=/usr/local/php7.0.0RC5/bin/php-config ./configure --with-php-config=/usr/local/php7.0.0RC5/bin/php-config make make test sudo cp modules/* /usr/local/php7.0.0RC5/lib/php/extensions/no-debug-non-zts-20151012/ sudo nano /usr/local/php7.0.0RC5/etc/php.ini extension=gearman.so /usr/local/php7.0.0RC5/bin/php -m</pre> <p>apcu Extension:</p> <pre class="brush: bash; title: ; notranslate" title="">git clone https://github.com/krakjoe/apcu.git --branch seven cd apcu /usr/local/php7.0.0RC5/bin/phpize --with-php-config=/usr/local/php7.0.0RC5/bin/php-config ./configure --enable-apcu-bc --with-php-config=/usr/local/php7.0.0RC5/bin/php-config make make test sudo cp modules/* /usr/local/php7.0.0RC5/lib/php/extensions/no-debug-non-zts-20151012/ sudo nano /usr/local/php7.0.0RC5/etc/php.ini extension=apcu.so extension=apc.so apc.enabled=1 apc.shm_size=256M apc.ttl=7200 apc.enable_cli=1 apc.gc_ttl=3600 apc.entries_hint=4096 apc.slam_defense=1 apc.serializer=php /usr/local/php7.0.0RC5/bin/php -m /usr/local/php7.0.0RC5/bin/php -r &quot;echo apc_store('a', 'b');&quot;</pre> <p>Im Unterschied zu früher gibt es nun zwei Extensions: apcu.so und apc.so. Man muss beide laden, dann funktionieren die &#8222;alten&#8220; apc_* Funktionen (apc_fetch(), apc_store()&#8230;) wieder. Lädt man nur apcu.so, dann kann man nur apcu_fetch(), apcu_store() usw. nutzen. Abwärtskompatible Projekte brauchen die alten apc_* Funktionen. Lädt man nur die neue apc.so, dann erhält man die Fehlermeldung &#8222;Unable to load dynamic library: &#8230; undefined symbol: zif_apcu_store&#8220;. Lädt man beide funktioniert alles. An dieser Hürde bin ich etwas hängengeblieben&#8230;</p> <h3>Migrationsvorbereitungen</h3> <p>Ich hatte es mir schon vor 2 Monaten mal angeschaut, aber jetzt nochmal frisch: Mit Hilfe des <a href="https://github.com/Alexia/php7mar" target="_blank">PHP Migration Assistant PHP 7 Migration Assistant Report(MAR)</a> mein Projekt analysiert und geschaut welche Probleme auftreten.</p> <p>Es zeigte mir eine Menge Hinweise zu &#8222;funcGetArg&#8220; (also Benutzungen von func_get_args()) an. In der aktuellen Version des <a href="http://php.net/manual/de/migration70.php" target="_blank">PHP 7 Migration-Guides</a> steht zu dem Thema nichts, aber es scheint so zu sein dass früher func_get_args() immer die Originalwerte der Funktionsparameter geliefert hat. Werden die Werte also VOR dem func_get_args() Aufruf verändert, so erhielt man die alten Werte. Seit PHP 7 erhält man die veränderten Werte. Da an den von php7mar bemängelten Stellen die Variablen nicht verändert wurden vor dem Aufruf sind es also alles False-Positives und damit kein Problem.</p> <p>Danach kamen noch einige kritische Hinweise zu &#8222;variableInterpolation&#8220;, dies sind ernst zu nehmende Stellen die in PHP 7 zu Bugs führen. Es geht um die Änderungen bzgl. der <a href="http://php.net/manual/de/migration70.incompatible.php#migration70.incompatible.variable-handling" target="_blank">Uniform Variablen Syntax</a>.</p> <p><img fetchpriority="high" decoding="async" class="alignnone size-full wp-image-6699" src="https://www.phpgangsta.de/wp-content/uploads/uniform_variable_syntax.png" alt="uniform_variable_syntax" width="689" height="203" srcset="https://phpgangsta.de/wp-content/uploads/uniform_variable_syntax.png 689w, https://phpgangsta.de/wp-content/uploads/uniform_variable_syntax-150x44.png 150w, https://phpgangsta.de/wp-content/uploads/uniform_variable_syntax-300x88.png 300w" sizes="(max-width: 689px) 100vw, 689px" /></p> <p>Mit ein paar geschweiften Klammern an den richtigen Stellen waren die Probleme gelöst.</p> <p>Dies ist meiner Meinung nach das gefährlichste Backwards-Compatibility-Problem in PHP 7: Es gibt keinerlei Deprecated Warnung, keinerlei Syntax Fehler oder ähnlich. Es ändert sich still und heimlich die Syntax, und Code der seit Jahren funktioniert hat funktioniert nun nicht mehr so wie früher. In den meisten Fällen sollte es in &#8222;Undefined Index&#8220; oder &#8222;xxx is not a function&#8220; münden und damit leicht zu finden und zu beheben sein, aber in Produktionsumgebungen kann es deshalb zu komischem Verhalten bis hin zu Datenverlust führen&#8230;</p> <p>Insgesamt befanden sich 90% der gefundenen Hinweise in Fremdbibliotheken, nur 10 Hinweise betrafen &#8222;meinen&#8220; Code. Es ging also auch etwas Zeit ins Land den anderen Entwicklern Bescheid zu geben, bei GitHub Issues zu eröffnen bzw. Pull-Requests zu erstellen.</p> <p>(Nette Nebeninfo: Führe ich php7mar mit dem &#8222;alten&#8220; PHP 5.6 aus, dann dauert die Code-Analyse 225 Sekunden. Mit PHP 7 nur noch 66 Sekunden! Yeah, das rockt!)</p> <h3>Unit-Tests laufen lassen</h3> <p>Nachdem ich die angezeigten Probleme behoben habe (auch hauptsächlich in externen Bibliotheken wie dompdf oder einer recht alten PEAR-Klasse, die noch PHP4-Konstruktoren hatte), konnte ich mich dran machen und die Unit-Tests laufen lassen. Und was soll ich sagen: KEINE FEHLER! Ich habe also das gute Gefühl dass ich keine großen Probleme bei der Umstellung haben werde.</p> <pre class="brush: plain; title: ; notranslate" title="">Time: 2.52 minutes, Memory: 156.00Mb Time: 3.32 minutes, Memory: 235.25Mb</pre> <p>Ihr dürft raten welcher der beiden Unit-Test-Runs PHP 5.6 und und welcher PHP 7 ist 😉</p> <p>Interessant fand ich dass auch PHPUnit 4.6.6 funktionierte, ich hätte erwartet dass ich für PHP 7 auch die PHP 7 kompatible PHPUnit 5.0 hätte verwenden müssen. Dem war nicht so, ein Update liegt aber trotzdem nahe.</p> <p>Die nächsten Schritte werden sein die Entwickler-Rechner und die Staging-Umgebung mit PHP 7 auszurüsten, sodass mehr Erfahrungen gesammelt werden, und Bugs durch die manuelle Benutzung der Applikation gesucht werden, die evtl. nicht von Unit-Tests abgedeckt sind, oder die nur in Verbindung mit einem echten Browser oder Webserver wie Apache oder PHP-FPM auftreten&#8230; Wer weiß&#8230;</p> <h3>Migrationsempfehlungen</h3> <p>Ich kann jedem nur empfehlen seinen Code vor der Umstellung auf PHP 7 mit Hilfe automatischer Tools analysieren zu lassen, um genau solche Probleme zu finden. Neben <a href="https://github.com/Alexia/php7mar" target="_blank">php7mar</a> gibt es noch andere Migrations-Tools wie beispielsweise <a href="https://github.com/sstalle/php7cc" target="_blank">php7cc</a> oder <a href="https://github.com/rlerdorf/phan" target="_blank">phan</a> (findet glaube ich &#8222;nur&#8220; die Uniform Variable Syntax Probleme?). Am besten alle durchlaufen lassen.</p> <p>Und ganz wichtig: Den <a href="http://php.net/manual/de/migration70.php" target="_blank">PHP 7 Migration-Guide</a> komplett durchlesen. Je nach Größe des Projektes ist es außerdem keine schlechte Idee, erstmal nur einzelne Nutzer oder nur 1% des Traffics auf PHP 7 zu leiten, und bei Problemen schnell wieder umschalten zu können auf PHP 5.6&#8230; Ist zwar etwas mehr Aufwand, man hat aber nicht mehr so viel Angst vor der Umstellung eines größeren Projekts.</p> <p><img decoding="async" class="alignright wp-image-6709" src="https://www.phpgangsta.de/wp-content/uploads/php7.png" alt="PHP 7" width="213" height="102" srcset="https://phpgangsta.de/wp-content/uploads/php7.png 238w, https://phpgangsta.de/wp-content/uploads/php7-150x72.png 150w" sizes="(max-width: 213px) 100vw, 213px" />Noch knapp einen Monat warten, dann erscheint <del>das Christkind</del> PHP7! Was gibt es also schöneres als sich damit zu beschäftigen und erste Erfahrungen zu sammeln?</p> <p>Im Januar habe ich mir speziell den <a href="https://www.phpgangsta.de/aktueller-stand-von-php-7-deutlich-geringerer-arbeitsspeicherverbrauch">Arbeitsspeicherverbrauch von PHP 7</a> angeschaut, die ChangeLogs verinnerlicht, es kompiliert und ein paar Testzeilen ausgeführt. Das lief schon sehr gut, aber um größere Projekte laufen zu lassen mangelte es noch an einigen Extensions. Außerdem wollte ich ein Zend Framework 1 Projekt testen, und ZF1 war zu dem Zeitpunkt noch nicht PHP 7-kompatibel.</p> <p>Doch das hat sich geändert. ZF1 ist seit Mai 2015 mit <a href="http://framework.zend.com/blog/zend-framework-1-12-12-released.html" target="_blank">Version 1.12.12 PHP 7 kompatibel</a>, und auch die von mir benötigten Extensions wurden umgebaut, sodass es nun PHP 7-kompatible Branches vieler Extensions auf Github gibt.</p> <p>Die Vorgehendweise: Neueste PHP 7 Version herunterladen, kompilieren, Extensions herunterladen, kompilieren, und dann SPASS HABEN!</p> <h3>Also los! PHP 7 RC5 kompilieren</h3> <p><span id="more-6697"></span></p> <pre class="brush: bash; title: ; notranslate" title="">wget https://downloads.php.net/~ab/php-7.0.0RC5.tar.gz tar -xzvf php-7.0.0RC5.tar.gz cd php-7.0.0RC5/ ./configure --prefix=/usr/local/php7.0.0RC5 --with-zlib --with-config-file-path=/usr/local/php7.0.0RC5/etc --enable-mbstring --with-mysql --with-mysqli --with-pdo-mysql --enable-zip --with-imap --with-kerberos --with-imap-ssl --with-openssl --with-jpeg-dir --with-gd --with-gettext --with-freetype-dir --enable-ftp --with-pspell --with-curl make make test sudo make install /usr/local/php7.0.0RC5/bin/php -v /usr/local/php7.0.0RC5/bin/php -m /usr/local/php7.0.0RC5/bin/php -i</pre> <p>Funktioniert wunderbar! Weiter gehts.</p> <h3>Extensions memcached, gearman und apcu</h3> <p>Diese 3 Extensions benötige ich für das Projekt. Laut <a href="http://gophp7.org/gophp7-ext/extensions-catalog.html" target="_blank">GoPHP7 extensions Catalog</a> sind sie für PHP 7 verfügbar, dann mal &#8222;Go&#8220;!</p> <p>memcached Extension:</p> <pre class="brush: bash; title: ; notranslate" title="">git clone https://github.com/php-memcached-dev/php-memcached.git --branch php7 cd php-memcached/ /usr/local/php7.0.0RC5/bin/phpize --with-php-config=/usr/local/php7.0.0RC5/bin/php-config ./configure --with-php-config=/usr/local/php7.0.0RC5/bin/php-config make make test sudo cp modules/* /usr/local/php7.0.0RC5/lib/php/extensions/no-debug-non-zts-20151012/ sudo nano /usr/local/php7.0.0RC5/etc/php.ini extension=memcached.so /usr/local/php7.0.0RC5/bin/php -m</pre> <p>gearman Extension:</p> <pre class="brush: bash; title: ; notranslate" title="">git clone https://github.com/wcgallego/pecl-gearman.git cd pecl-gearman/ /usr/local/php7.0.0RC5/bin/phpize --with-php-config=/usr/local/php7.0.0RC5/bin/php-config ./configure --with-php-config=/usr/local/php7.0.0RC5/bin/php-config make make test sudo cp modules/* /usr/local/php7.0.0RC5/lib/php/extensions/no-debug-non-zts-20151012/ sudo nano /usr/local/php7.0.0RC5/etc/php.ini extension=gearman.so /usr/local/php7.0.0RC5/bin/php -m</pre> <p>apcu Extension:</p> <pre class="brush: bash; title: ; notranslate" title="">git clone https://github.com/krakjoe/apcu.git --branch seven cd apcu /usr/local/php7.0.0RC5/bin/phpize --with-php-config=/usr/local/php7.0.0RC5/bin/php-config ./configure --enable-apcu-bc --with-php-config=/usr/local/php7.0.0RC5/bin/php-config make make test sudo cp modules/* /usr/local/php7.0.0RC5/lib/php/extensions/no-debug-non-zts-20151012/ sudo nano /usr/local/php7.0.0RC5/etc/php.ini extension=apcu.so extension=apc.so apc.enabled=1 apc.shm_size=256M apc.ttl=7200 apc.enable_cli=1 apc.gc_ttl=3600 apc.entries_hint=4096 apc.slam_defense=1 apc.serializer=php /usr/local/php7.0.0RC5/bin/php -m /usr/local/php7.0.0RC5/bin/php -r &quot;echo apc_store('a', 'b');&quot;</pre> <p>Im Unterschied zu früher gibt es nun zwei Extensions: apcu.so und apc.so. Man muss beide laden, dann funktionieren die &#8222;alten&#8220; apc_* Funktionen (apc_fetch(), apc_store()&#8230;) wieder. Lädt man nur apcu.so, dann kann man nur apcu_fetch(), apcu_store() usw. nutzen. Abwärtskompatible Projekte brauchen die alten apc_* Funktionen. Lädt man nur die neue apc.so, dann erhält man die Fehlermeldung &#8222;Unable to load dynamic library: &#8230; undefined symbol: zif_apcu_store&#8220;. Lädt man beide funktioniert alles. An dieser Hürde bin ich etwas hängengeblieben&#8230;</p> <h3>Migrationsvorbereitungen</h3> <p>Ich hatte es mir schon vor 2 Monaten mal angeschaut, aber jetzt nochmal frisch: Mit Hilfe des <a href="https://github.com/Alexia/php7mar" target="_blank">PHP Migration Assistant PHP 7 Migration Assistant Report(MAR)</a> mein Projekt analysiert und geschaut welche Probleme auftreten.</p> <p>Es zeigte mir eine Menge Hinweise zu &#8222;funcGetArg&#8220; (also Benutzungen von func_get_args()) an. In der aktuellen Version des <a href="http://php.net/manual/de/migration70.php" target="_blank">PHP 7 Migration-Guides</a> steht zu dem Thema nichts, aber es scheint so zu sein dass früher func_get_args() immer die Originalwerte der Funktionsparameter geliefert hat. Werden die Werte also VOR dem func_get_args() Aufruf verändert, so erhielt man die alten Werte. Seit PHP 7 erhält man die veränderten Werte. Da an den von php7mar bemängelten Stellen die Variablen nicht verändert wurden vor dem Aufruf sind es also alles False-Positives und damit kein Problem.</p> <p>Danach kamen noch einige kritische Hinweise zu &#8222;variableInterpolation&#8220;, dies sind ernst zu nehmende Stellen die in PHP 7 zu Bugs führen. Es geht um die Änderungen bzgl. der <a href="http://php.net/manual/de/migration70.incompatible.php#migration70.incompatible.variable-handling" target="_blank">Uniform Variablen Syntax</a>.</p> <p><img fetchpriority="high" decoding="async" class="alignnone size-full wp-image-6699" src="https://www.phpgangsta.de/wp-content/uploads/uniform_variable_syntax.png" alt="uniform_variable_syntax" width="689" height="203" srcset="https://phpgangsta.de/wp-content/uploads/uniform_variable_syntax.png 689w, https://phpgangsta.de/wp-content/uploads/uniform_variable_syntax-150x44.png 150w, https://phpgangsta.de/wp-content/uploads/uniform_variable_syntax-300x88.png 300w" sizes="(max-width: 689px) 100vw, 689px" /></p> <p>Mit ein paar geschweiften Klammern an den richtigen Stellen waren die Probleme gelöst.</p> <p>Dies ist meiner Meinung nach das gefährlichste Backwards-Compatibility-Problem in PHP 7: Es gibt keinerlei Deprecated Warnung, keinerlei Syntax Fehler oder ähnlich. Es ändert sich still und heimlich die Syntax, und Code der seit Jahren funktioniert hat funktioniert nun nicht mehr so wie früher. In den meisten Fällen sollte es in &#8222;Undefined Index&#8220; oder &#8222;xxx is not a function&#8220; münden und damit leicht zu finden und zu beheben sein, aber in Produktionsumgebungen kann es deshalb zu komischem Verhalten bis hin zu Datenverlust führen&#8230;</p> <p>Insgesamt befanden sich 90% der gefundenen Hinweise in Fremdbibliotheken, nur 10 Hinweise betrafen &#8222;meinen&#8220; Code. Es ging also auch etwas Zeit ins Land den anderen Entwicklern Bescheid zu geben, bei GitHub Issues zu eröffnen bzw. Pull-Requests zu erstellen.</p> <p>(Nette Nebeninfo: Führe ich php7mar mit dem &#8222;alten&#8220; PHP 5.6 aus, dann dauert die Code-Analyse 225 Sekunden. Mit PHP 7 nur noch 66 Sekunden! Yeah, das rockt!)</p> <h3>Unit-Tests laufen lassen</h3> <p>Nachdem ich die angezeigten Probleme behoben habe (auch hauptsächlich in externen Bibliotheken wie dompdf oder einer recht alten PEAR-Klasse, die noch PHP4-Konstruktoren hatte), konnte ich mich dran machen und die Unit-Tests laufen lassen. Und was soll ich sagen: KEINE FEHLER! Ich habe also das gute Gefühl dass ich keine großen Probleme bei der Umstellung haben werde.</p> <pre class="brush: plain; title: ; notranslate" title="">Time: 2.52 minutes, Memory: 156.00Mb Time: 3.32 minutes, Memory: 235.25Mb</pre> <p>Ihr dürft raten welcher der beiden Unit-Test-Runs PHP 5.6 und und welcher PHP 7 ist 😉</p> <p>Interessant fand ich dass auch PHPUnit 4.6.6 funktionierte, ich hätte erwartet dass ich für PHP 7 auch die PHP 7 kompatible PHPUnit 5.0 hätte verwenden müssen. Dem war nicht so, ein Update liegt aber trotzdem nahe.</p> <p>Die nächsten Schritte werden sein die Entwickler-Rechner und die Staging-Umgebung mit PHP 7 auszurüsten, sodass mehr Erfahrungen gesammelt werden, und Bugs durch die manuelle Benutzung der Applikation gesucht werden, die evtl. nicht von Unit-Tests abgedeckt sind, oder die nur in Verbindung mit einem echten Browser oder Webserver wie Apache oder PHP-FPM auftreten&#8230; Wer weiß&#8230;</p> <h3>Migrationsempfehlungen</h3> <p>Ich kann jedem nur empfehlen seinen Code vor der Umstellung auf PHP 7 mit Hilfe automatischer Tools analysieren zu lassen, um genau solche Probleme zu finden. Neben <a href="https://github.com/Alexia/php7mar" target="_blank">php7mar</a> gibt es noch andere Migrations-Tools wie beispielsweise <a href="https://github.com/sstalle/php7cc" target="_blank">php7cc</a> oder <a href="https://github.com/rlerdorf/phan" target="_blank">phan</a> (findet glaube ich &#8222;nur&#8220; die Uniform Variable Syntax Probleme?). Am besten alle durchlaufen lassen.</p> <p>Und ganz wichtig: Den <a href="http://php.net/manual/de/migration70.php" target="_blank">PHP 7 Migration-Guide</a> komplett durchlesen. Je nach Größe des Projektes ist es außerdem keine schlechte Idee, erstmal nur einzelne Nutzer oder nur 1% des Traffics auf PHP 7 zu leiten, und bei Problemen schnell wieder umschalten zu können auf PHP 5.6&#8230; Ist zwar etwas mehr Aufwand, man hat aber nicht mehr so viel Angst vor der Umstellung eines größeren Projekts.</p> https://phpgangsta.de/php-7-migration-eines-projekts/feed 10 Gewinner der Verlosung für die code.talks 2015 https://phpgangsta.de/gewinner-der-verlosung-fuer-die-code-talks-2015 https://phpgangsta.de/gewinner-der-verlosung-fuer-die-code-talks-2015#comments Wed, 27 May 2015 15:59:41 +0000 http://www.phpgangsta.de/?p=6678 <p><img decoding="async" class="alignright size-full wp-image-6665" src="https://www.phpgangsta.de/wp-content/uploads/code.talks2015_logoklein.jpg" alt="code.talks 2015" width="320" height="137" srcset="https://phpgangsta.de/wp-content/uploads/code.talks2015_logoklein.jpg 320w, https://phpgangsta.de/wp-content/uploads/code.talks2015_logoklein-150x64.jpg 150w, https://phpgangsta.de/wp-content/uploads/code.talks2015_logoklein-300x128.jpg 300w" sizes="(max-width: 320px) 100vw, 320px" />Die Zeit ist um, ein Gewinner für das code.talks 2015 Freiticket muss bestimmt werden. 14 gültige Teilnehmer sind im Pott. Die richtige Antwort lautete natürlich: &#8222;Developer Conference&#8220;.</p> <p>Max hat leider an die Key ID 79D56D60 verschlüsselt, die Key ID an die verschlüsselt werden sollte lautete jedoch A08ED813. Leider hat Max nicht auf meine E-Mail reagiert, ich hatte ihn darauf hingewiesen, er kann leider nicht teilnehmen an der Verlosung.</p> <p>Wer von euch 14 hat gewonnen? Das Freiticket für die Konferenz geht an:</p> <p><span id="more-6678"></span>Carsten (<a href="https://www.phpgangsta.de/code-talks-2015-gutscheine-und-freiticket#comment-1476804" target="_blank">Link zum Kommentar</a>)</p> <p>Herzlichen Glückwunsch!</p> <p>Für den Zufall habe ich die neue PHP7 Funktion <a href="https://wiki.php.net/rfc/easy_userland_csprng" target="_blank">random_int()</a> genommen, endlich eine einfache Möglichkeit eine kryptografisch sichere Zufallszahl zu bekommen (<a href="https://www.phpgangsta.de/den-aktuellen-stand-von-php-7-pre-alpha-selbst-kompilieren-und-testen">wie man PHP 7 selbst kompiliert</a> hatte ich vor ein paar Wochen beschrieben):</p> <p><a href="https://www.phpgangsta.de/wp-content/uploads/Screenshot-from-2015-05-27-133739.png"><img fetchpriority="high" decoding="async" class="alignnone wp-image-6679" src="https://www.phpgangsta.de/wp-content/uploads/Screenshot-from-2015-05-27-133739.png" alt="Screenshot from 2015-05-27 13:37:39" width="712" height="124" srcset="https://phpgangsta.de/wp-content/uploads/Screenshot-from-2015-05-27-133739.png 758w, https://phpgangsta.de/wp-content/uploads/Screenshot-from-2015-05-27-133739-150x26.png 150w, https://phpgangsta.de/wp-content/uploads/Screenshot-from-2015-05-27-133739-300x52.png 300w" sizes="(max-width: 712px) 100vw, 712px" /></a></p> <p>An euch alle sende ich eine E-Mail mit den Gutschein-Codes, die ihr einlösen könnt bei der Ticketbestellung. Ich hoffe dass ich die Codes morgen bekomme. Wir sehen uns dann alle in Hamburg im September!</p> <p>Danke auch nochmal an Sarah für das Freiticket und die Rabatt-Codes!</p> <p><img decoding="async" class="alignright size-full wp-image-6665" src="https://www.phpgangsta.de/wp-content/uploads/code.talks2015_logoklein.jpg" alt="code.talks 2015" width="320" height="137" srcset="https://phpgangsta.de/wp-content/uploads/code.talks2015_logoklein.jpg 320w, https://phpgangsta.de/wp-content/uploads/code.talks2015_logoklein-150x64.jpg 150w, https://phpgangsta.de/wp-content/uploads/code.talks2015_logoklein-300x128.jpg 300w" sizes="(max-width: 320px) 100vw, 320px" />Die Zeit ist um, ein Gewinner für das code.talks 2015 Freiticket muss bestimmt werden. 14 gültige Teilnehmer sind im Pott. Die richtige Antwort lautete natürlich: &#8222;Developer Conference&#8220;.</p> <p>Max hat leider an die Key ID 79D56D60 verschlüsselt, die Key ID an die verschlüsselt werden sollte lautete jedoch A08ED813. Leider hat Max nicht auf meine E-Mail reagiert, ich hatte ihn darauf hingewiesen, er kann leider nicht teilnehmen an der Verlosung.</p> <p>Wer von euch 14 hat gewonnen? Das Freiticket für die Konferenz geht an:</p> <p><span id="more-6678"></span>Carsten (<a href="https://www.phpgangsta.de/code-talks-2015-gutscheine-und-freiticket#comment-1476804" target="_blank">Link zum Kommentar</a>)</p> <p>Herzlichen Glückwunsch!</p> <p>Für den Zufall habe ich die neue PHP7 Funktion <a href="https://wiki.php.net/rfc/easy_userland_csprng" target="_blank">random_int()</a> genommen, endlich eine einfache Möglichkeit eine kryptografisch sichere Zufallszahl zu bekommen (<a href="https://www.phpgangsta.de/den-aktuellen-stand-von-php-7-pre-alpha-selbst-kompilieren-und-testen">wie man PHP 7 selbst kompiliert</a> hatte ich vor ein paar Wochen beschrieben):</p> <p><a href="https://www.phpgangsta.de/wp-content/uploads/Screenshot-from-2015-05-27-133739.png"><img fetchpriority="high" decoding="async" class="alignnone wp-image-6679" src="https://www.phpgangsta.de/wp-content/uploads/Screenshot-from-2015-05-27-133739.png" alt="Screenshot from 2015-05-27 13:37:39" width="712" height="124" srcset="https://phpgangsta.de/wp-content/uploads/Screenshot-from-2015-05-27-133739.png 758w, https://phpgangsta.de/wp-content/uploads/Screenshot-from-2015-05-27-133739-150x26.png 150w, https://phpgangsta.de/wp-content/uploads/Screenshot-from-2015-05-27-133739-300x52.png 300w" sizes="(max-width: 712px) 100vw, 712px" /></a></p> <p>An euch alle sende ich eine E-Mail mit den Gutschein-Codes, die ihr einlösen könnt bei der Ticketbestellung. Ich hoffe dass ich die Codes morgen bekomme. Wir sehen uns dann alle in Hamburg im September!</p> <p>Danke auch nochmal an Sarah für das Freiticket und die Rabatt-Codes!</p> https://phpgangsta.de/gewinner-der-verlosung-fuer-die-code-talks-2015/feed 3 code.talks 2015: Gutscheine und Freiticket! https://phpgangsta.de/code-talks-2015-gutscheine-und-freiticket https://phpgangsta.de/code-talks-2015-gutscheine-und-freiticket#comments Wed, 13 May 2015 11:52:22 +0000 http://www.phpgangsta.de/?p=6659 <p>Die <a href="http://www.codetalks.de/" target="_blank">code.talks</a>, die meines Wissens nach größte Webentwickler-Konferenz in Deutschland, findet auch dieses Jahr wieder statt und wird 1500 Entwickler begrüßen in Hamburg. Da sie in den letzten Jahren immer ausgebucht war und auch dieses Jahr wieder damit zu rechnen ist (nach 2,5 Monaten ist bereits über ein Drittel der Tickets verkauft), bin ich für euch an die Veranstalter herangetreten und habe um eine Aktion für meine Leser gebeten, und siehe da: Ich hatte Erfolg!</p> <p><img decoding="async" class="alignright size-full wp-image-6665" src="https://www.phpgangsta.de/wp-content/uploads/code.talks2015_logoklein.jpg" alt="code.talks 2015" width="320" height="137" srcset="https://phpgangsta.de/wp-content/uploads/code.talks2015_logoklein.jpg 320w, https://phpgangsta.de/wp-content/uploads/code.talks2015_logoklein-150x64.jpg 150w, https://phpgangsta.de/wp-content/uploads/code.talks2015_logoklein-300x128.jpg 300w" sizes="(max-width: 320px) 100vw, 320px" />Ich habe <strong>Gutscheincodes</strong> für euch, und auch ein <strong>Freiticket</strong> zu vergeben. Wie ihr die bekommt steht weiter unten.</p> <p>Ende September, genauer am 29. und 30. September, werden alle 8 Säle im Cinemaxx Hamburg-Dammtor gefüllt und <a href="http://www.codetalks.de/2015/programm" target="_blank">112 Sessions mit Themen rund um Webentwicklung</a> (PHP, Javascript, DevOps, Big Data, UX/Frontend, Skalierung, Infrastruktur, Mobile, Startups uvm.) werden viel Wissen vermitteln. Als Sprecher sind bereits an Bord: GitHub, StackOverflow, Zalando, Wooga, Jimdo, InnoGames, Cloudera und viele mehr. Der <a href="http://www.codetalks.de/2015/call-for-papers" target="_blank">Call-for-Papers</a> läuft noch, und die Liste wir garantiert viele weitere interessante Leute und Firmen beinhalten die aus der Praxis erzählen. 2 Tage volles Programm, incl. Frühstück, Mittagessen, Afterwork-Party, riesige Leinwände, bequeme Sessel und Popcorn &amp; Nachos bis zum Umfallen 😉</p> <p><span id="more-6659"></span>Auch ich werde dieses Jahr dabei sein und am Spektakel im Cinemaxx Hamburg-Dammtor teilnehmen, ich bin schon sehr gespannt! Ich hoffe euch dort auch zu sehen!</p> <p>So, nun zum Wichtigsten: Rabatt-Codes und das Freiticket:</p> <h3>Rabatt-Code</h3> <p>Einen 10% Rabatt-Code erhält jeder der hier einen Kommentar hinterlässt, ich sende dann per E-Mail den Rabatt-Code raus. Easy-Peasy Geld gespart! Ab 99€ (-10%) für Studenten ist man dabei.</p> <h3>Freiticket</h3> <p>Für das begehrte Freiticket musst du etwas tun: PGP Verschlüsselung nutzen! Eigentlich eine Sache die jeder Entwickler kennen und nutzen sollte, von daher keine große Hürde oder? Beantwortet einfach folgende Frage, verschlüsselt die Antwort zusammen mit eurer E-Mail-Adresse an den <a href="https://www.phpgangsta.de/wp-content/uploads/public.code_.talks_.key" target="_blank">PGP-Public-Key</a>, und postet das Ergebnis im ASCII-Armor-Format hier als Kommentar! Die Frage lautet:</p> <p>Wie lautete der Name der code.talks Konferenz, bevor sie in code.talks umbenannt wurde?</p> <p>Die Antwort kann man ziemlich schnell herausfinden indem man auf der code.talks Website auf den passenden Menu-Punkt klickt 😉 Die Antwort, plus eure E-Mail-Adresse, verschlüsselt ihr an den oben genannten PGP-Public-Key. Beispielsweise &#8222;Die Antwort lautet: XXXXX XXXXX &#8211; meine E-Mail-Adresse: xxxxx@domain.de&#8220;. Kurz durch PGP gejagt und gepostet als Kommentar (im ASCII-Armor-Format), schon bist du im Lostopf! Zusätzlich könnt ihr das natürlich auch noch signieren, gibt aber keine Zusatzpunkte 😉</p> <p>Die Verlosung findet am 27.05.2015 statt, ihr habt also 2 Wochen Zeit für die Aufgabe.</p> <p>Wir sehen uns dann im September in Hamburg!</p> <p>Danke an Sarah für die Rabatt-Codes und das Freiticket!</p> <p>&#8212;&#8212;&#8212;</p> <p>Wer Ende Juni noch Zeit hat sollte über den <a href="http://www.trivago.com/hackathon2015" target="_blank">Trivago-Hackathon am 27./28. Juni</a> nachdenken, dort werden 50 Hacker erwartet, die coole Dinge erstellen, es gibt Essen und Trinken, tolle Preise (1. Preis 5000€!), und das ganze kostenlos in Düsseldorf. Wer Bock drauf hat kann sich bis zum 6. Juni bewerben.</p> <p>Die <a href="http://www.codetalks.de/" target="_blank">code.talks</a>, die meines Wissens nach größte Webentwickler-Konferenz in Deutschland, findet auch dieses Jahr wieder statt und wird 1500 Entwickler begrüßen in Hamburg. Da sie in den letzten Jahren immer ausgebucht war und auch dieses Jahr wieder damit zu rechnen ist (nach 2,5 Monaten ist bereits über ein Drittel der Tickets verkauft), bin ich für euch an die Veranstalter herangetreten und habe um eine Aktion für meine Leser gebeten, und siehe da: Ich hatte Erfolg!</p> <p><img decoding="async" class="alignright size-full wp-image-6665" src="https://www.phpgangsta.de/wp-content/uploads/code.talks2015_logoklein.jpg" alt="code.talks 2015" width="320" height="137" srcset="https://phpgangsta.de/wp-content/uploads/code.talks2015_logoklein.jpg 320w, https://phpgangsta.de/wp-content/uploads/code.talks2015_logoklein-150x64.jpg 150w, https://phpgangsta.de/wp-content/uploads/code.talks2015_logoklein-300x128.jpg 300w" sizes="(max-width: 320px) 100vw, 320px" />Ich habe <strong>Gutscheincodes</strong> für euch, und auch ein <strong>Freiticket</strong> zu vergeben. Wie ihr die bekommt steht weiter unten.</p> <p>Ende September, genauer am 29. und 30. September, werden alle 8 Säle im Cinemaxx Hamburg-Dammtor gefüllt und <a href="http://www.codetalks.de/2015/programm" target="_blank">112 Sessions mit Themen rund um Webentwicklung</a> (PHP, Javascript, DevOps, Big Data, UX/Frontend, Skalierung, Infrastruktur, Mobile, Startups uvm.) werden viel Wissen vermitteln. Als Sprecher sind bereits an Bord: GitHub, StackOverflow, Zalando, Wooga, Jimdo, InnoGames, Cloudera und viele mehr. Der <a href="http://www.codetalks.de/2015/call-for-papers" target="_blank">Call-for-Papers</a> läuft noch, und die Liste wir garantiert viele weitere interessante Leute und Firmen beinhalten die aus der Praxis erzählen. 2 Tage volles Programm, incl. Frühstück, Mittagessen, Afterwork-Party, riesige Leinwände, bequeme Sessel und Popcorn &amp; Nachos bis zum Umfallen 😉</p> <p><span id="more-6659"></span>Auch ich werde dieses Jahr dabei sein und am Spektakel im Cinemaxx Hamburg-Dammtor teilnehmen, ich bin schon sehr gespannt! Ich hoffe euch dort auch zu sehen!</p> <p>So, nun zum Wichtigsten: Rabatt-Codes und das Freiticket:</p> <h3>Rabatt-Code</h3> <p>Einen 10% Rabatt-Code erhält jeder der hier einen Kommentar hinterlässt, ich sende dann per E-Mail den Rabatt-Code raus. Easy-Peasy Geld gespart! Ab 99€ (-10%) für Studenten ist man dabei.</p> <h3>Freiticket</h3> <p>Für das begehrte Freiticket musst du etwas tun: PGP Verschlüsselung nutzen! Eigentlich eine Sache die jeder Entwickler kennen und nutzen sollte, von daher keine große Hürde oder? Beantwortet einfach folgende Frage, verschlüsselt die Antwort zusammen mit eurer E-Mail-Adresse an den <a href="https://www.phpgangsta.de/wp-content/uploads/public.code_.talks_.key" target="_blank">PGP-Public-Key</a>, und postet das Ergebnis im ASCII-Armor-Format hier als Kommentar! Die Frage lautet:</p> <p>Wie lautete der Name der code.talks Konferenz, bevor sie in code.talks umbenannt wurde?</p> <p>Die Antwort kann man ziemlich schnell herausfinden indem man auf der code.talks Website auf den passenden Menu-Punkt klickt 😉 Die Antwort, plus eure E-Mail-Adresse, verschlüsselt ihr an den oben genannten PGP-Public-Key. Beispielsweise &#8222;Die Antwort lautet: XXXXX XXXXX &#8211; meine E-Mail-Adresse: xxxxx@domain.de&#8220;. Kurz durch PGP gejagt und gepostet als Kommentar (im ASCII-Armor-Format), schon bist du im Lostopf! Zusätzlich könnt ihr das natürlich auch noch signieren, gibt aber keine Zusatzpunkte 😉</p> <p>Die Verlosung findet am 27.05.2015 statt, ihr habt also 2 Wochen Zeit für die Aufgabe.</p> <p>Wir sehen uns dann im September in Hamburg!</p> <p>Danke an Sarah für die Rabatt-Codes und das Freiticket!</p> <p>&#8212;&#8212;&#8212;</p> <p>Wer Ende Juni noch Zeit hat sollte über den <a href="http://www.trivago.com/hackathon2015" target="_blank">Trivago-Hackathon am 27./28. Juni</a> nachdenken, dort werden 50 Hacker erwartet, die coole Dinge erstellen, es gibt Essen und Trinken, tolle Preise (1. Preis 5000€!), und das ganze kostenlos in Düsseldorf. Wer Bock drauf hat kann sich bis zum 6. Juni bewerben.</p> https://phpgangsta.de/code-talks-2015-gutscheine-und-freiticket/feed 21 PHP 7 Feature Freeze https://phpgangsta.de/php-7-feature-freeze https://phpgangsta.de/php-7-feature-freeze#comments Thu, 02 Apr 2015 08:58:19 +0000 http://www.phpgangsta.de/?p=6644 <p>PHP 7 wird großartig, ich freue mich schon sehr darauf! Ich hoffe dass der <a href="https://wiki.php.net/rfc/php7timeline" target="_blank">straffe Zeitplan</a> eingehalten werden kann, und wir im Oktober/November die Version 7.0 in den Händen halten.</p> <p>Vor 2 Wochen war der Feature-Freeze, und alle Abstimmungen die noch liefen sind beendet, es stehen also nun mehr oder minder alle Features fest die drin sein werden. Im großen und ganzen wissen wir nun <a href="https://wiki.php.net/rfc#accepted" target="_blank">was uns in PHP 7 alles erwarten wird</a>.</p> <p>Hier stelle ich folgende Features von PHP 7 vor:</p> <ol> <li>Performance</li> <li>Skalare Typehints</li> <li>jsond</li> <li>Coalesce-Operator</li> <li>Engine-Exceptions</li> <li>Kontext-sensitiver Lexer</li> <li>Uniform Variable Syntax</li> <li>Abstract Syntax Tree</li> <li>Neue einheitliche Zufallsfunktionen</li> <li>weiteres</li> </ol> <p><span id="more-6644"></span></p> <h3>1. Performance</h3> <p>Für mich an erster Stelle steht wahrscheinlich die stark gestiegene Performance. In bisherigen Versionen wurde PHP &#8222;nur&#8220; jeweils 5-10% schneller, was kontinuierlich auch ganz gut ist, aber PHP 7 setzt einen oben drauf. Wie bereits in anderen Blogartikeln (<a href="http://www.drupalonwindows.com/en/blog/benchmarking-drupal-7-php-7-dev" target="_blank">1</a> <a href="http://zsuraski.blogspot.com.br/2014/07/benchmarking-phpng.html" target="_blank">2</a> <a href="https://docs.google.com/spreadsheets/d/1qW0avj2eRvPVxj_5V4BBNrOP1ULK7AaXTFsxcffFxT8/edit#gid=746230409" target="_blank">3</a>) aufgezeigt werden wir ein zwischen 70% und 120% schnelleres PHP bekommen gegenüber PHP 5.6. Damit wird PHP 7 ungefähr  genauso schnell sein wie Facebooks HHVM. Geschenkte Performance ohne dass man seine Applikationen umbauen muss ist immer gern gesehen 😉</p> <h3>2. Skalare Typehints</h3> <p>Das nächste sehr interessante Feature werden die <a href="https://wiki.php.net/rfc/scalar_type_hints_v5" target="_blank">skalaren Typehints</a> sein. Mit der Zeit werde ich diese sicherlich einsetzen in Projekten, in denen ich selbst die PHP-Version bestimmen kann und keine Rücksicht auf alte Systeme nehmen muss. Mit den Typehints stark verbunden sind auch die <a href="https://wiki.php.net/rfc/return_types" target="_blank">Return Types</a>, man kann in Zukunft einer Funktion also einen Typ zuordnen die sie zurückzuliefern hat.<br /> Die skalaren Typehints waren eine riesen Diskussion. Jeder will sie, aber man war sich nicht einige wie &#8222;stark&#8220; sie sein sollen. Nun hat man sich auf einen Dual-Mode geeinigt, mit dem jeder hoffentlich halbwegs glücklich werden wird. Hierzu werde ich bald noch einen separaten Blogartikel verfassen, weil das ganze ein recht umfangreiches Thema ist.</p> <h3>3. jsond</h3> <p>PHP wird eine <a href="https://wiki.php.net/rfc/jsond" target="_blank">neue Implementation der JSON-Extension</a> bekommen. Damit werden Lizenzprobleme gelöst, und die neue Variante ist in vielen Fällen (nicht allen) auch schneller, zwischen 20% und 250%. Das ganze passiert unter der Haube, der einzige Unterschied zu vorher ist, dass man json in Zukunft nicht mehr einzeln nachinstallieren muss bei den meisten Linux-Distributionen, sondern es fest eingebaut mitgeliefert wird.</p> <h3>4. Coalesce-Operator</h3> <p>Der sogenannte <a href="https://wiki.php.net/rfc/isset_ternary" target="_blank">Coalesce-Operator</a> könnte auch recht hilfreich sein, man wird sich sicher ein paar Wochen an das &#8222;Aussehen&#8220; gewöhnen müssen, aber ich glaube er gefällt mir sehr gut:</p> <pre class="brush: php; title: ; notranslate" title="">// vorher: $username = isset($_GET&#x5B;'user']) ? $_GET&#x5B;'user'] : 'nobody'; // mit PHP 7: $username = $_GET&#x5B;'user'] ?? 'nobody';</pre> <h3>5. Engine-Exceptions</h3> <p>Die <a href="https://wiki.php.net/rfc/engine_exceptions_for_php7" target="_blank">Engine von PHP darf in Zukunft auch Exceptions werfen</a>. Vorbei sind also die Zeiten von &#8222;Fatal errors&#8220;, zukünftig kann man diese Fehler abfangen und sie behandeln. Beispiel:</p> <pre class="brush: php; title: ; notranslate" title="">function call_method($obj) { $obj-&gt;method(); } call_method(null); // oops!</pre> <p>Aktuell bricht der Code ab mit der Fehlermeldung:</p> <pre class="brush: plain; title: ; notranslate" title="">Fatal error: Call to a member function method() on a non-object in /path/file.php on line 4</pre> <p>Fatale Fehler sind immer doof, denn evtl. wichtiger &#8222;Aufräumcode&#8220; wird nicht mehr aufgerufen. Das kann böse enden.</p> <p>Und so kann man in Zukunft diese Exception abfangen und darauf reagieren:</p> <pre class="brush: php; title: ; notranslate" title="">try { call_method(null); // oops! } catch (EngineException $e) { echo &quot;Exception: {$e-&gt;getMessage()}\n&quot;; }</pre> <h3>6. Kontext-sensitiver Lexer</h3> <p>In Zukunft wird es weniger reservierte Wörter für Funktionsnamen geben. Das ganze nennt sich <a href="https://wiki.php.net/rfc/context_sensitive_lexer" target="_blank">kontext-sensitiver Lexer</a> und bedeutet dass reservierte Wörter wie &#8222;for&#8220; oder &#8222;list&#8220; nicht mehr global verboten werden, sondern je nach Kontext des Gebrauchs erlaubt sein werden. Mit PHP 7 wird folgender Code möglich sein, der aktuell nicht erlaubt ist weil &#8222;for&#8220;, &#8222;and&#8220;, &#8222;or&#8220;, &#8222;list&#8220; reserviert sind und nicht genutzt werden dürfen:</p> <pre class="brush: php; title: ; notranslate" title="">$projects = Finder::for('project') -&gt;where('name')-&gt;like('%secret%') -&gt;and('priority', '&gt;', 9) -&gt;or('code')-&gt;in(&#x5B;'4', '5', '7']) -&gt;and()-&gt;not('created_at')-&gt;between(&#x5B;$time1, $time2]) -&gt;list($limit, $offset);</pre> <h3>7. Uniform Variable Syntax</h3> <p>Durch die <a href="https://wiki.php.net/rfc/uniform_variable_syntax" target="_blank">Uniform Variable Syntax</a> wird man einige schöne neue Zeilen Code schreiben können, für die man bisher häufig temporäre Variablen brauchte. Einige Beispiele:</p> <pre class="brush: php; title: ; notranslate" title="">$foo()&#x5B;'bar']() getStr(){0} $foo-&gt;bar()::baz() $foo-&gt;bar()()</pre> <h3>8. Abstract Syntax Tree</h3> <p>Ein weiteres Feature unter der Haube von PHP 7 wird der <a href="https://wiki.php.net/rfc/abstract_syntax_tree" target="_blank">Abstract Syntax Tree (AST)</a> sein. Das Voting war mit 47:0 sehr eindeutig 😉 Bisher produziert der PHP-Parser direkt OpCodes. In Zukunft wird der Parser als Zwischenstruktur den AST generieren, der dann erstens einige schöne Optimierungen des Codes erlaubt, aber auch entkoppelt er damit den Parser vom Compiler, was die Wartung einfacher machen wird. Wenn der AST zugänglich gemacht wird für Userland/Extensions, dann wird man damit auch super Statische Analyzer bauen könne. Und nebenbei bringt er auch nochmal mehr Performance. Wir dürfen gespannt sein!</p> <h3>9. Neue einheitliche Zufallsfunktionen</h3> <p>PHP hat noch keinen einheitlichen Cryptographically secure pseudo-random number generator (CSPRNG), und wird nun einen bekommen. Kein Gehampel mehr mit openssl_random_pseudo_bytes(), mcrypt_create_iv() und /dev/urandom. Es hilft hoffentlich dabei, dass User bei kryptografischen Aufgaben nicht mehr auf rand() oder ähnliches zurückgreifen sondern die &#8222;richtige&#8220; Funktion dafür nutzen: <a href="https://wiki.php.net/rfc/easy_userland_csprng" target="_blank">random_bytes() bzw. random_int()</a>.</p> <h3>10. weiteres</h3> <p>Zusätzlich zu den genannten Features gibt es noch eine Menge weiterer Änderungen: <a href="https://wiki.php.net/rfc/combined-comparison-operator" target="_blank">Spaceship-Operator</a>, <a href="https://wiki.php.net/rfc/generator-delegation" target="_blank">Generator Delegation</a>, <a href="https://wiki.php.net/rfc/size_t_and_int64_next" target="_blank">besserer 64bit Support</a>, <a href="https://wiki.php.net/rfc/switch.default.multiple" target="_blank">Verbieten von mehreren default-Blöcken</a>, <a href="https://wiki.php.net/rfc/group_use_declarations" target="_blank">Gruppen-&#8222;use&#8220;-Deklarationen</a>, <a href="https://wiki.php.net/rfc#php_70" target="_blank">und und und</a>. Etwas aufpassen muss man bei den <a href="https://wiki.php.net/rfc/reserve_more_types_in_php_7" target="_blank">neuen reservierten Typen</a> (int, float, bool, string, true, false, null), die nun nicht mehr als Klassennamen, Interfacenamen oder Namespacebezeichnungen genutzt werden würden.</p> <p>Unter anderem werden auch einige alte Zöpfe abgeschnitten wie z.B. einige <a href="https://wiki.php.net/rfc/removal_of_dead_sapis_and_exts" target="_blank">alte SAPIs und Extensions</a> und die alten <a href="https://wiki.php.net/rfc/remove_alternative_php_tags" target="_blank">ASP tags (&lt;%) und Script-Tags (&lt;script language=php&gt;)</a> werden entfernt, <a href="https://wiki.php.net/rfc/remove_php4_constructors" target="_blank">alte PHP4-Konstruktoren werden entfernt</a>, und noch mehr <a href="https://wiki.php.net/rfc/remove_deprecated_functionality_in_php7" target="_blank">Extensions (ext/mysql, ext/ereg) und Funktionen die bereits als DEPRECATED markiert waren</a> werden endlich rausgeschmissen. <a href="https://wiki.php.net/rfc/reclassify_e_strict" target="_blank">E_STRICT wird auch entfernt</a> da es kaum genutzt wurde und wenig Sinn macht.</p> <p>In PHP 7 wird man auch weiter weggehen von PEAR und Pecl, hin zu <a href="https://getcomposer.org/" target="_blank">Composer</a> und <a href="https://github.com/FriendsOfPHP/pickle" target="_blank">Pickle</a>. Sich darauf vorzubereiten und daran zu gewöhnen ist sicher auch nicht verkehrt.</p> <h3>Fazit</h3> <p>In den nächsten Monaten ist Testen angesagt, je eher man sich mit den Änderungen befasst und seinen Code schonmal langsam auf PHP 7 vorbereitet, beispielsweise also von mysql_*-Funktionen befreit, umso stressfreier wird der Umstieg Ende des Jahres. Auf GitHub wird die aktuelle PHP 7 nightly Version <a href="https://twitter.com/travisci/status/570616566171242497" target="_blank">bereits von Travis-CI unterstützt</a>, man kann also bereits seinen Code dort testen lassen. Auch gibt es noch viel zu tun um <a href="http://gophp7.org/gophp7-ext/" target="_blank">alle benötigten PHP-Extensions für PHP 7 fertig zu machen</a>, prüft also ob alle eure benötigen Extensions in der Liste sind, und helft im Idealfall dabei sie kompatibel zu machen!</p> <p>Go, PHP 7!</p> <p>PHP 7 wird großartig, ich freue mich schon sehr darauf! Ich hoffe dass der <a href="https://wiki.php.net/rfc/php7timeline" target="_blank">straffe Zeitplan</a> eingehalten werden kann, und wir im Oktober/November die Version 7.0 in den Händen halten.</p> <p>Vor 2 Wochen war der Feature-Freeze, und alle Abstimmungen die noch liefen sind beendet, es stehen also nun mehr oder minder alle Features fest die drin sein werden. Im großen und ganzen wissen wir nun <a href="https://wiki.php.net/rfc#accepted" target="_blank">was uns in PHP 7 alles erwarten wird</a>.</p> <p>Hier stelle ich folgende Features von PHP 7 vor:</p> <ol> <li>Performance</li> <li>Skalare Typehints</li> <li>jsond</li> <li>Coalesce-Operator</li> <li>Engine-Exceptions</li> <li>Kontext-sensitiver Lexer</li> <li>Uniform Variable Syntax</li> <li>Abstract Syntax Tree</li> <li>Neue einheitliche Zufallsfunktionen</li> <li>weiteres</li> </ol> <p><span id="more-6644"></span></p> <h3>1. Performance</h3> <p>Für mich an erster Stelle steht wahrscheinlich die stark gestiegene Performance. In bisherigen Versionen wurde PHP &#8222;nur&#8220; jeweils 5-10% schneller, was kontinuierlich auch ganz gut ist, aber PHP 7 setzt einen oben drauf. Wie bereits in anderen Blogartikeln (<a href="http://www.drupalonwindows.com/en/blog/benchmarking-drupal-7-php-7-dev" target="_blank">1</a> <a href="http://zsuraski.blogspot.com.br/2014/07/benchmarking-phpng.html" target="_blank">2</a> <a href="https://docs.google.com/spreadsheets/d/1qW0avj2eRvPVxj_5V4BBNrOP1ULK7AaXTFsxcffFxT8/edit#gid=746230409" target="_blank">3</a>) aufgezeigt werden wir ein zwischen 70% und 120% schnelleres PHP bekommen gegenüber PHP 5.6. Damit wird PHP 7 ungefähr  genauso schnell sein wie Facebooks HHVM. Geschenkte Performance ohne dass man seine Applikationen umbauen muss ist immer gern gesehen 😉</p> <h3>2. Skalare Typehints</h3> <p>Das nächste sehr interessante Feature werden die <a href="https://wiki.php.net/rfc/scalar_type_hints_v5" target="_blank">skalaren Typehints</a> sein. Mit der Zeit werde ich diese sicherlich einsetzen in Projekten, in denen ich selbst die PHP-Version bestimmen kann und keine Rücksicht auf alte Systeme nehmen muss. Mit den Typehints stark verbunden sind auch die <a href="https://wiki.php.net/rfc/return_types" target="_blank">Return Types</a>, man kann in Zukunft einer Funktion also einen Typ zuordnen die sie zurückzuliefern hat.<br /> Die skalaren Typehints waren eine riesen Diskussion. Jeder will sie, aber man war sich nicht einige wie &#8222;stark&#8220; sie sein sollen. Nun hat man sich auf einen Dual-Mode geeinigt, mit dem jeder hoffentlich halbwegs glücklich werden wird. Hierzu werde ich bald noch einen separaten Blogartikel verfassen, weil das ganze ein recht umfangreiches Thema ist.</p> <h3>3. jsond</h3> <p>PHP wird eine <a href="https://wiki.php.net/rfc/jsond" target="_blank">neue Implementation der JSON-Extension</a> bekommen. Damit werden Lizenzprobleme gelöst, und die neue Variante ist in vielen Fällen (nicht allen) auch schneller, zwischen 20% und 250%. Das ganze passiert unter der Haube, der einzige Unterschied zu vorher ist, dass man json in Zukunft nicht mehr einzeln nachinstallieren muss bei den meisten Linux-Distributionen, sondern es fest eingebaut mitgeliefert wird.</p> <h3>4. Coalesce-Operator</h3> <p>Der sogenannte <a href="https://wiki.php.net/rfc/isset_ternary" target="_blank">Coalesce-Operator</a> könnte auch recht hilfreich sein, man wird sich sicher ein paar Wochen an das &#8222;Aussehen&#8220; gewöhnen müssen, aber ich glaube er gefällt mir sehr gut:</p> <pre class="brush: php; title: ; notranslate" title="">// vorher: $username = isset($_GET&#x5B;'user']) ? $_GET&#x5B;'user'] : 'nobody'; // mit PHP 7: $username = $_GET&#x5B;'user'] ?? 'nobody';</pre> <h3>5. Engine-Exceptions</h3> <p>Die <a href="https://wiki.php.net/rfc/engine_exceptions_for_php7" target="_blank">Engine von PHP darf in Zukunft auch Exceptions werfen</a>. Vorbei sind also die Zeiten von &#8222;Fatal errors&#8220;, zukünftig kann man diese Fehler abfangen und sie behandeln. Beispiel:</p> <pre class="brush: php; title: ; notranslate" title="">function call_method($obj) { $obj-&gt;method(); } call_method(null); // oops!</pre> <p>Aktuell bricht der Code ab mit der Fehlermeldung:</p> <pre class="brush: plain; title: ; notranslate" title="">Fatal error: Call to a member function method() on a non-object in /path/file.php on line 4</pre> <p>Fatale Fehler sind immer doof, denn evtl. wichtiger &#8222;Aufräumcode&#8220; wird nicht mehr aufgerufen. Das kann böse enden.</p> <p>Und so kann man in Zukunft diese Exception abfangen und darauf reagieren:</p> <pre class="brush: php; title: ; notranslate" title="">try { call_method(null); // oops! } catch (EngineException $e) { echo &quot;Exception: {$e-&gt;getMessage()}\n&quot;; }</pre> <h3>6. Kontext-sensitiver Lexer</h3> <p>In Zukunft wird es weniger reservierte Wörter für Funktionsnamen geben. Das ganze nennt sich <a href="https://wiki.php.net/rfc/context_sensitive_lexer" target="_blank">kontext-sensitiver Lexer</a> und bedeutet dass reservierte Wörter wie &#8222;for&#8220; oder &#8222;list&#8220; nicht mehr global verboten werden, sondern je nach Kontext des Gebrauchs erlaubt sein werden. Mit PHP 7 wird folgender Code möglich sein, der aktuell nicht erlaubt ist weil &#8222;for&#8220;, &#8222;and&#8220;, &#8222;or&#8220;, &#8222;list&#8220; reserviert sind und nicht genutzt werden dürfen:</p> <pre class="brush: php; title: ; notranslate" title="">$projects = Finder::for('project') -&gt;where('name')-&gt;like('%secret%') -&gt;and('priority', '&gt;', 9) -&gt;or('code')-&gt;in(&#x5B;'4', '5', '7']) -&gt;and()-&gt;not('created_at')-&gt;between(&#x5B;$time1, $time2]) -&gt;list($limit, $offset);</pre> <h3>7. Uniform Variable Syntax</h3> <p>Durch die <a href="https://wiki.php.net/rfc/uniform_variable_syntax" target="_blank">Uniform Variable Syntax</a> wird man einige schöne neue Zeilen Code schreiben können, für die man bisher häufig temporäre Variablen brauchte. Einige Beispiele:</p> <pre class="brush: php; title: ; notranslate" title="">$foo()&#x5B;'bar']() getStr(){0} $foo-&gt;bar()::baz() $foo-&gt;bar()()</pre> <h3>8. Abstract Syntax Tree</h3> <p>Ein weiteres Feature unter der Haube von PHP 7 wird der <a href="https://wiki.php.net/rfc/abstract_syntax_tree" target="_blank">Abstract Syntax Tree (AST)</a> sein. Das Voting war mit 47:0 sehr eindeutig 😉 Bisher produziert der PHP-Parser direkt OpCodes. In Zukunft wird der Parser als Zwischenstruktur den AST generieren, der dann erstens einige schöne Optimierungen des Codes erlaubt, aber auch entkoppelt er damit den Parser vom Compiler, was die Wartung einfacher machen wird. Wenn der AST zugänglich gemacht wird für Userland/Extensions, dann wird man damit auch super Statische Analyzer bauen könne. Und nebenbei bringt er auch nochmal mehr Performance. Wir dürfen gespannt sein!</p> <h3>9. Neue einheitliche Zufallsfunktionen</h3> <p>PHP hat noch keinen einheitlichen Cryptographically secure pseudo-random number generator (CSPRNG), und wird nun einen bekommen. Kein Gehampel mehr mit openssl_random_pseudo_bytes(), mcrypt_create_iv() und /dev/urandom. Es hilft hoffentlich dabei, dass User bei kryptografischen Aufgaben nicht mehr auf rand() oder ähnliches zurückgreifen sondern die &#8222;richtige&#8220; Funktion dafür nutzen: <a href="https://wiki.php.net/rfc/easy_userland_csprng" target="_blank">random_bytes() bzw. random_int()</a>.</p> <h3>10. weiteres</h3> <p>Zusätzlich zu den genannten Features gibt es noch eine Menge weiterer Änderungen: <a href="https://wiki.php.net/rfc/combined-comparison-operator" target="_blank">Spaceship-Operator</a>, <a href="https://wiki.php.net/rfc/generator-delegation" target="_blank">Generator Delegation</a>, <a href="https://wiki.php.net/rfc/size_t_and_int64_next" target="_blank">besserer 64bit Support</a>, <a href="https://wiki.php.net/rfc/switch.default.multiple" target="_blank">Verbieten von mehreren default-Blöcken</a>, <a href="https://wiki.php.net/rfc/group_use_declarations" target="_blank">Gruppen-&#8222;use&#8220;-Deklarationen</a>, <a href="https://wiki.php.net/rfc#php_70" target="_blank">und und und</a>. Etwas aufpassen muss man bei den <a href="https://wiki.php.net/rfc/reserve_more_types_in_php_7" target="_blank">neuen reservierten Typen</a> (int, float, bool, string, true, false, null), die nun nicht mehr als Klassennamen, Interfacenamen oder Namespacebezeichnungen genutzt werden würden.</p> <p>Unter anderem werden auch einige alte Zöpfe abgeschnitten wie z.B. einige <a href="https://wiki.php.net/rfc/removal_of_dead_sapis_and_exts" target="_blank">alte SAPIs und Extensions</a> und die alten <a href="https://wiki.php.net/rfc/remove_alternative_php_tags" target="_blank">ASP tags (&lt;%) und Script-Tags (&lt;script language=php&gt;)</a> werden entfernt, <a href="https://wiki.php.net/rfc/remove_php4_constructors" target="_blank">alte PHP4-Konstruktoren werden entfernt</a>, und noch mehr <a href="https://wiki.php.net/rfc/remove_deprecated_functionality_in_php7" target="_blank">Extensions (ext/mysql, ext/ereg) und Funktionen die bereits als DEPRECATED markiert waren</a> werden endlich rausgeschmissen. <a href="https://wiki.php.net/rfc/reclassify_e_strict" target="_blank">E_STRICT wird auch entfernt</a> da es kaum genutzt wurde und wenig Sinn macht.</p> <p>In PHP 7 wird man auch weiter weggehen von PEAR und Pecl, hin zu <a href="https://getcomposer.org/" target="_blank">Composer</a> und <a href="https://github.com/FriendsOfPHP/pickle" target="_blank">Pickle</a>. Sich darauf vorzubereiten und daran zu gewöhnen ist sicher auch nicht verkehrt.</p> <h3>Fazit</h3> <p>In den nächsten Monaten ist Testen angesagt, je eher man sich mit den Änderungen befasst und seinen Code schonmal langsam auf PHP 7 vorbereitet, beispielsweise also von mysql_*-Funktionen befreit, umso stressfreier wird der Umstieg Ende des Jahres. Auf GitHub wird die aktuelle PHP 7 nightly Version <a href="https://twitter.com/travisci/status/570616566171242497" target="_blank">bereits von Travis-CI unterstützt</a>, man kann also bereits seinen Code dort testen lassen. Auch gibt es noch viel zu tun um <a href="http://gophp7.org/gophp7-ext/" target="_blank">alle benötigten PHP-Extensions für PHP 7 fertig zu machen</a>, prüft also ob alle eure benötigen Extensions in der Liste sind, und helft im Idealfall dabei sie kompatibel zu machen!</p> <p>Go, PHP 7!</p> https://phpgangsta.de/php-7-feature-freeze/feed 3 Ein altes Navigationsmenu sortieren https://phpgangsta.de/ein-altes-navigationsmenu-sortieren https://phpgangsta.de/ein-altes-navigationsmenu-sortieren#comments Wed, 11 Mar 2015 21:58:12 +0000 http://www.phpgangsta.de/?p=6635 <p>Ich habe eine kleine Programmieraufgabe für euch.</p> <p>Ich habe ein altes Projekt, in dem ich folgende Navigationsstruktur in der Datenbank habe:</p> <table id="tablepress-26" class="tablepress tablepress-id-26"> <thead> <tr class="row-1 odd"> <th class="column-1">menuid</th><th class="column-2">parentid</th><th class="column-3">title</th><th class="column-4">level</th><th class="column-5">sortid</th> </tr> </thead> <tbody> <tr class="row-2 even"> <td class="column-1">1</td><td class="column-2">3</td><td class="column-3">Wurm 1.1</td><td class="column-4">2</td><td class="column-5">10</td> </tr> <tr class="row-3 odd"> <td class="column-1">2</td><td class="column-2">6</td><td class="column-3">Vogel 2.1</td><td class="column-4">2</td><td class="column-5">30</td> </tr> <tr class="row-4 even"> <td class="column-1">3</td><td class="column-2">0</td><td class="column-3">Tiger 1</td><td class="column-4">1</td><td class="column-5">10</td> </tr> <tr class="row-5 odd"> <td class="column-1">4</td><td class="column-2">6</td><td class="column-3">Hund 2.2</td><td class="column-4">2</td><td class="column-5">40</td> </tr> <tr class="row-6 even"> <td class="column-1">5</td><td class="column-2">3</td><td class="column-3">Katze 1.2</td><td class="column-4">2</td><td class="column-5">11</td> </tr> <tr class="row-7 odd"> <td class="column-1">6</td><td class="column-2">0</td><td class="column-3">Pferd 2</td><td class="column-4">1</td><td class="column-5">20</td> </tr> <tr class="row-8 even"> <td class="column-1">7</td><td class="column-2">1</td><td class="column-3">Baer 1.1.1</td><td class="column-4">3</td><td class="column-5">0</td> </tr> <tr class="row-9 odd"> <td class="column-1">8</td><td class="column-2">3</td><td class="column-3">Schwein 1.3</td><td class="column-4">2</td><td class="column-5">12</td> </tr> <tr class="row-10 even"> <td class="column-1">9</td><td class="column-2">4</td><td class="column-3">Esel 2.2.1</td><td class="column-4">3</td><td class="column-5">0</td> </tr> </tbody> </table> <!-- #tablepress-26 from cache --> <p>Nun möchte ich diese Menüpunkte sortiert ausgeben, und zwar in der folgenden Reihenfolge:</p> <pre class="brush: plain; title: ; notranslate" title="">Tiger 1 Wurm 1.1 Baer 1.1.1 Katze 1.2 Schwein 1.3 Pferd 2 Vogel 2.1 Hund 2.2 Esel 2.2.1</pre> <p>Die Sortierreihenfolge muss anhand der menuid, parentid, level und sortid berechnet werden. Eine parentid verweist auf den Elternknoten, sprich er ist darunter einzusortieren. Zwei Einträge mit der selben parentid sind nach der Spalte sortid zu sortieren.</p> <p>Der Wurm ist ein Kindknoten vom Tiger, der Bär ist ein Kindknoten vom Wurm. Die Katze ist auch ein Kindknoten vom Tiger, hat aber die höhere sortid, muss also nach dem Wurm einsortiert werden.</p> <p>Es ist ein altes Projekt mit dieser Struktur, und die Frage ist wie man das am einfachsten und schnellsten sortiert?</p> <p>Geht das ganze mit einem SQL-Query? Das wäre natürlich die beste Lösung, aber mir ist kein solcher Query eingefallen der das Problem lösen könnte.</p> <p>Also muss es in PHP sortiert werden. Ich habe das ganze in ein PHP-Array gepackt und hier für euch zum Spielen bereitgestellt:</p> <p><a href="http://3v4l.org/PTuRc" target="_blank">http://3v4l.org/PTuRc</a></p> <p>Dort könnt ihr an dem Algorithmus arbeiten, sodass aus dem Ursprungs-Array das Ziel-Array wird. Nachdem ihr &#8222;eval()&#8220; gedrückt habt könnt ihr einfach die URL hier in die Kommentare packen, nach jedem Druck auf &#8222;eval()&#8220; wird das ganze gespeichert und versioniert.</p> <p>Ich bin gespannt auf eure Lösungen!</p> <p>Ich habe eine kleine Programmieraufgabe für euch.</p> <p>Ich habe ein altes Projekt, in dem ich folgende Navigationsstruktur in der Datenbank habe:</p> <table id="tablepress-26" class="tablepress tablepress-id-26"> <thead> <tr class="row-1 odd"> <th class="column-1">menuid</th><th class="column-2">parentid</th><th class="column-3">title</th><th class="column-4">level</th><th class="column-5">sortid</th> </tr> </thead> <tbody> <tr class="row-2 even"> <td class="column-1">1</td><td class="column-2">3</td><td class="column-3">Wurm 1.1</td><td class="column-4">2</td><td class="column-5">10</td> </tr> <tr class="row-3 odd"> <td class="column-1">2</td><td class="column-2">6</td><td class="column-3">Vogel 2.1</td><td class="column-4">2</td><td class="column-5">30</td> </tr> <tr class="row-4 even"> <td class="column-1">3</td><td class="column-2">0</td><td class="column-3">Tiger 1</td><td class="column-4">1</td><td class="column-5">10</td> </tr> <tr class="row-5 odd"> <td class="column-1">4</td><td class="column-2">6</td><td class="column-3">Hund 2.2</td><td class="column-4">2</td><td class="column-5">40</td> </tr> <tr class="row-6 even"> <td class="column-1">5</td><td class="column-2">3</td><td class="column-3">Katze 1.2</td><td class="column-4">2</td><td class="column-5">11</td> </tr> <tr class="row-7 odd"> <td class="column-1">6</td><td class="column-2">0</td><td class="column-3">Pferd 2</td><td class="column-4">1</td><td class="column-5">20</td> </tr> <tr class="row-8 even"> <td class="column-1">7</td><td class="column-2">1</td><td class="column-3">Baer 1.1.1</td><td class="column-4">3</td><td class="column-5">0</td> </tr> <tr class="row-9 odd"> <td class="column-1">8</td><td class="column-2">3</td><td class="column-3">Schwein 1.3</td><td class="column-4">2</td><td class="column-5">12</td> </tr> <tr class="row-10 even"> <td class="column-1">9</td><td class="column-2">4</td><td class="column-3">Esel 2.2.1</td><td class="column-4">3</td><td class="column-5">0</td> </tr> </tbody> </table> <!-- #tablepress-26 from cache --> <p>Nun möchte ich diese Menüpunkte sortiert ausgeben, und zwar in der folgenden Reihenfolge:</p> <pre class="brush: plain; title: ; notranslate" title="">Tiger 1 Wurm 1.1 Baer 1.1.1 Katze 1.2 Schwein 1.3 Pferd 2 Vogel 2.1 Hund 2.2 Esel 2.2.1</pre> <p>Die Sortierreihenfolge muss anhand der menuid, parentid, level und sortid berechnet werden. Eine parentid verweist auf den Elternknoten, sprich er ist darunter einzusortieren. Zwei Einträge mit der selben parentid sind nach der Spalte sortid zu sortieren.</p> <p>Der Wurm ist ein Kindknoten vom Tiger, der Bär ist ein Kindknoten vom Wurm. Die Katze ist auch ein Kindknoten vom Tiger, hat aber die höhere sortid, muss also nach dem Wurm einsortiert werden.</p> <p>Es ist ein altes Projekt mit dieser Struktur, und die Frage ist wie man das am einfachsten und schnellsten sortiert?</p> <p>Geht das ganze mit einem SQL-Query? Das wäre natürlich die beste Lösung, aber mir ist kein solcher Query eingefallen der das Problem lösen könnte.</p> <p>Also muss es in PHP sortiert werden. Ich habe das ganze in ein PHP-Array gepackt und hier für euch zum Spielen bereitgestellt:</p> <p><a href="http://3v4l.org/PTuRc" target="_blank">http://3v4l.org/PTuRc</a></p> <p>Dort könnt ihr an dem Algorithmus arbeiten, sodass aus dem Ursprungs-Array das Ziel-Array wird. Nachdem ihr &#8222;eval()&#8220; gedrückt habt könnt ihr einfach die URL hier in die Kommentare packen, nach jedem Druck auf &#8222;eval()&#8220; wird das ganze gespeichert und versioniert.</p> <p>Ich bin gespannt auf eure Lösungen!</p> https://phpgangsta.de/ein-altes-navigationsmenu-sortieren/feed 12 Erstaunlich langsam beim Kopieren einer Datei auf ein NFS-Share https://phpgangsta.de/erstaunlich-langsam-beim-kopieren-einer-datei-auf-ein-nfs-share https://phpgangsta.de/erstaunlich-langsam-beim-kopieren-einer-datei-auf-ein-nfs-share#comments Tue, 03 Mar 2015 09:46:16 +0000 http://www.phpgangsta.de/?p=6627 <p>Heute mal etwas skurriles. Eigentlich eine Alltagsaufgabe, die man mit einem 2-Zeiler lösen kann, aber ich bin doch erstaunt über das Problem und die Lösung. Es geht darum, eine Datei auf einem NFS-Share abzulegen, das vorher per PUT zum Webserver hochgeladen wurde. Wahrscheinlich hat man das selbe Problem auch wenn die Datei per POST-Formular hochgeladen wurde.</p> <p>Folgender Aufruf lädt eine Datei via PUT auf einen Webserver:</p> <pre class="brush: bash; title: ; notranslate" title="">curl -T 100mb.test http://localhost/put.php</pre> <p>Mein einfaches Testscript, das die Datei auf das NFS-Share legen soll, sieht so aus:</p> <p><span id="more-6627"></span></p> <pre class="brush: php; title: ; notranslate" title="">&lt;? $putdata = fopen(&quot;php://input&quot;, &quot;r&quot;); file_put_contents('/mnt/nfs/100mb.zip', $putdata);</pre> <p>Es dauert knapp 26 Sekunden bis das Script fertig ist bei einer 100MB Datei. Das muss doch schneller gehen! 4MB/s ist viel zu wenig für ein Gigabit-Netzwerk und einen schnellen NFS-Storage.</p> <p>Nächster Versuch:</p> <pre class="brush: php; title: ; notranslate" title="">&lt;? $putdata = fopen(&quot;php://input&quot;, &quot;r&quot;); file_put_contents('/tmp/100mb.zip', $putdata); copy('/tmp/100mb.zip', '/mnt/nfs/100mb.zip');</pre> <p>Hier gehe ich den Umweg über die lokale Festplatte. Ich speichere die Datei erst lokal auf dem Webserver, und kopiere sie dann auf das NFS-Share. Das file_put_contents() auf die lokale Festplatte dauert knapp 1 Sekunde, das ist kein Problem. Aber der copy()-Befehl ist wieder recht langsam, 21 Sekunden, sprich 5MB/s. Was ist denn nur los?</p> <p>(Die PHP-Funktion rename(), die normalerweise dafür das ist eine Datei zu verschieben, kann ich nicht nutzen da man die Funktion nur zum Verschieben auf einer Partition nutzen kann, und ich die Datei auf ein NFS-Share ablegen möchte.)</p> <p>Um mich zu vergewissern dass es nicht am Netzwerk oder am NFS-Storage liegt mache ich einen Test per SSH:</p> <pre class="brush: bash; title: ; notranslate" title="">time cp 100mb.zip /mnt/nfs/100mb.zip real    0m4.236s user    0m0.007s sys     0m0.144s</pre> <p>Aha! Es geht doch! 4 Sekunden, sprich 25MB/s, das ist doch schon viel besser.</p> <p>Nächster Versuch:</p> <pre class="brush: php; title: ; notranslate" title="">&lt;? $putdata = fopen(&quot;php://input&quot;, &quot;r&quot;); file_put_contents('/tmp/100mb.zip', $putdata); shell_exec(&quot;cp /tmp/100mb.zip /mnt/nfs/100mb.zip&quot;);</pre> <p>Die Laufzeit dieses Scripts ist nur 5 Sekunden! Ich muss also die Datei erstmal lokal auf die Festplatte schreiben, um sie dann mit dem System-Befehl &#8222;cp&#8220; auf das NFS-Share zu kopieren.</p> <p>Warum ist &#8222;cp&#8220; so viel schneller als copy()? Ich hätte getippt dass PHP intern etwas ähnliches macht oder sogar das selbe? Oder ist die &#8222;cp&#8220;-Funktion deutlich im Vorteil weil sie den Filesystem-Cache oder Kernel-Cache oder ähnliches ausnutzen kann, was die copy()-Funktion nicht tut? Oder liegt es daran dass sowohl file_put_contents() als auch copy() intern immer in kleinen Häppchen vorgeht: &#8222;4KB lesen, 4KB schreiben, 4KB lesen, 4KB schreiben&#8230;&#8220;, und dass das sehr unperformant für eine NFS-Verbindung ist?</p> <p>Kann mir das jemand erklären? Warum ist PHP so schlecht darin eine Datei auf ein NFS-Share zu kopieren?</p> <p>Ich nutze in diesem Fall PHP 5.5.9-1ubuntu4.6</p> <p>Ich bin dankbar über jeden Ratschlag.</p> <p>Heute mal etwas skurriles. Eigentlich eine Alltagsaufgabe, die man mit einem 2-Zeiler lösen kann, aber ich bin doch erstaunt über das Problem und die Lösung. Es geht darum, eine Datei auf einem NFS-Share abzulegen, das vorher per PUT zum Webserver hochgeladen wurde. Wahrscheinlich hat man das selbe Problem auch wenn die Datei per POST-Formular hochgeladen wurde.</p> <p>Folgender Aufruf lädt eine Datei via PUT auf einen Webserver:</p> <pre class="brush: bash; title: ; notranslate" title="">curl -T 100mb.test http://localhost/put.php</pre> <p>Mein einfaches Testscript, das die Datei auf das NFS-Share legen soll, sieht so aus:</p> <p><span id="more-6627"></span></p> <pre class="brush: php; title: ; notranslate" title="">&lt;? $putdata = fopen(&quot;php://input&quot;, &quot;r&quot;); file_put_contents('/mnt/nfs/100mb.zip', $putdata);</pre> <p>Es dauert knapp 26 Sekunden bis das Script fertig ist bei einer 100MB Datei. Das muss doch schneller gehen! 4MB/s ist viel zu wenig für ein Gigabit-Netzwerk und einen schnellen NFS-Storage.</p> <p>Nächster Versuch:</p> <pre class="brush: php; title: ; notranslate" title="">&lt;? $putdata = fopen(&quot;php://input&quot;, &quot;r&quot;); file_put_contents('/tmp/100mb.zip', $putdata); copy('/tmp/100mb.zip', '/mnt/nfs/100mb.zip');</pre> <p>Hier gehe ich den Umweg über die lokale Festplatte. Ich speichere die Datei erst lokal auf dem Webserver, und kopiere sie dann auf das NFS-Share. Das file_put_contents() auf die lokale Festplatte dauert knapp 1 Sekunde, das ist kein Problem. Aber der copy()-Befehl ist wieder recht langsam, 21 Sekunden, sprich 5MB/s. Was ist denn nur los?</p> <p>(Die PHP-Funktion rename(), die normalerweise dafür das ist eine Datei zu verschieben, kann ich nicht nutzen da man die Funktion nur zum Verschieben auf einer Partition nutzen kann, und ich die Datei auf ein NFS-Share ablegen möchte.)</p> <p>Um mich zu vergewissern dass es nicht am Netzwerk oder am NFS-Storage liegt mache ich einen Test per SSH:</p> <pre class="brush: bash; title: ; notranslate" title="">time cp 100mb.zip /mnt/nfs/100mb.zip real    0m4.236s user    0m0.007s sys     0m0.144s</pre> <p>Aha! Es geht doch! 4 Sekunden, sprich 25MB/s, das ist doch schon viel besser.</p> <p>Nächster Versuch:</p> <pre class="brush: php; title: ; notranslate" title="">&lt;? $putdata = fopen(&quot;php://input&quot;, &quot;r&quot;); file_put_contents('/tmp/100mb.zip', $putdata); shell_exec(&quot;cp /tmp/100mb.zip /mnt/nfs/100mb.zip&quot;);</pre> <p>Die Laufzeit dieses Scripts ist nur 5 Sekunden! Ich muss also die Datei erstmal lokal auf die Festplatte schreiben, um sie dann mit dem System-Befehl &#8222;cp&#8220; auf das NFS-Share zu kopieren.</p> <p>Warum ist &#8222;cp&#8220; so viel schneller als copy()? Ich hätte getippt dass PHP intern etwas ähnliches macht oder sogar das selbe? Oder ist die &#8222;cp&#8220;-Funktion deutlich im Vorteil weil sie den Filesystem-Cache oder Kernel-Cache oder ähnliches ausnutzen kann, was die copy()-Funktion nicht tut? Oder liegt es daran dass sowohl file_put_contents() als auch copy() intern immer in kleinen Häppchen vorgeht: &#8222;4KB lesen, 4KB schreiben, 4KB lesen, 4KB schreiben&#8230;&#8220;, und dass das sehr unperformant für eine NFS-Verbindung ist?</p> <p>Kann mir das jemand erklären? Warum ist PHP so schlecht darin eine Datei auf ein NFS-Share zu kopieren?</p> <p>Ich nutze in diesem Fall PHP 5.5.9-1ubuntu4.6</p> <p>Ich bin dankbar über jeden Ratschlag.</p> https://phpgangsta.de/erstaunlich-langsam-beim-kopieren-einer-datei-auf-ein-nfs-share/feed 6 Eine PLZ-Umkreissuche in PHP https://phpgangsta.de/eine-plz-umkreissuche-in-php https://phpgangsta.de/eine-plz-umkreissuche-in-php#comments Sun, 22 Feb 2015 15:22:33 +0000 http://www.phpgangsta.de/?p=6615 <p>Ich bekam vor ein paar Tagen folgende kleine Programmieraufgabe:</p> <blockquote><p>Gegeben ist eine große Datenbank mit &gt; 300.000 Kunden, worin jeder Kunde eine Postleitzahl hinterlegt hat. Firma X möchte nun diese Kunden kontaktieren, aber nur diejenigen die in 35km Umkreis um eine seiner 42 Filialen wohnen.</p></blockquote> <p>Tja, wie macht man das?</p> <p><span id="more-6615"></span>Die einfachste Lösung die mir in den Sinn kam war eine Geo-Datenbank zu nutzen, in der deutsche Postleitzahlen und deren Latitude+Longitude hinterlegt sind. Dann durchlaufe ich die gegebenen 42 Postleitzahlen der Filialen und berechne jeweils die Distanz zu allen 17052 Postleitzahlen die es in Deutschland gibt. Wenn die Distanz unter 35 Kilometer beträgt kommt die PLZ in ein Ergebnis-Array. Am Ende filtere ich noch die doppelten raus, fertig.</p> <p><img decoding="async" class="alignright size-full wp-image-6621" src="https://www.phpgangsta.de/wp-content/uploads/opengeodb.png" alt="OpenGeoDB" width="135" height="135" />Aufgabe 1 war also eine Geo-Datenbank mit Postleitzahlen für Deutschland zu finden. Ich wurde fündig bei der <a href="http://opengeodb.org" target="_blank">OpenGeoDB</a>.</p> <p>Aufgabe 2 war doch etwas schwieriger als gedacht: Den Datenbank-Dump zu importieren in meine MySQL-Datenbank und in ein Format zu bekommen das ich benutzen kann. Um die OpenGeoDB in meine MySQL zu importieren musste ich leider nicht nur einen SQL-Dump importieren, sondern ein paar Schritte beachten, die aber nach etwas Suche im Wiki beschrieben sind. Die Schritte lauten:</p> <ul> <li>Ersetzen von &#8222;TYPE=InnoDB&#8220; durch &#8222;ENGINE=InnoDB&#8220;, da ich eine MySQL 5.6. Datenbank habe</li> <li>opengeodb-begin.sql importieren</li> <li>DE.sql importieren</li> <li>DEhier.sql importieren</li> <li>opengeod-end.sql importieren</li> </ul> <p>Gerade bei den beiden großen Dumps musste ich zwischendurch abbrechen, &#8222;BEGIN;&#8220;  und &#8222;COMMIT;&#8220; einfügen oben und unten, und dann nochmal laufen lassen, denn ohne diese Transaktion war der Import sehr sehr langsam.</p> <p>Aufgabe 3: Dann hatte ich die Rohdaten in meiner Datenbank. Die OpenGeoDB ist relativ groß da sie viele Daten zu Städten, Landkreisen, Postleitzahlen usw. enthält. Ich habe anhand <a href="http://opengeodb.org/wiki/OpenGeoDB_-_Umkreissuche" target="_blank">dieser Anleitung</a> (die genau das zeigt was ich vorhabe) als nächstes eine Zwischentabelle &#8222;zip_coordinates&#8220; erstellt, die nur Postleitzahlen und Latitude+Longitude enthält.</p> <p>Folgendes kleines Script lieferte mir dann die Ergebnisse, die ich haben wollte:</p> <pre class="brush: php; title: ; notranslate" title="">&lt;?php $sourceZipCodes = array(59302,50667,38855,57271,38518,23730); $distance = 35; $resultingZipCodes = array(); $dbh = new PDO('mysql:host=127.0.0.1;dbname=opengeodb', 'opengeodb', 'secretpassword'); $getZcIdStmt = $dbh-&gt;prepare(&quot;SELECT zc_id FROM zip_coordinates WHERE zc_zip = :zip&quot;); $getZipList = $dbh-&gt;prepare(&quot;SELECT dest.zc_zip, dest.zc_location_name, ACOS( SIN(RADIANS(src.zc_lat)) * SIN(RADIANS(dest.zc_lat)) + COS(RADIANS(src.zc_lat)) * COS(RADIANS(dest.zc_lat)) * COS(RADIANS(src.zc_lon) - RADIANS(dest.zc_lon)) ) * 6380 AS distance FROM zip_coordinates dest CROSS JOIN zip_coordinates src WHERE src.zc_id = :zcid AND dest.zc_id &lt;&gt; src.zc_id HAVING distance &lt; :distance ORDER BY distance;&quot;); foreach ($sourceZipCodes as $sourceZipCode) { $getZcIdStmt-&gt;execute(array(':zip' =&gt; $sourceZipCode)); $row = $getZcIdStmt-&gt;fetch(); $getZipList-&gt;execute(array(':zcid' =&gt; $row&#x5B;'zc_id'], ':distance' =&gt; $distance)); $zipList = $getZipList-&gt;fetchAll(); foreach ($zipList as $zipResult) { if (!in_array($zipResult&#x5B;'zc_zip'], $resultingZipCodes)) { $resultingZipCodes&#x5B;] = $zipResult&#x5B;'zc_zip']; } } } echo join(',', $resultingZipCodes);</pre> <p>Den etwas komplizierteren SQL-Query habe ich aus dem besagten Wiki-Artikel, den hätte ich selbst nur schwerlich erstellen können in kurzer Zeit.</p> <p>Das war es eigentlich schon. Aus der Liste mit den gegebenen 42 Postleitzahlen kam eine Liste mit 3028 Postleitzahlen heraus, die ich dann gegen die Kundendatenbank habe laufen lassen, und schon wusste ich wie viele und welche Kunden im 35km Umkreis der 42 Filialen wohnen.</p> <p>Bevor jemand fragt: Die OpenGeoDB enthält neben den Daten für Deutschland auch Daten aus Österreich, Belgien, Schweiz und Lichtenstein. Damit müsste das ganze äquivalent möglich sein.</p> <p>Ich bekam vor ein paar Tagen folgende kleine Programmieraufgabe:</p> <blockquote><p>Gegeben ist eine große Datenbank mit &gt; 300.000 Kunden, worin jeder Kunde eine Postleitzahl hinterlegt hat. Firma X möchte nun diese Kunden kontaktieren, aber nur diejenigen die in 35km Umkreis um eine seiner 42 Filialen wohnen.</p></blockquote> <p>Tja, wie macht man das?</p> <p><span id="more-6615"></span>Die einfachste Lösung die mir in den Sinn kam war eine Geo-Datenbank zu nutzen, in der deutsche Postleitzahlen und deren Latitude+Longitude hinterlegt sind. Dann durchlaufe ich die gegebenen 42 Postleitzahlen der Filialen und berechne jeweils die Distanz zu allen 17052 Postleitzahlen die es in Deutschland gibt. Wenn die Distanz unter 35 Kilometer beträgt kommt die PLZ in ein Ergebnis-Array. Am Ende filtere ich noch die doppelten raus, fertig.</p> <p><img decoding="async" class="alignright size-full wp-image-6621" src="https://www.phpgangsta.de/wp-content/uploads/opengeodb.png" alt="OpenGeoDB" width="135" height="135" />Aufgabe 1 war also eine Geo-Datenbank mit Postleitzahlen für Deutschland zu finden. Ich wurde fündig bei der <a href="http://opengeodb.org" target="_blank">OpenGeoDB</a>.</p> <p>Aufgabe 2 war doch etwas schwieriger als gedacht: Den Datenbank-Dump zu importieren in meine MySQL-Datenbank und in ein Format zu bekommen das ich benutzen kann. Um die OpenGeoDB in meine MySQL zu importieren musste ich leider nicht nur einen SQL-Dump importieren, sondern ein paar Schritte beachten, die aber nach etwas Suche im Wiki beschrieben sind. Die Schritte lauten:</p> <ul> <li>Ersetzen von &#8222;TYPE=InnoDB&#8220; durch &#8222;ENGINE=InnoDB&#8220;, da ich eine MySQL 5.6. Datenbank habe</li> <li>opengeodb-begin.sql importieren</li> <li>DE.sql importieren</li> <li>DEhier.sql importieren</li> <li>opengeod-end.sql importieren</li> </ul> <p>Gerade bei den beiden großen Dumps musste ich zwischendurch abbrechen, &#8222;BEGIN;&#8220;  und &#8222;COMMIT;&#8220; einfügen oben und unten, und dann nochmal laufen lassen, denn ohne diese Transaktion war der Import sehr sehr langsam.</p> <p>Aufgabe 3: Dann hatte ich die Rohdaten in meiner Datenbank. Die OpenGeoDB ist relativ groß da sie viele Daten zu Städten, Landkreisen, Postleitzahlen usw. enthält. Ich habe anhand <a href="http://opengeodb.org/wiki/OpenGeoDB_-_Umkreissuche" target="_blank">dieser Anleitung</a> (die genau das zeigt was ich vorhabe) als nächstes eine Zwischentabelle &#8222;zip_coordinates&#8220; erstellt, die nur Postleitzahlen und Latitude+Longitude enthält.</p> <p>Folgendes kleines Script lieferte mir dann die Ergebnisse, die ich haben wollte:</p> <pre class="brush: php; title: ; notranslate" title="">&lt;?php $sourceZipCodes = array(59302,50667,38855,57271,38518,23730); $distance = 35; $resultingZipCodes = array(); $dbh = new PDO('mysql:host=127.0.0.1;dbname=opengeodb', 'opengeodb', 'secretpassword'); $getZcIdStmt = $dbh-&gt;prepare(&quot;SELECT zc_id FROM zip_coordinates WHERE zc_zip = :zip&quot;); $getZipList = $dbh-&gt;prepare(&quot;SELECT dest.zc_zip, dest.zc_location_name, ACOS( SIN(RADIANS(src.zc_lat)) * SIN(RADIANS(dest.zc_lat)) + COS(RADIANS(src.zc_lat)) * COS(RADIANS(dest.zc_lat)) * COS(RADIANS(src.zc_lon) - RADIANS(dest.zc_lon)) ) * 6380 AS distance FROM zip_coordinates dest CROSS JOIN zip_coordinates src WHERE src.zc_id = :zcid AND dest.zc_id &lt;&gt; src.zc_id HAVING distance &lt; :distance ORDER BY distance;&quot;); foreach ($sourceZipCodes as $sourceZipCode) { $getZcIdStmt-&gt;execute(array(':zip' =&gt; $sourceZipCode)); $row = $getZcIdStmt-&gt;fetch(); $getZipList-&gt;execute(array(':zcid' =&gt; $row&#x5B;'zc_id'], ':distance' =&gt; $distance)); $zipList = $getZipList-&gt;fetchAll(); foreach ($zipList as $zipResult) { if (!in_array($zipResult&#x5B;'zc_zip'], $resultingZipCodes)) { $resultingZipCodes&#x5B;] = $zipResult&#x5B;'zc_zip']; } } } echo join(',', $resultingZipCodes);</pre> <p>Den etwas komplizierteren SQL-Query habe ich aus dem besagten Wiki-Artikel, den hätte ich selbst nur schwerlich erstellen können in kurzer Zeit.</p> <p>Das war es eigentlich schon. Aus der Liste mit den gegebenen 42 Postleitzahlen kam eine Liste mit 3028 Postleitzahlen heraus, die ich dann gegen die Kundendatenbank habe laufen lassen, und schon wusste ich wie viele und welche Kunden im 35km Umkreis der 42 Filialen wohnen.</p> <p>Bevor jemand fragt: Die OpenGeoDB enthält neben den Daten für Deutschland auch Daten aus Österreich, Belgien, Schweiz und Lichtenstein. Damit müsste das ganze äquivalent möglich sein.</p> https://phpgangsta.de/eine-plz-umkreissuche-in-php/feed 15 Aktueller Stand von PHP 7: Deutlich geringerer Arbeitsspeicherverbrauch https://phpgangsta.de/aktueller-stand-von-php-7-deutlich-geringerer-arbeitsspeicherverbrauch https://phpgangsta.de/aktueller-stand-von-php-7-deutlich-geringerer-arbeitsspeicherverbrauch#comments Wed, 21 Jan 2015 11:56:47 +0000 http://www.phpgangsta.de/?p=6600 <p>Ich möchte mir den aktuellen Stand von PHP 7 anschauen (Stand 20. Januar 2015), und habe dazu im letzten Blogartikel gezeigt <a href="https://www.phpgangsta.de/den-aktuellen-stand-von-php-7-pre-alpha-selbst-kompilieren-und-testen">wie man PHP 7 direkt aus dem Git-Repository selbst kompiliert</a>. Ich habe nun also PHP 7 zur Verfügung:</p> <pre class="brush: bash; title: ; notranslate" title="">$ sapi/cli/php -v PHP 7.0.0-dev (cli) (built: Jan 20 2015 23:13:58) Copyright (c) 1997-2015 The PHP Group Zend Engine v3.0.0-dev, Copyright (c) 1998-2015 Zend Technologies</pre> <p>Vergleichen werde ich mit der aktuell unter Ubuntu 14.04 LTS verfügbaren Version PHP 5.5.9:</p> <pre class="brush: bash; title: ; notranslate" title="">$ php -v PHP 5.5.9-1ubuntu4.5 (cli) (built: Oct 29 2014 11:59:10) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies with Zend OPcache v7.0.3, Copyright (c) 1999-2014, by Zend Technologies</pre> <p>Da die eine Version selbst kompiliert ist und die andere von Ubuntu stammt sind sie in diesem Fall nicht ideal für einen Vergleich nutzbar, aber auf ein paar Bytes oder Prozente soll es mir nicht ankommen.</p> <p>PHP 7 hat in diesem Fall keinen OPcache aktiviert, aber den benötige ich für meine Tests auf der Kommandozeile (CLI) nicht. Möchte man PHP via Webserver (PHP-FPM usw.) nutzen sollte man darauf achten den OPcache per php.ini zu aktivieren, um vergleichbare Ergebnisse zu bekommen.</p> <p>Folgendes kleines Testscript werde ich mit beiden Versionen laufen lassen:</p> <pre class="brush: php; title: ; notranslate" title="">&lt;?php $a = array(); for ($i=1; $i&lt;2000000; $i++) { $a&#x5B;] = rand(100000000, 999999999); } echo &quot;not real: &quot;.(memory_get_peak_usage(false)/1024/1024).&quot; MiB\n&quot;; echo &quot;real: &quot;.(memory_get_peak_usage(true)/1024/1024).&quot; MiB\n&quot;;</pre> <p>Und hier sind die jeweiligen Ergebnisse:</p> <pre class="brush: bash; title: ; notranslate" title="">$ time php arraytest.php not real: 275.61262512207 MiB real: 276 MiB real    0m1.119s user    0m0.763s sys     0m0.190s</pre> <pre class="brush: bash; title: ; notranslate" title="">$ $ time sapi/cli/php arraytest.php not real: 96.334381103516 MiB real: 98 MiB real    0m0.414s user    0m0.290s sys     0m0.068s</pre> <p>Ui ui ui! Mit PHP 7 reduziert sich der Arbeitsspeicherverbrauch bei diesem Testarray (2.000.000 Zahlen als Values) um satte 65%!</p> <p>Weniger Arbeitsspeicherverbrauch heißt nicht nur dass &#8222;mehr PHP&#8220; auf einem Server laufen kann, weniger Arbeitsspeicher heißt auch dass weniger Daten im Arbeitsspeicher abgelegt werden müssen, und weniger daraus gelesen werden muss, es impliziert also automatisch auch einen Performance-Boost. Wie man an den Laufzeiten erkennen kann ist PHP 7 auch ungefähr 3 Mal so schnell!</p> <p>In richtigen Applikationen wie WordPress oder Typo3 usw. ist der Unterschied nicht ganz so groß, da spricht man <a href="http://zsuraski.blogspot.de/2014/07/benchmarking-phpng.html" target="_blank">von ungefähr 50% bis 110% mehr Laufzeit-Performance</a>. Denn bei größeren Applikationen wird auch viel Zeit beim Warten auf die Datenbank verbraucht, und Warten ist genauso langsam in PHP 5.5 wie in PHP 7 😉</p> <p>All diese Verbesserungen sind darauf zurückzuführen <a href="http://nikic.github.io/2011/12/12/How-big-are-PHP-arrays-really-Hint-BIG.html" target="_blank">wie PHP intern Variablen und Arrays organisiert</a>, den sogenannten ZVALs und Hashtables. Die detaillierten Informationen über die <a href="http://nikic.github.io/2014/12/22/PHPs-new-hashtable-implementation.html" target="_blank">Änderungen an der Hashtable-Implementation von PHP 7</a> sollte man sich mal zu Gemüte führen.</p> <p><strong>Edit:</strong> Auf Wunsch habe ich auch noch PHP 5.6 getestet, hier die Ergebnisse:</p> <pre class="brush: plain; title: ; notranslate" title="">wget http://de2.php.net/get/php-5.6.5.tar.gz/from/this/mirror mv mirror php-5.6.5.tar.gz tar -xzvf php-5.6.5.tar.gz cd php-5.6.5/ ./configure --prefix=/usr/local/php-5.6.5 --with-zlib --with-config-file-path=/usr/local/php-5.6.5/etc --enable-mbstring --with-mysql --with-mysqli --with-pdo-mysql --enable-zip --with-imap --with-kerberos --with-imap-ssl --with-openssl --with-jpeg-dir --with-gd --with-gettext --with-freetype-dir --enable-ftp --with-pspell --with-curl make</pre> <pre class="brush: plain; title: ; notranslate" title="">$ sapi/cli/php -v PHP 5.6.5 (cli) (built: Jan 23 2015 00:46:40) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies</pre> <pre class="brush: plain; title: ; notranslate" title="">$ time sapi/cli/php -d memory_limit=512M arraytest.php not real: 275.61260223389 MiB real: 276 MiB real    0m1.023s user    0m0.663s sys     0m0.170s</pre> <p>PHP 5.6 ist also leicht schneller als PHP 5.5, aber zu PHP 7 ist es immer noch ein richtig großer Unterschied.</p> <p>Ich möchte mir den aktuellen Stand von PHP 7 anschauen (Stand 20. Januar 2015), und habe dazu im letzten Blogartikel gezeigt <a href="https://www.phpgangsta.de/den-aktuellen-stand-von-php-7-pre-alpha-selbst-kompilieren-und-testen">wie man PHP 7 direkt aus dem Git-Repository selbst kompiliert</a>. Ich habe nun also PHP 7 zur Verfügung:</p> <pre class="brush: bash; title: ; notranslate" title="">$ sapi/cli/php -v PHP 7.0.0-dev (cli) (built: Jan 20 2015 23:13:58) Copyright (c) 1997-2015 The PHP Group Zend Engine v3.0.0-dev, Copyright (c) 1998-2015 Zend Technologies</pre> <p>Vergleichen werde ich mit der aktuell unter Ubuntu 14.04 LTS verfügbaren Version PHP 5.5.9:</p> <pre class="brush: bash; title: ; notranslate" title="">$ php -v PHP 5.5.9-1ubuntu4.5 (cli) (built: Oct 29 2014 11:59:10) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies with Zend OPcache v7.0.3, Copyright (c) 1999-2014, by Zend Technologies</pre> <p>Da die eine Version selbst kompiliert ist und die andere von Ubuntu stammt sind sie in diesem Fall nicht ideal für einen Vergleich nutzbar, aber auf ein paar Bytes oder Prozente soll es mir nicht ankommen.</p> <p>PHP 7 hat in diesem Fall keinen OPcache aktiviert, aber den benötige ich für meine Tests auf der Kommandozeile (CLI) nicht. Möchte man PHP via Webserver (PHP-FPM usw.) nutzen sollte man darauf achten den OPcache per php.ini zu aktivieren, um vergleichbare Ergebnisse zu bekommen.</p> <p>Folgendes kleines Testscript werde ich mit beiden Versionen laufen lassen:</p> <pre class="brush: php; title: ; notranslate" title="">&lt;?php $a = array(); for ($i=1; $i&lt;2000000; $i++) { $a&#x5B;] = rand(100000000, 999999999); } echo &quot;not real: &quot;.(memory_get_peak_usage(false)/1024/1024).&quot; MiB\n&quot;; echo &quot;real: &quot;.(memory_get_peak_usage(true)/1024/1024).&quot; MiB\n&quot;;</pre> <p>Und hier sind die jeweiligen Ergebnisse:</p> <pre class="brush: bash; title: ; notranslate" title="">$ time php arraytest.php not real: 275.61262512207 MiB real: 276 MiB real    0m1.119s user    0m0.763s sys     0m0.190s</pre> <pre class="brush: bash; title: ; notranslate" title="">$ $ time sapi/cli/php arraytest.php not real: 96.334381103516 MiB real: 98 MiB real    0m0.414s user    0m0.290s sys     0m0.068s</pre> <p>Ui ui ui! Mit PHP 7 reduziert sich der Arbeitsspeicherverbrauch bei diesem Testarray (2.000.000 Zahlen als Values) um satte 65%!</p> <p>Weniger Arbeitsspeicherverbrauch heißt nicht nur dass &#8222;mehr PHP&#8220; auf einem Server laufen kann, weniger Arbeitsspeicher heißt auch dass weniger Daten im Arbeitsspeicher abgelegt werden müssen, und weniger daraus gelesen werden muss, es impliziert also automatisch auch einen Performance-Boost. Wie man an den Laufzeiten erkennen kann ist PHP 7 auch ungefähr 3 Mal so schnell!</p> <p>In richtigen Applikationen wie WordPress oder Typo3 usw. ist der Unterschied nicht ganz so groß, da spricht man <a href="http://zsuraski.blogspot.de/2014/07/benchmarking-phpng.html" target="_blank">von ungefähr 50% bis 110% mehr Laufzeit-Performance</a>. Denn bei größeren Applikationen wird auch viel Zeit beim Warten auf die Datenbank verbraucht, und Warten ist genauso langsam in PHP 5.5 wie in PHP 7 😉</p> <p>All diese Verbesserungen sind darauf zurückzuführen <a href="http://nikic.github.io/2011/12/12/How-big-are-PHP-arrays-really-Hint-BIG.html" target="_blank">wie PHP intern Variablen und Arrays organisiert</a>, den sogenannten ZVALs und Hashtables. Die detaillierten Informationen über die <a href="http://nikic.github.io/2014/12/22/PHPs-new-hashtable-implementation.html" target="_blank">Änderungen an der Hashtable-Implementation von PHP 7</a> sollte man sich mal zu Gemüte führen.</p> <p><strong>Edit:</strong> Auf Wunsch habe ich auch noch PHP 5.6 getestet, hier die Ergebnisse:</p> <pre class="brush: plain; title: ; notranslate" title="">wget http://de2.php.net/get/php-5.6.5.tar.gz/from/this/mirror mv mirror php-5.6.5.tar.gz tar -xzvf php-5.6.5.tar.gz cd php-5.6.5/ ./configure --prefix=/usr/local/php-5.6.5 --with-zlib --with-config-file-path=/usr/local/php-5.6.5/etc --enable-mbstring --with-mysql --with-mysqli --with-pdo-mysql --enable-zip --with-imap --with-kerberos --with-imap-ssl --with-openssl --with-jpeg-dir --with-gd --with-gettext --with-freetype-dir --enable-ftp --with-pspell --with-curl make</pre> <pre class="brush: plain; title: ; notranslate" title="">$ sapi/cli/php -v PHP 5.6.5 (cli) (built: Jan 23 2015 00:46:40) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies</pre> <pre class="brush: plain; title: ; notranslate" title="">$ time sapi/cli/php -d memory_limit=512M arraytest.php not real: 275.61260223389 MiB real: 276 MiB real    0m1.023s user    0m0.663s sys     0m0.170s</pre> <p>PHP 5.6 ist also leicht schneller als PHP 5.5, aber zu PHP 7 ist es immer noch ein richtig großer Unterschied.</p> https://phpgangsta.de/aktueller-stand-von-php-7-deutlich-geringerer-arbeitsspeicherverbrauch/feed 15 Den aktuellen Stand von PHP 7 (pre-alpha) selbst kompilieren und testen https://phpgangsta.de/den-aktuellen-stand-von-php-7-pre-alpha-selbst-kompilieren-und-testen https://phpgangsta.de/den-aktuellen-stand-von-php-7-pre-alpha-selbst-kompilieren-und-testen#comments Wed, 21 Jan 2015 11:54:59 +0000 http://www.phpgangsta.de/?p=6598 <p>PHP 7 wird kommen, <a href="https://wiki.php.net/rfc/php7timeline" target="_blank">nach aktuellem Plan wird es Mitte Oktober 2015 soweit sein</a>. Ich persönlich bin da noch etwas skeptisch ob das zeitlich klappen kann, aber ich hoffe dass es noch 2015 sein wird.</p> <p>PHP 7 wird sehr große interne Änderungen an der Zend Engine mit sich bringen, <a href="https://wiki.php.net/phpng#performance_evaluation" target="_blank">die Performance wird</a> <a href="http://phpmagazin.de/news/phpng-versus-hhvm-175333" target="_blank">ungefähr verdoppelt</a> und dann auf dem Niveau von HHVM sein. Aber auch der Arbeitsspeicherbedarf wird radikal reduziert. Genau um letzteres zu prüfen habe ich den aktuellen PHP 7-Stand selbst kompiliert, und möchte hier zeigen dass es sehr einfach geht und ihr das auch machen solltet!</p> <p>Wir werden PHP 7 aka phpng direkt aus dem GIT-Repository holen und kompilieren, folgende Schritte sind dazu nötig:</p> <pre class="brush: bash; title: ; notranslate" title="">cd /tmp/ git clone https://github.com/php/php-src.git cd php-src ./buildconf ./configure --prefix=/usr/local/phpng --with-zlib --with-config-file-path=/usr/local/phpng/etc --enable-mbstring --with-mysql --with-mysqli --with-pdo-mysql --enable-zip --with-imap --with-kerberos --with-imap-ssl --with-openssl --with-jpeg-dir --with-gd --with-gettext --with-freetype-dir --enable-ftp --with-pspell --with-curl make make test</pre> <p>Falls es Fehler beim configure bzgl. re2c oder bison gibt, unter Ubuntu installiert man diese folgendermaßen:</p> <pre class="brush: bash; title: ; notranslate" title="">sudo apt-get install bison sudo apt-get install re2c</pre> <p>Falls pspell nicht gefunden werden kann:</p> <pre class="brush: plain; title: ; notranslate" title="">configure: error: Cannot find pspell</pre> <pre class="brush: bash; title: ; notranslate" title="">sudo apt-get install libpspell-dev</pre> <p>Nach dem &#8222;make test&#8220; ist PHP 7 auf Kommandozeilenebene nutzbar:</p> <pre class="brush: bash; title: ; notranslate" title="">$ sapi/cli/php -v PHP 7.0.0-dev (cli) (built: Jan 20 2015 23:13:58) Copyright (c) 1997-2015 The PHP Group Zend Engine v3.0.0-dev, Copyright (c) 1998-2015 Zend Technologies</pre> <p>Wer PHP danach richtig installieren möchte macht noch ein &#8222;sudo make install&#8220;, dann wird PHP im oben definierten Prefix-Verzeichnis installiert.</p> <p>Ich bin mir sehr sicher dass ich Mitte des Jahres, wenn es die ersten Alpha- und Beta-Versionen gibt, ausgiebig Applikationen testen werde, damit möglichst wenige Bugs in PHP 7 drin sind, und es hoffentlich bereits Ende 2015 auf Produktionsmaschinen einsetzbar sein wird. Ich sage schonmal voraus dass ich dann breit grinsend vor den Maschinen hocken werde und die neuen schnellen Webseiten und Scripte bewundern werde 😉</p> <p>Im nächsten Blogartikel geht es um meinen <a href="https://www.phpgangsta.de/aktueller-stand-von-php-7-deutlich-geringerer-arbeitsspeicherverbrauch">kleinen Vergleich des Memory-Verbrauchs</a>.</p> <p>PHP 7 wird kommen, <a href="https://wiki.php.net/rfc/php7timeline" target="_blank">nach aktuellem Plan wird es Mitte Oktober 2015 soweit sein</a>. Ich persönlich bin da noch etwas skeptisch ob das zeitlich klappen kann, aber ich hoffe dass es noch 2015 sein wird.</p> <p>PHP 7 wird sehr große interne Änderungen an der Zend Engine mit sich bringen, <a href="https://wiki.php.net/phpng#performance_evaluation" target="_blank">die Performance wird</a> <a href="http://phpmagazin.de/news/phpng-versus-hhvm-175333" target="_blank">ungefähr verdoppelt</a> und dann auf dem Niveau von HHVM sein. Aber auch der Arbeitsspeicherbedarf wird radikal reduziert. Genau um letzteres zu prüfen habe ich den aktuellen PHP 7-Stand selbst kompiliert, und möchte hier zeigen dass es sehr einfach geht und ihr das auch machen solltet!</p> <p>Wir werden PHP 7 aka phpng direkt aus dem GIT-Repository holen und kompilieren, folgende Schritte sind dazu nötig:</p> <pre class="brush: bash; title: ; notranslate" title="">cd /tmp/ git clone https://github.com/php/php-src.git cd php-src ./buildconf ./configure --prefix=/usr/local/phpng --with-zlib --with-config-file-path=/usr/local/phpng/etc --enable-mbstring --with-mysql --with-mysqli --with-pdo-mysql --enable-zip --with-imap --with-kerberos --with-imap-ssl --with-openssl --with-jpeg-dir --with-gd --with-gettext --with-freetype-dir --enable-ftp --with-pspell --with-curl make make test</pre> <p>Falls es Fehler beim configure bzgl. re2c oder bison gibt, unter Ubuntu installiert man diese folgendermaßen:</p> <pre class="brush: bash; title: ; notranslate" title="">sudo apt-get install bison sudo apt-get install re2c</pre> <p>Falls pspell nicht gefunden werden kann:</p> <pre class="brush: plain; title: ; notranslate" title="">configure: error: Cannot find pspell</pre> <pre class="brush: bash; title: ; notranslate" title="">sudo apt-get install libpspell-dev</pre> <p>Nach dem &#8222;make test&#8220; ist PHP 7 auf Kommandozeilenebene nutzbar:</p> <pre class="brush: bash; title: ; notranslate" title="">$ sapi/cli/php -v PHP 7.0.0-dev (cli) (built: Jan 20 2015 23:13:58) Copyright (c) 1997-2015 The PHP Group Zend Engine v3.0.0-dev, Copyright (c) 1998-2015 Zend Technologies</pre> <p>Wer PHP danach richtig installieren möchte macht noch ein &#8222;sudo make install&#8220;, dann wird PHP im oben definierten Prefix-Verzeichnis installiert.</p> <p>Ich bin mir sehr sicher dass ich Mitte des Jahres, wenn es die ersten Alpha- und Beta-Versionen gibt, ausgiebig Applikationen testen werde, damit möglichst wenige Bugs in PHP 7 drin sind, und es hoffentlich bereits Ende 2015 auf Produktionsmaschinen einsetzbar sein wird. Ich sage schonmal voraus dass ich dann breit grinsend vor den Maschinen hocken werde und die neuen schnellen Webseiten und Scripte bewundern werde 😉</p> <p>Im nächsten Blogartikel geht es um meinen <a href="https://www.phpgangsta.de/aktueller-stand-von-php-7-deutlich-geringerer-arbeitsspeicherverbrauch">kleinen Vergleich des Memory-Verbrauchs</a>.</p> https://phpgangsta.de/den-aktuellen-stand-von-php-7-pre-alpha-selbst-kompilieren-und-testen/feed 1 SSLv3: Uralt, bröckelig, abschalten! https://phpgangsta.de/sslv3-uralt-broeckelig-abschalten https://phpgangsta.de/sslv3-uralt-broeckelig-abschalten#comments Tue, 14 Oct 2014 22:18:42 +0000 http://www.phpgangsta.de/?p=6583 <p><strong>[EDIT] Tja, da schreibt man gerade drüber und ein paar Minuten später wird die Lücke veröffentlicht: <a href="https://www.openssl.org/~bodo/ssl-poodle.pdf" target="_blank">Poodle</a> . Details im <a href="http://googleonlinesecurity.blogspot.co.uk/2014/10/this-poodle-bites-exploiting-ssl-30.html" target="_blank">Google Blog</a>. Das Problem liegt im SSLv3 Protokoll selbst, es wird keine Patches geben, es muss ausgeschaltet werden. Eigentlich wäre nur uralt-Software wie der IE6 unter WindowsXP betroffen, aber durch Downgrade-Attacken die bei TLS möglich sind, sind alle betroffen und können auf das schwache SSLv3 downgegraded werden wenn es denn auf Server+Client unterstützt wird. Also abschalten!<br /> </strong></p> <p>Seit 2 Tagen gibt es Gerüchte über eine kritische Lücke in SSLv3. Aktuell (Mitternacht) ist noch nichts publik geworden außer ein eventuell interessanter Patch von Microsoft, und eine Falschmeldung eines OpenBSD-Patches, der in Wirklichkeit schon einige Monate alt ist.</p> <p>Sicher ist dass SSLv3 18 Jahr alt ist, und vor 15 Jahren durch TLSv1.0 abgelöst wurde. Bei mail.de haben wir SSLv3 bereits vor einigen Monaten deaktiviert auf den Webseiten da kaum ein Client dieses alte Protokoll benutzte außer der IE6 auf WindowsXP Systemen. Da wir den IE6 eh schon lange nicht mehr unterstützen war es sehr einfach, SSLv3 abzuschalten.</p> <p>Für die anderen Protokolle wie IMAP, POP3 und SMTP haben wir SSLv3 allerdings noch aktiviert gelassen da es noch diverse E-Mail-Clients gibt die TLS &gt;1.0 noch nicht beherrschen. Auch einige ältere Smartphones beherrschen noch kein TLS1.0 oder neuer, sodass es Sinn machte es noch aktiviert zu lassen, denn es gab auch (noch) keine bekannten Angriffsvektoren.</p> <p><span id="more-6583"></span>Da nun aber die Gerüchteküche kocht und es dort wirklich etwas zu geben scheint, haben wir es kurzerhand nun deaktiviert, um der Veröffentlichung zuvorzukommen. Da es pro Tag nur knapp 20 Verbindungen gab die noch SSLv3 genutzt haben sind so wenige Kunden betroffen dass wir es verantworten können.</p> <p>Auch ihr solltet darüber nachdenken SSLv3 abzuschalten, allem voraus in euren Webservern.</p> <h3>SSLv3 in nginx deaktivieren</h3> <p>Ich empfehle für nginx aktuell die folgenden SSL-Einstellungen:</p> <pre class="brush: plain; title: ; notranslate" title="">ssl_protocols             TLSv1.1 TLSv1.2 TLSv1; ssl_ciphers               ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:RSA+3DES:!ADH:!AECDH:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache         shared:SSL:10m; ssl_session_timeout       10m;</pre> <h3>SSLv3 im Apache deaktivieren</h3> <p>Für den Apache müsste es folgende Einstellung sein wenn ich das richtig sehe. Habe leider keinen Apache mit SSL parat zum testen:</p> <pre class="brush: plain; title: ; notranslate" title=""># apache bis 2.2.22 SSLProtocol all -SSLv2 -SSLv3 # apache ab 2.2.23 SSLProtocol TLSv1 TLSv1.1 TLSv1.2 </pre> <h3>SSLv3 in Dovecot deaktivieren</h3> <p>Seit Version 2.1 lässt sich SSLv3 so deaktivieren:</p> <pre class="brush: plain; title: ; notranslate" title="">ssl_protocols = !SSLv2 !SSLv3</pre> <p>Ältere Versionen muss man manuell patchen, aber hoffentlich verwendet keiner von euch mehr so alte Versionen.</p> <h3>SSLv3 in Postfix deaktivieren</h3> <pre class="brush: plain; title: ; notranslate" title="">smtpd_tls_protocols = !SSLv2, !SSLv3  smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3 smtp_tls_protocols = !SSLv2, !SSLv3</pre> <h3>SSLv3 in HAProxy deaktivieren:</h3> <pre class="brush: plain; title: ; notranslate" title="">bind :443 ssl crt &lt;crt&gt; ciphers &lt;ciphers&gt; no-sslv3</pre> <h3>SSLv3 in Firefox deaktivieren:</h3> <p>Einfach in der Adressleiste about:config eintippen, dann nach &#8222;tls&#8220; suchen und die Option security.tls.version.min auf 1 stellen.</p> <h3>SSLv3 in Chrome deaktivieren:</h3> <p>In Chrome ist es ein bisschen aufwändiger, da man den Browser mit der Kommandozeilen-Option &#8211;ssl-version-min=tls1 starten muss. Am einfachsten legt man sich einen entsprechenden Shortcut an.</p> <h3>SSLv3 im Internet Explorer deaktivieren:</h3> <p>Im Internet Explorer kann man in den Internetoptionen unter Erweitert SSL 3.0 verwenden abwählen – und bei der Gelegenheit auch gleich TLS 1.1 und 1.2 aktivieren.</p> <h3>Wie teste ich ob SSLv3 unterstützt wird?</h3> <p>Webseiten kann man am einfachsten mit dem Qualys SSL-Tester online prüfen:</p> <p><a href="https://www.ssllabs.com/ssltest/index.html" target="_blank">https://www.ssllabs.com/ssltest/index.html</a></p> <p>So prüft man ob seine Dienste noch SSLv3 unterstützen:</p> <pre class="brush: plain; title: ; notranslate" title="">openssl s_client -crlf -ssl3 -connect imap.mail.de:993 openssl s_client -starttls smtp -crlf -ssl3 -connect mx01.mail.de:25 openssl s_client -starttls smtp -crlf -ssl3 -connect smtp.mail.de:587 openssl s_client -ssl3 -connect mail.de:443</pre> <p>Natürlich muss dort der passende Hostname des zu testenden Servers eingegeben werden.</p> <p>Wenn SSLv3 nicht unterstützt wird, dann wird die folgende Fehlermeldung angezeigt und die Verbindung kommt nicht zustande:</p> <pre class="brush: plain; title: ; notranslate" title="">New, (NONE), Cipher is (NONE) Secure Renegotiation IS NOT supported</pre> <p>Kommt eine Verbindung zustande sieht man folgende Informationen:</p> <pre class="brush: plain; title: ; notranslate" title="">New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE SSL-Session: Protocol: SSLv3</pre> <p><strong>[EDIT] Tja, da schreibt man gerade drüber und ein paar Minuten später wird die Lücke veröffentlicht: <a href="https://www.openssl.org/~bodo/ssl-poodle.pdf" target="_blank">Poodle</a> . Details im <a href="http://googleonlinesecurity.blogspot.co.uk/2014/10/this-poodle-bites-exploiting-ssl-30.html" target="_blank">Google Blog</a>. Das Problem liegt im SSLv3 Protokoll selbst, es wird keine Patches geben, es muss ausgeschaltet werden. Eigentlich wäre nur uralt-Software wie der IE6 unter WindowsXP betroffen, aber durch Downgrade-Attacken die bei TLS möglich sind, sind alle betroffen und können auf das schwache SSLv3 downgegraded werden wenn es denn auf Server+Client unterstützt wird. Also abschalten!<br /> </strong></p> <p>Seit 2 Tagen gibt es Gerüchte über eine kritische Lücke in SSLv3. Aktuell (Mitternacht) ist noch nichts publik geworden außer ein eventuell interessanter Patch von Microsoft, und eine Falschmeldung eines OpenBSD-Patches, der in Wirklichkeit schon einige Monate alt ist.</p> <p>Sicher ist dass SSLv3 18 Jahr alt ist, und vor 15 Jahren durch TLSv1.0 abgelöst wurde. Bei mail.de haben wir SSLv3 bereits vor einigen Monaten deaktiviert auf den Webseiten da kaum ein Client dieses alte Protokoll benutzte außer der IE6 auf WindowsXP Systemen. Da wir den IE6 eh schon lange nicht mehr unterstützen war es sehr einfach, SSLv3 abzuschalten.</p> <p>Für die anderen Protokolle wie IMAP, POP3 und SMTP haben wir SSLv3 allerdings noch aktiviert gelassen da es noch diverse E-Mail-Clients gibt die TLS &gt;1.0 noch nicht beherrschen. Auch einige ältere Smartphones beherrschen noch kein TLS1.0 oder neuer, sodass es Sinn machte es noch aktiviert zu lassen, denn es gab auch (noch) keine bekannten Angriffsvektoren.</p> <p><span id="more-6583"></span>Da nun aber die Gerüchteküche kocht und es dort wirklich etwas zu geben scheint, haben wir es kurzerhand nun deaktiviert, um der Veröffentlichung zuvorzukommen. Da es pro Tag nur knapp 20 Verbindungen gab die noch SSLv3 genutzt haben sind so wenige Kunden betroffen dass wir es verantworten können.</p> <p>Auch ihr solltet darüber nachdenken SSLv3 abzuschalten, allem voraus in euren Webservern.</p> <h3>SSLv3 in nginx deaktivieren</h3> <p>Ich empfehle für nginx aktuell die folgenden SSL-Einstellungen:</p> <pre class="brush: plain; title: ; notranslate" title="">ssl_protocols             TLSv1.1 TLSv1.2 TLSv1; ssl_ciphers               ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:RSA+3DES:!ADH:!AECDH:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache         shared:SSL:10m; ssl_session_timeout       10m;</pre> <h3>SSLv3 im Apache deaktivieren</h3> <p>Für den Apache müsste es folgende Einstellung sein wenn ich das richtig sehe. Habe leider keinen Apache mit SSL parat zum testen:</p> <pre class="brush: plain; title: ; notranslate" title=""># apache bis 2.2.22 SSLProtocol all -SSLv2 -SSLv3 # apache ab 2.2.23 SSLProtocol TLSv1 TLSv1.1 TLSv1.2 </pre> <h3>SSLv3 in Dovecot deaktivieren</h3> <p>Seit Version 2.1 lässt sich SSLv3 so deaktivieren:</p> <pre class="brush: plain; title: ; notranslate" title="">ssl_protocols = !SSLv2 !SSLv3</pre> <p>Ältere Versionen muss man manuell patchen, aber hoffentlich verwendet keiner von euch mehr so alte Versionen.</p> <h3>SSLv3 in Postfix deaktivieren</h3> <pre class="brush: plain; title: ; notranslate" title="">smtpd_tls_protocols = !SSLv2, !SSLv3  smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3 smtp_tls_protocols = !SSLv2, !SSLv3</pre> <h3>SSLv3 in HAProxy deaktivieren:</h3> <pre class="brush: plain; title: ; notranslate" title="">bind :443 ssl crt &lt;crt&gt; ciphers &lt;ciphers&gt; no-sslv3</pre> <h3>SSLv3 in Firefox deaktivieren:</h3> <p>Einfach in der Adressleiste about:config eintippen, dann nach &#8222;tls&#8220; suchen und die Option security.tls.version.min auf 1 stellen.</p> <h3>SSLv3 in Chrome deaktivieren:</h3> <p>In Chrome ist es ein bisschen aufwändiger, da man den Browser mit der Kommandozeilen-Option &#8211;ssl-version-min=tls1 starten muss. Am einfachsten legt man sich einen entsprechenden Shortcut an.</p> <h3>SSLv3 im Internet Explorer deaktivieren:</h3> <p>Im Internet Explorer kann man in den Internetoptionen unter Erweitert SSL 3.0 verwenden abwählen – und bei der Gelegenheit auch gleich TLS 1.1 und 1.2 aktivieren.</p> <h3>Wie teste ich ob SSLv3 unterstützt wird?</h3> <p>Webseiten kann man am einfachsten mit dem Qualys SSL-Tester online prüfen:</p> <p><a href="https://www.ssllabs.com/ssltest/index.html" target="_blank">https://www.ssllabs.com/ssltest/index.html</a></p> <p>So prüft man ob seine Dienste noch SSLv3 unterstützen:</p> <pre class="brush: plain; title: ; notranslate" title="">openssl s_client -crlf -ssl3 -connect imap.mail.de:993 openssl s_client -starttls smtp -crlf -ssl3 -connect mx01.mail.de:25 openssl s_client -starttls smtp -crlf -ssl3 -connect smtp.mail.de:587 openssl s_client -ssl3 -connect mail.de:443</pre> <p>Natürlich muss dort der passende Hostname des zu testenden Servers eingegeben werden.</p> <p>Wenn SSLv3 nicht unterstützt wird, dann wird die folgende Fehlermeldung angezeigt und die Verbindung kommt nicht zustande:</p> <pre class="brush: plain; title: ; notranslate" title="">New, (NONE), Cipher is (NONE) Secure Renegotiation IS NOT supported</pre> <p>Kommt eine Verbindung zustande sieht man folgende Informationen:</p> <pre class="brush: plain; title: ; notranslate" title="">New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE SSL-Session: Protocol: SSLv3</pre> https://phpgangsta.de/sslv3-uralt-broeckelig-abschalten/feed 6