www.phparch.com September 2018 Volume 17 - Issue 9

MagniPHPicent 7.3

PHP 7.3 is On Track! Upgrading Old Legacy Apps to PHP 7 and Beyond Using the Symfony Workflow Component as a State Machine for Ecommerce

ALSO INSIDE

The Dev Lead Trenches: Security Corner: The Workshop: How Long Will Thinking Like Describe Your Tests It Take? an Attacker with Kahlan Community Corner: Education Station: finally{}: Finding the Perfect Producer-Consumer The Seven Deadly Sins Development Job Programming of Programming: Pride Start building with a focused, faster cloud. Fully supported by Thermo Physicists there to help solve any of your problems..

Focused Faster Care

Elastic energy at your Deploy in Thermo.io Physicists fingertips. Launch. seconds on our are here to help Rebuild. Clone. Swap. high-availability, you out without Grow. Instantly. SSD-driven platform. confiscating root.

DISCOUNT: Get your $150 credit today using code PHPDEVELOPER

WEB: EMAIL: PHONE: Thermo.io [email protected] 833-3-THERMO Early Bird Sale until 9/15!

2018

The 4th annual PHP conference for Washington ..

November 14–15, 2018 Washington, D.C.

world.phparch.com

Only $475 Full price: $795 SEPTEMBER 2018 Volume 17 - Issue 9

Features Columns

2 MagniPHPicent 7.3 3 PHP 7.3 is On Track! Oscar Merida 31 The Dev Lead Trenches: Damien Seguy How Long Will It Take? Chris Tankersley 10 Upgrading Old Legacy Apps 34 Security Corner: Professional Paranoia: Thinking to PHP 7 and Beyond Like an Attacker Eric Mann

Sammy Kaye Powers 37 The Workshop: Describe Your Tests with Kahlan 24 Using the Symfony Workflow Joe Ferguson 41 Community Corner: Component as a State Finding the Perfect Development Job Machine for Ecommerce James Titcumb 43 Education Station: Michelle Sanver Producer-Consumer Programming Edward Barnard

51 August Happenings

52 finally{}: The Seven Deadly Sins of Programming: Pride Eli White

Editor-in-Chief: Subscriptions Contact Information: Oscar Merida General mailbox: [email protected] Editorial: Editor: Kara Ferguson Print, digital, and corporate [email protected] subscriptions are available. Visit Print ISSN 1709-7169 https://www.phparch.com/magazine to Digital ISSN 2375-3544 Managing Partners subscribe or email [email protected] for Copyright © 2018—musketeers.me, LLC more information. All Rights Reserved Oscar Merida, SandySample Smith Although all possible care has been placed in assuring the Advertising accuracy of the contents of this magazine, including all architect associated source code, listings and figures, the publisher [ ] is published twelve times a To learn about advertising and receive year by: musketeers.me, LLC assumes no responsibilities with regards of use of the the full prospectus, contact us at information contained herein or in all associated material. 201 Adams Avenue [email protected] today! Alexandria, VA 22301, USA php[architect], php[a], the php[architect] logo, musketeers. me, LLC and the musketeers.me, LLC logo are trademarks of musketeers.me, LLC. PHP 7.3 is OnFEATURE Track!

PHP 7.3 is On Track! Damien Seguy PHP 7.3 successfully passed the “feature freeze” deadline. On Aug. 1st, 2018 all features for PHP 7.3 were identified. This triggered the first PHP 7.3 beta, on the following day, and, from there, we’ll reach RC in September. It is time to review what this new PHP version has available for us, help test PHP 7.3, and get ready.

Improved Garbage Collector Relaxed Heredoc/Nowdoc One of the main improvement in the PHP 7.3 engine is the Heredoc and nowdoc are a string definition syntax that is garbage collector, also called GC. adapted to large pieces of text. Here is a heredoc: The Garbage Collector is an internal tool that frees memory. $x = <<

• How to optimize the PHP garbage collector usage to 1.

www.phparch.com \ September 2018 \ 3 PHP 7.3 is On Track!

In PHP 7.3, two constraints are is the secure argument, and should feature was rarely used, yet, for those relaxed: first, the ending delimiter may always be used), will create a one-line who do, the impact shall be significant. be freely followed by other operators. diff. More on this: Deprecate and Remove So, it is now possible to use heredoc in Case-Insensitive Constants6. a function call. > 1, PCRE 2.0 $variable = 'THINGS'; instead of a two-line diff: print strtolower(<< "example.com", pendent library, called PCRE7. PHP has > 1 ENGLISH); been using the PCRE library for ages. It has made its way to the core of PHP, Secondly, the ending delimiter may Note that function definitions don’t and can’t be disabled anymore. Yet, PHP be moved to the left. There is no need get that syntax. still uses the version 1.0 of the PCRE for it to be the first on its line. Better, More on this: Allow a trailing comma library. It has been abandoned, and a the indentation of that ending delimit- in function calls5 new version, PCRE2, was released in er is the indentation for the text in the 2015. This new version is actively devel- Heredoc syntax. Look at that: Deprecated Case-insensitive oped. function foo() { Constants The change from PCRE 1 to 2 means return <<

4 \ September 2018 \ www.phparch.com PHP 7.3 is On Track!

preg_match, and begging it to raise an error, which we can try { suppress with an @. $read = json_decode( $data, false, 512, JSON_THROW_ON_ERROR // since we hunt for regex error, let's not log them ); if (false === @preg_match($regex, null)) { } catch (JsonException $e) { print "$regex is an invalid regex in pcre\n. Error : " echo "the incoming data are not valid json code\n"; . error_get_last() . PHP_EOL; } } The default behavior is to keep the old behavior, for back- More on this: PCRE2 migration10 ward compatibility. It is recommended to make a call to json_last_error() after calls tojson_encode() and json_ SQLite 3.24 decode(). 14 SQLite is another independent library embedded in PHP. It More on this: JSON_THROW_ON_ERROR . 11 now supports version 3.24 , which was released in June 2018. array_first_key(), array_last_key() This new version adds support forUPSERT . UPSERT is inspired by the same command in PostgreSQL. An UPSERT is an ordi- Finding the first key of an array required some workaround nary INSERT statement that is followed by the special ON in PHP 7.2 and older. While it is easy to know what the first CONFLICT clause: if the row being inserted is not available element of an auto-generated list is, (hint: it is 0) it requires in the table, it is inserted. If it is already there, the insert is some work to find the first key of an array. turned into an UPDATE command. Various workarounds are shown in Listing 3. This is close to theREPLACE command, which is already Starting in PHP 7.3, it is possible to use array_first_key() available in SQLite. The main difference is the UPDATE to reach that value, without resetting the internal pointer, nor doesn’t have to change every column and may decide to starting a loop on the array. preserve some of them. The same applies toarray_last_key() , which targets the last Here is an example, taken from the UPSERT12 documentation: element of an array. Solutions to that thorny problem were even more creative than the previous (Listing 4). CREATE TABLE vocabulary( word TEXT PRIMARY KEY, count INT DEFAULT 1 ); Listing 3 INSERT INTO vocabulary(word) VALUES('jovial') ON CONFLICT(word) DO UPDATE SET count=count+1; 1. $array = ['a' = > 1, 'b' => 2, 'c' => 3]; 2. A word is inserted in the vocabulary table, and the column 3. // solution 1 : 4. reset($array); count keeps track of the number of its insertions. 5. $key = key($array); More on this: version 3.2413. 6. 7. // solution 2 : Json_encode May Throw Exceptions 8. $key = array_keys($array)[0]; 9. PHP has two functions for dealing with JSON: json_ 10. // solution 3 : decode() and json_encode(). Unfortunately, they both return 11. foreach($array as $key => $value) { null when an error happens while processing the data. Yet, 12. break 1; null is a possible valid result when decoding a JSON. For 13. } example, the string "null" will be decoded into null (the constant). When decoding null is part of the business logic, there Listing 4 is no other way than checking json_last_error() for errors 1. $array = ['a' = > 1, 'b' => 2, 'c' => 3]; before continuing. 2. PHP 7.3 introduces a new option for the two functions: 3. // solution 1 : JSON_THROW_ON_ERROR. This makes json_* throw an exception 4. reset($array); when an error happens, and it may be cleanly caught with a 5. end($array); try/catch clause. 6. $key = key($array); 7. 8. // solution 2 : 10 PCRE2 migration: https://wiki.php.net/rfc/pcre2-migration 9. $key = array_keys($array)[count($array) - 1]; 10. 11 version 3.24:Sample https://www.sqlite.org/releaselog/3_24_0.html 11. // solution 3 : 12 UPSERT: https://www.sqlite.org/lang_UPSERT.html 12. foreach ($array as $key => $value) { 13 version 3.24: https://www.sqlite.org/releaselog/3_24_0.html 13. // Actually found in code... 14 JSON_THROW_ON_ERROR: 14. } https://wiki.php.net/rfc/json_throw_on_error

www.phparch.com \ September 2018 \ 5 PHP 7.3 is On Track!

array_value_first() and array_value_last() were also part net_get_interfaces() of the RFC, but once the first and final key is found, its value net_get_interfaces() is a new function which lists all is one dereferencing away. network interfaces. Until now, it was necessary to rely on More on this: int the array_key_first, array_key_last, etc php_exec() 15 to poke the system, then parse its results. Now, RFC net_get_interfaces() provides the same information in an array, directly inside PHP. It has been ported to all available list() with References OS, including Windows. PHP has had the list() function, and its short syntax The result of a call to this function may look like Output 1. version []. Until PHP 7.3, it was not possible to assign refer- More on this: getting ip for eth018 ences with list(). This is now possible.

$array = [1, 2]; Removing image2wbmp() list($a, &$b) = $array; image2wbmp() was removed from the PHP API. It is used to produce WBMP pictures, and a twin function called imagewb- This is the same as: mp(). The latter is still available in PHP 7.3. $array = [1, 2]; This function was identified as a duplicate feature of $a = $array[0]; $b =& $array[1]; Output 1

// and also 1. Array

2. ( [$a, &$b] = $array; 3. [lo0] => Array 4. ( As usual, list() may be combined with foreach(). For 5. [unicast] => Array example, this will only set ‘c’ index to 7. 6. ( 7. [0] => Array $array = [['c' => 1, 2], ['c' => 3, 4], ['c' => 5, 6]]; 8. ( foreach ($array as list('c' => &$a, 1 => $b)) { $a = 7; 9. [flags] => 32841 } 10. [family] => 18 print_r($array); 11. ) 12. More on this: list Reference Assignment16 13. [1] => Array 14. ( 15. [flags] => 32841 is_countable() 16. [family] => 30 This new function aims at identifying easily data that may 17. [address] => ::1 passed to count(). Since count() yields a warning if fed with 18. [netmask] => ffff:ffff:ffff:ffff: wrong data: 19. ) 20. Parameter must be an array or an object 21. [2] => Array that implements Countable 22. ( 23. [flags] => 32841 is_countable() is here to provide protection. The function 24. [family] => 2 is syntactic sugar: it replaces the following logical construct: 25. [address] => 127.0.0.1 26. [netmask] => 255.0.0.0 if (is_array($foo) || $foo instanceof Countable) { 27. ) // $foo is countable 28. } 29. [3] => Array 30. ( More on this: is_countable17 31. [flags] => 32841 32. [family] => 30 33. [address] => fe80::1 34. [netmask] => ffff:ffff:ffff:ffff:: 35. ) 36. 15 array_key_first, array_key_last,Sample etc RFC: 37. ) https://wiki.php.net/rfc/array_key_first_last 38. 16 list Reference Assignment: See code archive for complete listing https://wiki.php.net/rfc/list_reference_assignment 17 is_countable: https://wiki.php.net/rfc/is-countable 18 getting ip for eth0: https://bugs.php.net/bug.php?id=17400

6 \ September 2018 \ www.phparch.com PHP 7.3 is On Track!

imagewbmp(), and removed. The later function is still available. microtime(true) is often used. microtime() returns the time of the day, with the microseconds. As soon as a difference assert() is Now a Reserved Function is made between two microtime() calls, a bug is waiting to assert19 is already a PHP function. It belongs to the global happen. namespace and checks if an assertion is true (obvious, isn’t microtime() is based on the internal system clock, and the it?). It is currently not possible to define an assert function assumption is the clock will only go on, at least until 2037. in the global namespace, since the native one is already there. Many events may impact the internal clock—daylight saving A problem arises when an assert function is created in a time changing (twice a year), leap seconds (27 times since namespace and is called as an unqualified name. Basically, 1970), and manual reconfiguration of the clock. just like assert( ). PHP 7.3 introduces hrtime(). It is a monotonic timer. It’s a When disabling the assertions with zend.assertions=0 timer, as it behaves like microtime() and provides an ultra-pre- or assert_options20, PHP prevents any call to assert. This cise representation of the time: either an array with seconds includes namespaced assert, as the fully qualified name and microseconds, or a large integer. assert is reduced to the bare minimum. is not a function print_r(hrtime(true)); anymore, but a language construct, so reserving it is probably print PHP_EOL; a good idea. print_r(hrtime()); More on this: Deprecations for PHP 7.321 This displays :

Continue for Loops, Break for Switch 828536158380710 One may have noticed PHP has two very similar keywords: Array continue and break. They both break a control flow structure, ( [0] => 828536 and they actually may be used interchangeably. They should [1] => 158403415 have distinct usage, as explained by Nikita Popov in the RFC ) related to this. You may consider hrtime() as a modern version of micro- while ($foo) { time(). Any time difference should be done withhrtime() , switch ($bar) { microtime() case "baz": while may be reserved for displaying the actu- continue; // In PHP: Behaves like "break;" al time. In fact, hrtime() starts counting at some uncertain // In C: Behaves like "continue 2;" point in the past. On the other hand, hrtime() is not affected } by any variation of the internal clock. } More on this: High resolution monotonic timer #297625 continue and break behave the same, while other languages, and Monotonic Clocks—the Right Way to Determine Elapsed 26 such as C, make a distinction between the two. For example, Time 22 23 Drupal or TCPDF emits notice at linting time. compact() Reports Undefined Variables So, when a continue may be mistaken for a break, PHP 7.3 now emits this error: "continue" targeting switch is equiv- compact() is a convenient function which converts a list of alent to "break." Did you mean to use "continue 2"?. variable names into an array.

More on this: Deprecate and remove continue targeting $foo = 'bar'; 24 switch $array = compact('foo', 'foz'); Monotonic Timer: hrtime() // ['foo' => 'bar']; We all have relied on date() and time() to tell us the date Until now, compact() would silently ignore undefined vari- and time of the present moment. When measuring elapsed ables. It was up to the developer to check if the array was fully time, that is, the amount of time between two moments, built, or send it to the next method without checking. Those days are gone. 19 assert: http://php.net/assert compact() is heavily used with templating engines. This new 20 assert_options: http://php.net/function.assert-options feature may raise a large number of notices. It is recommend- 21 Deprecations for PHP 7.3: ed to check the logs in production and adapt the code. At https://wiki.php.net/rfc/deprecations_php_7_3Sample 22 Drupal: https://phpa.me/drupal-86-break 25 High resolution monotonic timer #2976: 23 TCPDF: https://phpa.me/tcpdf-break https://github.com/php/php-src/pull/2976 24 Deprecate and remove continue targeting switch: 26 Monotonic Clocks—the Right Way to Determine Elapsed Time: https://phpa.me/php73-switch-depr https://phpa.me/softwariness-monotonic-clocks

www.phparch.com \ September 2018 \ 7 a php[architect] guide

Discover how to secure your applications against many of the vulnerabilities exploited by attackers.

Security is an ongoing process not something to add right before your app launches. In this book, you’ll learn how to write secure PHP applications from fi rst principles. Why wait until your site is attacked or your data is breached? Prevent your exposure by being aware of the ways a malicious user might hijack your web site or API. Security Principles for PHP Applications is a comprehensive guide. Th is book contains examples of vulnerable code side-by-side with solutions to harden it. Organized around the 2017 OWASP Top Ten list, topics cover include: • Injection Attacks • Authentication and Session Management • Sensitive Data Exposure • Access Control and Password Handling • PHP Security Settings • Cross-Site Scripting • Logging and Monitoring • API Protection • Cross-Site Request Forgery • ...and more. Written by PHP professional Eric Mann, this book builds on his Sampleexperience in building secure, web applications with PHP. Order Your Copy http://phpa.me/security-principles PHP 7.3 is On Track!

worse, you may revert to the old behav- totally automati- Figure 1 ior by using the @ operator. cally, the improved More on this: Make compact function Garbage Collec- reports undefined passed variables27 tor. All of them will make any fall- Migration to PHP 7.3 back to PHP 7.2 hard or impossi- With all those new features and ble, as those new incompatibilities, how do you prepare features won’t for the newest PHP version? compile with Figure 1 is a summary of the features, older versions. and their impact on your code. So, once you have There are three ways to get your code migrated to PHP ready: prepare your code, review situ- 7.3, think twice ations that may benefit from upgrades, before adopting or just wait for PHP 7.3. a new feature, checking that your code meets this new which may break your application’s version. There are several steps you can Getting Ready for PHP 7.3 backward compatibility. Getting ready means removing every take which will help you and the PHP incompatibility between the current Static Analysis for the Review community: code and the new version. For example, The final column indicates if stat- • download PHP 7.3 from GitHub29 you can prepare for PCRE2 by collect- ic analysis is able to review, report, or and build it ing all your regex and linting them with recommend a feature. Tools like Exakat • lint your code with php -l, just to PHP 7.3’s regex engine. That will tell are already working on PHP 7.3-dev check the syntax you if they are compatible or not. and review efficiently code for migra- • run a static analysis tool, such as On the other hand, there is not tion. It proofreads the code well beyond Exakat30, to review all issues much to prepare for SQLite 3.24, since what the lint is capable of, and can the main evolution is a new feature direct your attention to the most inter- • run your test suite (UPSERT). The “recommendations” esting parts of the code. Migrating to a • report bugs to PHP Bugs31 column indicates we can search now for new PHP version is a good moment to portions of code that will benefit from add them to your tool belt. the new version, such as is_countable(). You’ll have to wait after the new version While We’re Waiting for to actually start using them, or rely on December 29 GitHub: https://github.com/php/php-src/ a compatibility library that will emulate 30 Exakat: https://www.exakat.io those functions until then. Symfony PHP 7.3 is forecast for December provides a polyfill for PHP 7.328, which 13th. Until then, it is important to keep 31 PHP Bugs: https://bugs.php.net at the moment only has an is_countable implementation but may have more Damien Seguy is CTO at Exakat Ltd., a company special- to come now that the feature freeze is ized in PHP code quality solutions for the industry. He leads done. In any way, this will be a job for development of the exakat PHP static analysis engine that after the big migration. automatically audit code for version compatibility, security and auto-documentation. Since last millenium, Damien has Migrating Then Downgrading contributed to PHP, as documentation author, elephpant Finally, the table in Figure 1 also breeder, conference speaker on every continents. He also enjoys 狮子头 reports backward incompatibilities machine learning, gremlin, and camembert. @exakat introduced by the new features of PHP 7.3. After the code has been migrated, you’ll be able to adopt new features, Related Reading such as the trailing comma, or even, • finally{}: Innovation in PHP by Eli White. May 2018. https://phparch.com/magazine/2018-2/may/ 27 Make compactSample function reports undefined passed variables: • Community Corner: The Imminent Release of PHP 7.2 https://wiki.php.net/rfc/compact by James Titcumb. October 2017. 28 polyfill for PHP 7.3: https://phparch.com/magazine/2017-2/october/ https://phpa.me/symfony-php73-polyfill

www.phparch.com \ September 2018 \ 9