Pages

2016/09/26

PHP 7 on macOS Sierra


PHP 7 on macOS Sierra

Apple has released the latest version of their OS X operating system to the broad public and many have already upgraded their mac devices. But as it goes with each release, Apple likes to do things a bit different making it quite challenging for PHP developers to stay current with the latest PHP version (or other versions).

This version of mac OS (11.12) comes pre-installed with PHP 5.6.24.

PHP 5.6.24 (cli) (built: Aug  8 2016 16:58:37)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies


Good for Apple, but this version reaches end-of-life support by the end of this year, so it would be great if you could upgrade to PHP 7.0 or even play with the latest PHP 7.1 release candidates.

Of course you can always turn to Homebrew, XAMMP or whatever package manager you use for easy installations, but taking the compiling path is just as complicated. The failure is equal in most situations.

Configuring PHP on macOS Sierra triggers the following error:


apxs:Error: /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.12.xctoolchain/usr/local/bin/apr-1-config not found!.
configure: error: Aborting


In this version of Apple's OS the Apache Portable Runtime was not included. You need to download it and compile it yourself.

wget http://apache.proserve.nl//apr/apr-1.5.2.tar.bz2
wget http://apache.hippo.nl//apr/apr-util-1.5.4.tar.bz2


Check the checksums!

tar -xjf apr-1.5.2.tar.bz2
tar -xjf apr-util-1.5.4.tar.bz2

cd apr-1.5.2/
./configure
make
make install

cd ../apr-util-1.5.4/
./configure --with-apr=/usr/local/apr
make
make install

sudo mkdir -p /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.12.xctoolchain/usr/local/bin/
sudo ln -s /usr/local/apr/bin/apu-1-config /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.12.xctoolchain/usr/local/bin/apu-1-config
sudo ln -s /usr/local/apr/bin/apr-1-config /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.12.xctoolchain/usr/local/bin/apr-1-config


Now you can hapily compile and run the latest PHP version on the latest OS from Apple. See my previous article Compile PHP 7 on Mac OS X 10.11 "El Capitain" for instructions.


Happy PHP-ing!

2016/07/19

Compile PHP 7 on Mac OS X 10.11 "El Capitain"


Apple has made a numerous changes to the way OS X (10.11) "El Capitain" uses open source elements like PHP and OpenSSL. Compiling PHP from source requires a bit more modifications.
This article is a follow-up on my previous post Installing PHP 7 with XDebug, Apache and MySQL on OS X Yosemite

OpenSSL

Get the latest OpenSSL from openssl.org and unpack it so you can work with the sources.
Then just execute:
./Configure shared darwin64-x86_64-cc
make depend
make
sudo make install

PHP 7

Download the latest PHP 7 source code from php.net/download and unpack it in a temporarily directory, I like to use /tmp.
My configure command arguments:
./configure \
--prefix=/opt/php7 \
--enable-cli \
--enable-mbstring \
--enable-gd-native-ttf \
--enable-gd-jis-conv \
--enable-sockets \
--enable-exif \
--enable-ftp \
--enable-intl \
--enable-soap \
--enable-zip \
--with-apxs2 \
--with-iconv=/usr \
--with-config-file-path=/etc/php7 \
--with-config-file-scan-dir=/etc/php7/ext \
--with-libxml-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/ \
--with-openssl=/usr/local/ssl \
--with-curl \
--with-gd \
--with-libedit \
--with-mcrypt=/usr/local/bin \
--with-mysqli \
--with-zlib \
--with-pdo-mysql \
--with-mysql-sock=/tmp/mysql.sock
This gives me most of the modules and extensions I require for doing my PHP work. For concrete situations I prefer to use virtual machines or Docker containers to mimic the production environment as much as possible, but for small work it's easy to have it running natively on my local machine.
WARNING: Compile OpenSSL instead of using the build-in SSL as it's not compatible!
Edit PHP's Makefile and find the line that begins with EXTRA_LIBS. In this line, replace the following references -lcrypto with /usr/local/ssl/lib/libcrypto.dylib and -lssl with /usr/local/ssl/lib/libssl.dylibor where you have installed the latest OpenSSL library.
A convenient way is to use vi and use :s/\-lcrypto/\usr\/local\/ssl\/lib\/libcrypto.dylib/g to immediately replace all instances of -lcrypto in the line. Do the same for -lssl as well.
Once done, just execute makemake test and sudo make install to install the latest PHP 7 version on your MacBook.
You might want to replace the build-in php with your new compiled version of PHP.
cd /usr/bin
sudo mv php php-orig
sudo ln -sf /opt/php7/bin/php php
When you execute php -v you should see something like the following:
PHP 7.0.8 (cli) (built: Jul 19 2016 11:36:18) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
    with Xdebug v2.4.0RC2, Copyright (c) 2002-2015, by Derick Rethans

Apache

It's nice to have PHP on command line, but you might want to have it run in your apache configuration as well.
If you look at the output of "make install" you will see the line:
[activating module `php7' in /private/etc/apache2/httpd.conf]
This means PHP has modified your apache configuration and included the php7 module, you only need to activate it.
In /etc/apache/httpd.conf find the following line:
LoadModule php5_module libexec/apache2/libphp5.so
And comment it out, as we're no longer use php 5, like this:
#LoadModule php5_module libexec/apache2/libphp5.so
Locate the line:
#LoadModule php7_module        libexec/apache2/libphp7.so
And remove the comment hash (#) in front of it
LoadModule php7_module        libexec/apache2/libphp7.so
Restart apache with sudo /usr/sbin/apachectl restart
Now put the following file (info.php) in your document root (see /etc/apache/httpd.conf where this is)
>?php phpinfo();
And point your browser to that file on your local machine, in my case it is http://localhost/info.php.
PHP 7.0.8 running on "El Capitain"


You're now ready to unleash the PHP7 power! Have fun and let me know in the comments if it worked out for you. If not, let's work together how we can solve the issue.

2016/06/01

PHPSrbija Conference 2016 review

This past weekend I was invited to speak at PHP Srbija Conference 2016 which was held in Belgrade, the capital of Serbia in the south-east of Europe.

I feared that my departure from Brussels Airport was going to take up a lot of time since the terrorist bombing on March 22, but going through the additional security measures went very smoothly.
Arrived at Brussels Airport well ahead of departure time for #phpsrbija
So, I ended up in "the Loft" business lounge on terminal A where I could catch up on some email and do some work before my flight left for Zurich.
Made it to “the Loft” lounge at Brussels Airport. Let’s get some work done! #IWorkAnywhere #DigitalNomad
This StarAlliance business lounge offers soups, bread and hot snacks along with a variety of drinks. So while waiting for your flight you can relax in the very comfortable sofa's (see picture), have a desk-like table for meals or work, use the sleeping pods or take a shower. I decided to have my coffee and a warm snack before take-off.

At the gate I got a pleasant surprise as I was upgraded to business class, making my trip to Zurich very comfortable.
Just got upgraded to @FlySWISS Business Class! W00t! #travelmagic #phpsrb2016
The flight from BRU to ZRH was quick and uneventful. Making the connection in Zurich was without stress as my flight to Belgrade was delayed. But Zurich is a very nice airport with lots of shops and bars, so instead of heading to the business lounge I ended up wondering around from shop to shop.

At my arrival at Nikola Tesla Airport Belgrade I was welcomed by Milan Popović, one of the 3 organizers of the conference. Milan is a very passionate guy who made PHP Srbija to what it is today.

Awesome reception by @komita1981 as a great start for #phpsrb2016
Before we got to the hotel, we first went for dinner. The other two organizers Aco Gagic and Nikola Poša, a couple of volunteers, Phil Sturgeon and Chris Hartjes were already there and had completed their meals. Milan and I joined the table and got extras. The food was awesome and made me forget I had traveled the bigger part of the day. That night, I slept immediately after we arrived at the hotel.
It's pre #phpsrb16 with @grmpyprogrammer @philsturgeon @DragonBe @nikolaposa @komita1981 @AcoGagic @LDusan

The day before the conference, Milan and Nikola took us on a tour at Belgrade Fortress, a beautiful piece of European history that is kept well preserved against the evils of time. If you visit Belgrade, you should visit this place, with perfect view over the Sava and Danube as it was build at their juncture. The visit was followed by a "small" lunch offered by the crew where we catched up with my good friend and fellow ninja turtle Rafael Dohms.

Lunch time! #phpsrb2016
In the evening we were joined by Ciaran McNulty when we went out for drinks and food. I've come to realize that "lots of meat" is just a simple meal in Serbia.

Just a bit of meat

Conference Day 1! Chris Hartjes was opening keynote and presented his best talk I've seen so far. Was it because of the great food or the warm welcome of the Serbian community, I leave that up to your immagination, but Chris flawlessly presented his keynote talk "An oral history of how I became Grumpy". The rest of the day was filled by Sebastian Bergmann, Rafael DohmsCiaran McNulty, Derick Rethans and Phil Sturgeon.


Conference Day 2: Again a day filled with awesome talks by Rafael Dohms, Marco Pivetta, Michelangelo van Dam (me), a dual talk by Sebastian Bergmann and Ciaran McNulty to be closed off by Gojko Adzic who presented an amazing "The future of test automation" closing keynote.


Again, I would like to thank the organizers Aco GagicMilan Popović and Nikola Poša of #PHPSrb16 for going way beyond expectations. You are awesome hosts and it was my privilege being part of this amazing event and taking home so many wonderful experiences.

I can recommend PHPSrbija Conference to every speaker!

It was hard to say goodbye to the good friends I made at this conference, but every beginning has to have an end. So on Monday I started my way back home. But this time it was a bit more eventful as I had hoped for. Flights were delayed because of bad weather in Western Europe and once I arrived back in Belgium, I ended up without normal public transportation because of strikes. In the end, I litterly had to walk the last mile back home. But I made it safe and sound. This little setback was nothing compared to the great conference I had in Serbia. Can't wait for next year!

2016/02/06

PHP Arrays - The php array functions

Source: Xavier33300 on Flickr.com
In my previous article about arrays (the basicssimple operations and associative arrays or hash maps) I have shown what arrays are and what you can do with it. Now I want to dive into real fun and explain PHP's array functions with real-world examples and how you can apply them in your day-to-day work.

Collection to select form key-values

Many of the website registration forms uses a country select element or an autocomplete input field using data from a database.


If this was a single PHP with HTML combined page, there was no problem as you could easily reuse the query made to collect the data. But when using an MVC approach where your controller needs to push the data it fetches from the backend to the form before the form can be passed to the view you're in for a treat. We're addressing the issues for an MVC approach here.

Let's look at our country table first to get an impression how data is being stored in the database.

+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | int(11)     | NO   | PRI | NULL    | auto_increment |
| iso       | char(2)     | NO   |     | NULL    |                |
| name      | varchar(80) | NO   |     | NULL    |                |
| nicename  | varchar(80) | NO   |     | NULL    |                |
| iso3      | char(3)     | YES  |     | NULL    |                |
| numcode   | smallint(6) | YES  |     | NULL    |                |
| phonecode | int(5)      | NO   |     | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+

In order to use this data in our forms, the two fields "iso" and "printable_name" are most likely the fields that would make the most sense.

Two approaches we can take here:

  1. we query our database for only those fields we need, with the requirement that we need to make a second database call when we need to populate our select field for country phone prefixes
  2. we query all of our required fields "iso", "printable_name" and "phonecode" in one query and use PHP array functions to populate our select fields
We choose to take option 2.

Let's have a look on how most people do things nowadays. The first thing they do is retrieve the data from their backend in the controller. In the controller they prepare their form and pass the form back to the view.

public function registerAction()
{
    
$form $this->getForm('member');

    
$countryMapper = new CountryMapper();
    
$countryList $countryMapper->fetchAll();
    
$countrySelect = [];
    
$phoneSelect = [];
    foreach (
$countryList as $country) {
        
$countrySelect[] = [
            
'iso' => $country['iso'],
            
'nicename' => $country['nicename'],
        ];
        
$phoneSelect[] = [
            
'phonecode' => $country['phonecode'],
            
'nicename' => $country['nicename'],
        ];
    }
    
$form->getElement('country')->addMultiOptions($countrySelect);
    
$form->getElement('phoneprefix')->addMultiOptions($phoneSelect);

    if (isset (
$this->session->memberForm)) {
        
$form unserialize($this->session->memberForm);
        unset (
$this->session->memberForm);
    }
    return [
        
'memberForm' => $form,
    ];
}

So, within the controller a loop is created to populate two field elements "country" and "phoneprefix".  Even though this is an easy approach and works in most cases, the moment you have a lot of data to process, this kind of approach is slowing down your application. Say hello to two power functions: "array_walk" and "array_intersect_key"!

PHP function "array_walk" allows you to apply user functionality to each element of that array. This means we can apply our second functionality "array_intersect_key" on each row.

PHP function "array_intersect_key" gives us the ability to take the common elements from our country list row and the keys we provide as second argument.

$countrySelect = [];
array_walk($countryList, function ($row$key) use (&$countrySelect) {
    
$countrySelect[] = array_intersect_key(
        
$row,
        [
'iso' => null'nicename' => null]
    );
});

$phoneSelect = [];
array_walk($countryList, function ($row$key) use (&$phoneSelect) {
    
$phoneSelect[] = array_intersect_key(
        
$row,
        [
'iso' => null'phonecode' => null]
    );
});

Now we have two arrays that contain only the elements we can just pass on to the form select elements. And the whole controller action now looks like this:

public function registerAction()
{
    
$form $this->getForm('member');

    
$countryMapper = new CountryMapper();
    
$countryList $countryMapper->fetchAll();
    
$countrySelect = [];
    
array_walk($countryList, function ($row$key) use (&$countrySelect) {
        
$countrySelect[] = array_intersect_key(
            
$row,
            [
'iso' => null'nicename' => null]
        );
    }); 

    
$phoneSelect = [];
    
array_walk($countryList, function ($row$key) use (&$phoneSelect) {
        
$phoneSelect[] = array_intersect_key(
            
$row,
            [
'iso' => null'phonecode' => null]
        );
    });
    
$form->getElement('country')->addMultiOptions($countrySelect);
    
$form->getElement('phoneprefix')->addMultiOptions($phoneSelect);

    if (isset (
$this->session->memberForm)) {
        
$form unserialize($this->session->memberForm);
        unset (
$this->session->memberForm);
    }
    return [
        
'memberForm' => $form,
    ];
}

Finding primary keys from a collection

Another common pattern I see is when developers need to pull ID's from a collection of elements to pass on to a next request. Again, foreach is the common used loop to iterate over each element, adding the ID property to another array which then gets passed on to the query.

Let's first look our code that we're going to process.

class PhpFunction {
    public 
$id;
    public 
$label;

    public function 
__construct($id$label)
    {
        
$this->id $id;
        
$this->label $label;
    }
$functions = [
    new 
PhpFunction(123'array_map'),
    new 
PhpFunction(124'array_merge_recursive'),
    new 
PhpFunction(125'array_merge'),
];

Now this example is only containing 3 elements, but when you look at the php.net website there are thousands of functions, so consider this is a huge collection of php functions.

In many cases I see something like the following code to retrieve the ID's from this collection:

$functionIds = [];
foreach (
$functions as $function) {
    
$functionIds[] = $function->id;
}

Even though this is a common pattern, I would prefer to use a native PHP function for processing this. Say hello to "array_map", the function that allows you to use a custom functionality on each element of the given array.

$functionIds array_map(function ($element) {
    return 
$element->id;
}, 
$functions);

The result is exactly the same, but now using PHP's native C power processing huge arrays goes a bit faster than the "foreach"-loop.

Next article we're looking at more common patterns for processing arrays. Love to see you again.



2016/01/14

PHP Arrays - Associative Arrays or Hash Maps


Associative array or hash maps are listings of key and value pairs with a posibility to nest additional keys and values. An associative array is a very powerful construct within PHP.

In our previous article we discussed simple arrays, which in their turn are indexed associative arrays under the hood. Take the following example:

$array = [
  
'apple',
  
'banana',
  
'chocolate',
]; 


Is in fact an indexed associative array under the hood:

$array = [
    
=> 'apple',
    
=> 'banana',
    
=> 'chocolate',
]; 


But associative arrays can be so much more than just an indexed array, and you will find many database operations returning arrays where the fields of a table are the keys in the array while their values are also the values within the array.

$productRowData = [
    
'product_id' => 1234,
    
'brand_id' => 321,
    
'product_name' => 'Our awesome product',
    
'prodcut_description' => 'This is our most awesome product.',
    
'product_sku' => 'ABC1234-XYZ',
    
'product_price' => 59.95,
];


Another example of use is to store configuration information in a PHP array, like Zend Framework does. It's maybe why they call it the "Array Framework". But it's actually a good approach to store configuration settings inside a PHP array as you don't need to parse another format like INI, XML, YAML, JSON or CSV, saving a couple of CPU cycles loading the configuration for your application. Once parsed, it will be represented as an array anyways, maybe serialized for persistance.

$dbConfig = [
    
'db' => [
        
'erp' => [
            
'host' => '123.123.456.456',
            
'port' => 3306,
            
'username' => 'erp_user',
            
'password' => 'v3rRy$ecR3tP@ssMor7! ',
            
'dbname' => 'erp',
        ],
        
'crm' => [
            
'host' => '123.123.426.426',
            
'port' => 3306,
            
'username' => 'crm_user',
            
'password' => ' Y0u L1k3 f1&h 4nD Ch1p$?! ',
            
'dbname' => 'crm',
        ],
    ],
];


How can we iterate over these values? The easiest way is to use "foreach()" as we can define the key and value in the iteration construction:

foreach ($productRowData as $key => $value) {
    echo 
'key : '  $key PHP_EOL;
    echo 
'value: ' $value PHP_EOL;
    echo 
PHP_EOL;
}


For the other loops like "for", "do-while" and "while-do" we need to do a bit of extra work. As we don't have direct access to the "index" of the associative array, we cannot iterate over the keys. So we fetch the keys as a seperate array with "array_keys" function.

$count count($productRowData); 
$keys array_keys($productRowData);

echo 
'== Iteration with for' PHP_EOL;
for (
$i 0$i $count$i++) {
    echo 
'key : '  $keys[$i] . PHP_EOL;
    echo 
'value: ' $productRowData[$keys[$i]] . PHP_EOL;
    echo 
PHP_EOL;
}

echo 
'== Iteration with do-while' PHP_EOL
$i 0;
do {
    echo 
'key : '  $keys[$i] . PHP_EOL;
    echo 
'value: ' $productRowData[$keys[$i]] . PHP_EOL;
    echo 
PHP_EOL;
    
$i++;
} while (
$i $count);

echo 
'== Iteration with while-do' PHP_EOL
$i 0;
while (
$i $count) {
    echo 
'key : '  $keys[$i] . PHP_EOL;
    echo 
'value: ' $productRowData[$keys[$i]] . PHP_EOL;
    echo 
PHP_EOL;
    
$i++;
}


Both loops "for" and "while-do" will first evaluate the given condition before they start their iteration. The "do-while" loop will execute the loop at least once before validating a condition. In some conditions this can be convenient.

What if we want to look for a specific value, should we iterate over each element until we find the value? Let's say we are looking in our configuration for the array containing the value "123.123.426.426" because we found it in one of our logs. A very common practice is the following example:

$searchResult null
$search '123.123.426.426'

foreach (
$dbConfig as $db) {
    foreach (
$db as $target => $dbSettings) {
        if (
$search === $dbSettings['host']) {
            
$searchResult $dbSettings;
        }
    }

// do something with $searchResult

This is a very common practice I come accross and even though it's not a bad practice, there are php array functions available that do the trick as well. In this case, I choose "array_filter" to quickly retrieve the correct array.

foreach ($dbConfig as $db) {
    
$searchResult array_filter($db, function ($v) use ($search) {
        return 
in_array($search$v);
    });

// do something with $searchResult

Above functionality allows us to keep a clear understanding what's going on and we reduce the amount of iterations we need to execute. Consider doing this on an array with a couple of 1000 entries.

In our next article we're going to look a bit more at the various PHP array functions you can use in your day-to-day application development.