Useful PHP tools you might not know about yet

PHP short array syntax converter

Is your project still using array() all over the place instead of the new [] short array syntax? Then the php-short-array-syntax-converter command-line script might be for you. The project page makes it clear the script is pretty robust.

The script was successfully tested against code bases with more than 5.000 PHP files.

Here's an example from within a target directory.

$ find . -name "*.php" -exec php "/path/to/convert.php" -w "{}" \;
6 replacements.  
4 replacements.  
8 replacements.  
No replacements.  
90 replacements.  
166 replacements.  
(snipped)

There's also a script to revert changes, but you could also use Git for that. Here's an example if you want to really wipe everything in your repo (changes, new files...) since the last git pull. Beware, this is a destructive operation.

$ git clean -fdx && git reset --hard

versionscan

While still a work in progress, versionscan is a promising initiative to report back potential known CVE issues with your PHP version.

Here's an example when everything's fine.

$ versionscan scan
Executing against version: 7.0.11-1~dotdeb+8.1  
+--------+--------+------+---------+
| Status | CVE ID | Risk | Summary |
+--------+--------+------+---------+

Scan complete  
--------------------
Total checks: 423  
Failures: 0  

And when you're indeed checking against a PHP version known to have vulnerabilities, failures are showing up in red (not represented here, though).

$ versionscan scan --sort=risk --php-version=7.0
Executing against version: 7.0  
+--------+---------------+------+------------------------------------------------------------------------------------------------------+
| Status | CVE ID        | Risk | Summary                                                                                              |
+--------+---------------+------+------------------------------------------------------------------------------------------------------+
| FAIL   | CVE-2015-8617 | 10.0 | Format string vulnerability in the zend_throw_or_error function in Zend/zend_execute_API.c in PHP... |
| FAIL   | CVE-2016-1904 | 7.5  | Multiple integer overflows in ext/standard/exec.c in PHP 7.x before 7.0.2 allow remote attackers ... |
| FAIL   | CVE-2015-8616 | 7.5  | Use-after-free vulnerability in the Collator::sortWithSortKeys function in ext/intl/collator/coll... |
| FAIL   | CVE-2015-6527 | 7.5  | The php_str_replace_in_subject function in ext/standard/string.c in PHP 7.x before 7.0.0 allows r... |
| FAIL   | CVE-2016-1903 | 6.4  | The gdImageRotateInterpolated function in ext/gd/libgd/gd_interpolation.c in PHP before 5.5.31, 5... |
+--------+---------------+------+------------------------------------------------------------------------------------------------------+

Scan complete  
--------------------
Total checks: 423  
Failures: 5  

We've passed the --php-version flag, which can be handy if you want to report on CVEs for PHP versions that are not installed on your system. We've also used the --sort=risk flag to order CVEs by most to less critical.

versionscan only depends on the Symfony Console and can export to json, xml and html.

phploc

PHPLOC is one of my favs for auditing a codebase. It simply measures the size and analyzes the structure of a PHP project.

Example for a Drupal 8.3.x codebase:

$ phploc .
phploc 3.0.1 by Sebastian Bergmann.

Directories                                       2186  
Files                                             8903

Size  
  Lines of Code (LOC)                          1231394
  Comment Lines of Code (CLOC)                  415248 (33.72%)
  Non-Comment Lines of Code (NCLOC)             816146 (66.28%)
  Logical Lines of Code (LLOC)                  257504 (20.91%)
    Classes                                     224923 (87.35%)
      Average Class Length                          25
        Minimum Class Length                         0
        Maximum Class Length                       619
      Average Method Length                          5
        Minimum Method Length                        0
        Maximum Method Length                      211
    Functions                                     1785 (0.69%)
      Average Function Length                        1
    Not in classes or functions                  30796 (11.96%)

Cyclomatic Complexity  
  Average Complexity per LLOC                     0.19
  Average Complexity per Class                    6.48
    Minimum Class Complexity                      1.00
    Maximum Class Complexity                    358.00
  Average Complexity per Method                   2.24
    Minimum Method Complexity                     1.00
    Maximum Method Complexity                   155.00

Dependencies  
  Global Accesses                                  787
    Global Constants                               336 (42.69%)
    Global Variables                               294 (37.36%)
    Super-Global Variables                         157 (19.95%)
  Attribute Accesses                             71458
    Non-Static                                   70113 (98.12%)
    Static                                        1345 (1.88%)
  Method Calls                                  202002
    Non-Static                                  182743 (90.47%)
    Static                                       19259 (9.53%)

Structure  
  Namespaces                                      1944
  Interfaces                                       847
  Traits                                           130
  Classes                                         7955
    Abstract Classes                               446 (5.61%)
    Concrete Classes                              7509 (94.39%)
  Methods                                        42255
    Scope
      Non-Static Methods                         39434 (93.32%)
      Static Methods                              2821 (6.68%)
    Visibility
      Public Methods                             34176 (80.88%)
      Non-Public Methods                          8079 (19.12%)
  Functions                                       1611
    Named Functions                                671 (41.65%)
    Anonymous Functions                            940 (58.35%)
  Constants                                       1302
    Global Constants                                67 (5.15%)
    Class Constants                               1235 (94.85%)

While this massive output can be turning you off, think about how it can help when you want to, say, port a module/bundle to a new version. PHPLOC will quickly help you evaluate the estimated amount of work needed and even drill down to advanced software engineering data (number of classes, interfaces, --count-tests to count PHPUnit test case classes, etc.). Of course this is only really an estimation as plenty of other factors are to be taken into account (e.g. new APIs, core application code removed/added, etc.)

Here's an example where we're quickly auditing Drupal 7 modules - via the prism of non-comment lines of code- to understand the amount of potential work needed to port them to Drupal 8.

$ for i in pathauto metatag panels features; do printf "Size for $i:\t" ; phploc $i/* | grep "Non-Comment Lines of Code (NCLOC)" ; done
Size for pathauto:   Non-Comment Lines of Code (NCLOC)    3066 (70.91%)  
Size for metatag:    Non-Comment Lines of Code (NCLOC)    8603 (77.47%)  
Size for panels:     Non-Comment Lines of Code (NCLOC)    5567 (73.80%)  
Size for features:   Non-Comment Lines of Code (NCLOC)    6079 (80.46%)  

Box

You've probably seen a good fraction of popular PHP applications are now distributed via PHAR files, e.g. Composer, CodeSniffer, etc.

Box is a tool that can help you create a PHAR file out of a PHP application, and it's very easy.

On installing the program, it'll perform a few checks to confirm PHAR files can be created successfully with your PHP setup.

$ curl -LSs https://box-project.github.io/box2/installer.php | php
Box Installer  
=============

Environment Check  
-----------------

"-" indicates success.
"*" indicates error.

 - You have a supported version of PHP (>= 5.3.3).
 - You have the "phar" extension installed.
 - You have a supported version of the "phar" extension.
 - You have the "openssl" extension installed.
 - The "phar.readonly" setting is off.
 - The "detect_unicode" setting is off.
 - The "allow_url_fopen" setting is on.

Everything seems good!

Download  
--------

 - Downloading manifest...
 - Reading manifest...
 - Downloading Box v2.7.4...
 - Checking file checksum...
 - Checking if valid Phar...
 - Making Box executable...

Box installed!  

The most common scenario is your phar.readonly PHP setting is probably going to be commented out or turned On. To create PHAR files, you need to have it explicitly set to Off.

$ grep "phar.readonly =" /etc/php/7.0/cli/php.ini 
phar.readonly = Off  

If all is well, then you can create your first PHAR file. There's a Box Example application to get you started.

$ box build && ls -l box.phar
Building...  
-rwxr-xr-x. 1 {USER} {GROUP} 1020781 Sep 25 18:24 box.phar

Here you go. You can now easily distribute PHAR files to your users.

Aurelien Navarre

Senior Technical Solutions Analyst @Acquia - Drupalist by day, DevOps by night.

Lyon, France