34
Published by S&S Media Group www.webandphp.com ALSO IN THIS ISSUE December 2013 Issue 21 PHP variables by Julien Pauli Compile Your Style part 2 by Ragnar Kurm End-to-end tests by Sebastian Bergmann Open source spotlight: PHP-CPP Nginx: A beginner’s guide Gift your site with a new server Automation with Phing Let your computer do the hard work Inside Git Sometimes you actually do need to know how it works ©iStockphoto.com/studio9400

nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

Embed Size (px)

Citation preview

Page 1: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

Published by S&S Media Group

www.webandphp.com

Also in this issue

December 2013Issue 21

PhP variablesby Julien Pauli

Compile Your style part 2by Ragnar Kurm

end-to-end testsby Sebastian Bergmann

open source spotlight: PhP-CPP

nginx: A beginner’s guideGift your site with a new server

Automation with PhingLet your computer do the hard work

inside GitSometimes you actually do need to know how it works

©iS

tock

pho

to.c

om/s

tud

io94

00

Page 2: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

Contents

ContentsLetter from the Editor

Linux, Apache, MySQL and PHP, as we all know, go together like John, Paul, George and Ringo. ‘LAMP stack’ has a nice ring to it and opens the door to a host of Anchorman refer-ences. Yet, just because it’s become ingrained in PHP’s culture, that doesn’t

mean we shouldn’t explore alternatives.Take MySQL, for example. Our faithful database

companion has been through a rough few years in the wake of Sun’s purchase, and the emergence of fork MariaDB seems to threaten its very existence. At Per-cona Live London last month, Monty Widenius – the man who founded both MySQL and, more recently, MariaDB – gave a keynote on how his new company has improved on MySQL and, more importantly, how easy it is to switch.

Perhaps in order to provide an alternative perspec-tive, Percona scheduled an Oracle keynote immediate-ly afterwards, in which Tomas Ulin came out fighting. “Monty has told you to switch, so I guess have to tell you not to switch,” he joked, but the keynote was clearly defensive in tone. Ulin emphasised Oracle’s commitment to MySQL, both in terms of resources be-ing thrown at it and performance improvements in 5.6.

MariaDB isn’t drastically different from MySQL, though. And it keeps the ‘M’ in LAMP constant. How about the ‘A’, then? Apache HTTP Server dominates the market, but it’s not always necessarily the best option.

How about Nginx? LNMP may be awkward to pro-nounce, but the Russian server is worth a look if you’re working with particularly high traffic, or just looking for joyfully simple configuration files. Benjamin Greena-way explains how to get to started on page 5.

As you might already know, this PDF you’re reading right now is the final ever issue of Web & PHP Maga-zine. It’s been a fantastic couple of years, but all good things must come to an end, and going into 2014 the magazine will no longer be publishing. (Don’t worry, I’m not out of a job; I’ll be working for JAXenter.com, our site for Java developers.)

In its short time on Earth, Web & PHP Magazine has left a distinct mark on the PHP community. We’ve pub-lished some incredible articles by a truly brilliant se-lection of expert web developers, and I’m thankful to everyone who has contributed – from one-off writers to our regular columnists.

I can’t take all the credit, of course. Previous editors Louis Goddard and Anna Kent did an incredible job in laying the mag’s foundations and building the the audi-ence up from nothing. The design team also deserve a shout-out for making Web & PHP look beautiful every single month.

Thanks again for reading, everyone. It’s been a lot of fun.

Elliot Bentley, Editor

P.S. Our friends at Navicat are offering Web & PHP Magazine readers an exclusive 20 % off their database management productions. Just follow this link: http://goo.gl/roOyuq

Switching off the LAMP Community CornerThis month’s top events 3Open source spotlight: PHP-CPP 4Interview with Emiel Bruijntjes

Tutorial Merry Nginxmas: 5 A beginner’s guide Benjamin Greenaway

TutorialAutomate ALL the Phings! 9Joey Rivera

TutorialGit is simple (on the inside) 14Ben Straub

FeatureHow PHP manages variables 18Julien Pauli

TutorialCompile Your Style: 25 Structuring and automating CSS Ragnar Kurm

ColumnEnd-to-end tests: 33 not the be-all and end-all Sebastian Bergmann

www.webandphp.com Web & PHP Magazine 12.13 | 2

Page 3: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

Community CornerCalendar

To suggest an event for our calendar, email [email protected].

this Month’s toP events December 3 – January 7 // A handpicked selection of some of the most

exciting PHP events from around the world

December 12 // Oviedo, FL, USA // Free

Beer.js http://www.meetup.com/Orlando-Software-Engineers/events/145035232/Free beer is promised, in addition to discussion of four node modules to make the development process easier: express.js, mongoose, jade and mocha.js

December 11 // Sydney, Australia // Free

Port80 sydney: end of year Mixerhttp://www.meetup.com/Port80-Sydney/events/149833382/Port80 and other local tech meetups come to-gether for a big party in the King St Brewhouse (located on King Street Wharf).

December 11 // Bristol, UK // Free

PhPsWhttp://www.meetup.com/PHPUGSW/events/151042702/“Finally!” tweeted the organisers as they re-vealed this one. The first announced talk will be on a ZF 1 REST API to Silex.

December 10–14 // Warsaw, Poland // € 299

symfonyConhttp://warsaw2013.symfony.com/The first ever conference for the fast-growing framework also hosts results for the 2013 Symfony Awards.

December 5 // Cape Town, South Africa // R100

security Workshophttp://www.meetup.com/Cape-Town-PHP-Group/events/151028602/Learn about tools for testing your own security setup: Kali Linux, Nmap and sqlmap. The en-trance fee will be dropped if a sponsor can be found in time.

December 11 // Santiago, Chile // Free

2da tanda de frameworkshttp://www.meetup.com/PHP-Frameworks-SCL/events/148795312/The second event in a series will be compar-ing Drupal, CodeIgniter and CakePHP. At least, that’s what Google Translate tells me.

www.webandphp.com Web & PHP Magazine 12.13 | 3

Page 4: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

Community CornerOSS Spotlight

Web & PHP Magazine: Who’s behind PHP-CPP?Emiel Bruijntjes: I am founder and CTO of Co-pernica Marketing Software and have been a PHP programmer since 2000. I’ve programmed using C/C++ since 1995.

WPM: Why did you decide to start it? And why did you make it open-source?Bruijntjes: While PHP is an easy to use language with a great syntax, it also has some issues. Com-pared with C++, it’s very slow and uses a lot of CPU. Wanting to improve the performance of the PHP based Copernica [http://www.copernica.com/] by mixing in some C++, I started studying the inter-nals of the PHP engine.

But despite the fact that this is currently the only way to combine PHP and C++, I found out that it is far from easy to use. PHP extensions are very hard to implement and require a deep knowledge of the Zend engine and pointer manipulation. Acquiring this knowledge is also nearly impossible to do, as clear documentation is barely available.

Even if I took the time to learn how to develop PHP extension with the PHP API, my fellow de-velopers at Copernica would have to learn to do so as well.

I decided there had to be a better way to combine PHP and C++. Creating the necessary libraries however would be too difficult for me to achieve alone. That’s why I decided to ask the open source community for help. Also because this is a project that can be of value for a lot of PHP developers, not just me.

WPM: What are PHP extensions useful for?Bruijntjes: Well, of course there is the performance is-sue. By mixing PHP and native you can speed up pro-cesses. If you have a website for example, you can reduce the load time of your website. Or accelerate the performance of your software.

A lot of developers now decide to just plug in some extra servers to compensate for the extra CPU load PHP code generates. While it doesn’t have to be that way if you re-place certain parts of your PHP algorithms with C++.

But going full native is not an option either. For a lot of developers it’s a language that’s too hard to master. PHP is a much more forgiving language than C++. Also, whenever you make a mistake in PHP, you can exactly see where something went wrong in the log file. Op-posed to C++, where small mistakes can result in fatal crashes.

WPM: How does PHP-CPP make them easier to create?

open source spotlight: PhP-CPP

Bruijntjes: The PHP-CPP library uses C++ fea-tures as operator overload, casting overloading and implicit constructors. This allows you to use C++ objects as if they were PHP variables. Because of this, extenstion creators will be able to create very straightforward code. All complicated constructions with memory management and pointer manipula-tion will stay hidden and handled by the PHP-CPP library.

WPM: Where do you hope to see the project in a year’s time?Bruijntjes: In a year’s time I’d like to see that PHP-CPP is the jQuery for PHP. Just like it’s normal to not address the DOM with JavaScript, I’d like to see that creating native extensions will no longer be done through the Zend engine, but through PHP-CPP.

Also, I hope that there will be a core team of a few people that develop the library themselves. Also, I expect the library to be used for other libraries like Symphone, CakePHP, FuelPHP and Lavarel. These frameworks could increase their performance sig-nificantly with PHP-CPP.

Meeting the people behind the most exciting homegrown OSS projects. This month, we speak to emiel Bruijntjes about PHP-CPP, a new library for writing PHP extensions in C++.

Homepage: http://php-cpp.comGitHub: https://github.com/EmielBruijntjes/PHP-CPP

www.webandphp.com Web & PHP Magazine 12.13 | 4

Page 5: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialNginx

by Benjamin Greenaway

Nginx (pronounced “engine x”) is an open source reverse proxy server for http, https, and the smtp, imap and pop3 mail protocols. It is an interesting and increasingly popular al-ternative to Apache for serving PHP, and this month we will take a look at how it works and how to use it.

Webservers of Xmas PastThe Nginx project started with a strong focus on concurrency at a time when webserver ca-pabilities made serving greater than 10,000 simultaneous requests a matter for multiple hosts. The “C10K problem”, as it is known, was resolved for the Russian search engine Rambler by Igor Sysoev, with the first release of his new, event driven and asynchronous webserver Nginx.

The first public version was released in Oc-tober 2004, and each version since then has been available under the 2-clause BSD-like li-cense, free to download, modify, use and dis-tribute, from [1] Since then its use has grown and grown, especially in the higher perfor-mance site sector.

Unlike the industry standard server Apache, Nginx responds to requests asynchronously with an event-based approach. It consumes fewer system resources per request than Apache does with its thread-driven process and hence can manage a higher number of connections within the same operating sys-tem and hardware footprint.

Reverse proxy servers, which are function-ally equivalent to their forward proxy server namesakes, insulate hosts from networks, rather than clients. Deploying a reverse proxy has its advantages: from the normalization of

A speedy seasonal special

Merry nginxmas: A beginner’s guide This holiday season, give your site the gift of asynchronous reverse proxy server Nginx.

Listing 1: A simple php-fpm site config in Nginxhttp { server { listen 80; server_name testsite.local; access_log /var/www/html/testsite.local/logs/access.log; error_log /var/www/html/testsite.local/logs/error.log; root /var/www/html/testsite.local/public_html; location / { index index.html index.htm index.php; } location ~ \.php$ { include /etc/nginx/fastcgi_params; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME/var/www/html/testsite.local/public_html$fastcgi_ script_name; } }}

www.webandphp.com Web & PHP Magazine 12.13 | 5

Page 6: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

tify logging files and the root for the filesystem to serve from. Then we add two additional blocks called “loca-tion” which refer to the HTTP re-quest being made.

If Nginx sees the request URL matches a location block, the direc-tives within that block will be followed. Within that block Nginx will override any previously declared parameter for a di-rective if it exists.

The syntax for location is location [= | ~|~*|^~|@] pat-tern { … } and the matching precedence employed by Nginx is as follows: location blocks with the = modifier, location blocks with no modifier at all, location blocks with the ^~ (pattern begins with) modifier, location blocks with the ~ or ~* (pattern or pattern ends with) modifier. If no location block has been found to match the request at this point, a block with no modifier whose string matches the start of the request will be used.

Our example directs all requests the root towards index.html, index.htm or index.php and all requests to a php script towards the service listening at local-host:9000, where php-fpm runs in its default settings. Nginx will match the php script regardless of query string parameters and forward them on.

The file fastcgi_params included by the listing above establishes environment variables specific to the oper-ation of FastCGI and can be tailored to suit your needs. It does not replace php.ini, which will be parsed and loaded when you start your php-fpm service.

Listing 2 adds two further location blocks and a pair of directives to the http block. Turning on gzip com-pression for all content returned by Nginx is set by gzip

Who uses nginx?

NetCraft’s July 2013 Web Serv-er survey recorded nginx as

the third most widely used web server across all domains with 13 % of all surveyed sites [3]. W3Techs saw 17 % of the top 1 million sites, 26 % of the top 100,000 sites and 34% of the

top 10,000 hosted by nginx [4].

TutorialNginx

DNS or protection of your IP addresses, to a variety of caching configurations and the management of sepa-rated services. As well as being a reverse proxy server out of the box, Nginx is also a capable load balancer and ideally suited to be first host of response, though it can equally be deployed alone to serve files and handle CGI script requests.

Getting hold of a copy is easy. The official site hosts repositories for Debian/Ubuntu, RHL/Cent, BSD and an official Win32 binary at wiki.nginx.org/Install. If you plan to run PHP scripts you will additionally need the FastCGI Process Manager “php-fpm” (the Python equivalent is “python-flup”) since all script execution in Nginx must be over CGI. There is a good package in the Debian repos for php-fpm, so a quick:

“sudo aptitude install php5-fpm” should get you on your way. The EPEL and Remi repos have up to date versions for yum installations, a gist of my notes is available at [2].

The Nginx wiki also includes build from source in-structions, which you may need for module additions later and Packt Publishing currently ship their second edition of the book, “Nginx HTTP Server” containing many useful Nginx setup tips.

Webservers of Xmas PresentEach instance of Nginx operates under a configura-tion file composed of a hierarchical series of logical blocks, identifying behaviours and services by di-rectives and parameters. These configuration files will appear familiar to anyone who has worked with Apache or any other server before now. The configu-ration file and any other file includes it might declare, are loaded and passed once at each server start, and remain active and unalterable until the next restart or reboot.

In listing 1, we set the http server to listen on port 80, as expected, give it a name – “testsite.local” – and iden-

Listing 2: Header and Gzip control in Nginx

http { gzip on; expires 86400;

server { listen 80; server_name testsite.local; access_log /var/www/html/testsite.local/logs/access.log; error_log /var/www/html/testsite.local/logs/error.log; root /var/www/html/testsite.local/public_html; location / { index index.html index.htm index.php; } location ~ \.php$ { expires 3600; include /etc/nginx/fastcgi_params; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME/var/www/html/testsite. local/public_html$fastcgi_script_name; }

location /rawserve/ { gzip off; } location /nevercache/ { expires -1; }

}}

www.webandphp.com Web & PHP Magazine 12.13 | 6

Page 7: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialNginx

on in the http block. Cache control headers for expiry are managed through the expiry directive, taking pa-rameters in second by default. All files now served by this server will be compressed, with an expiry time of 1 month except for the results of php scripts (which will expire after 1 day) and the contents of the direc-tory nevercache – a negative value sends do not cache

headers instead. Also, a request to the directory named rawserve will return non-gzipped content.

Location blocks can specify behaviours beyond CGI too. In listing 4, the WordPress admin area is secured by credentials stored in a password file at /etc/nginx/conf.d/allowedusers_htpasswd.

If you wish to redirect requests, the rewrite directive can modify the request on your behalf according to the pattern and replacement rules you give it. Both perma-nent 301 and temporary 303 redirections are shown in this example.

Listing 5 adds another new block – upstream – and demonstrates Nginx as a reverse proxy for Apache. Here, anything matching the php script pattern is for-warded on to one of the upstream servers, according to the load balancing rules for each.

With a weight of 2, the third upstream server will receive twice as many requests as each of the oth-ers. The last of the list, marked backup, will only re-ceive requests if each of the other three are down. The additional ip_hash; directive should be added to the upstream block to keep the PHP sessions sticky; any static, non PHP script content will be served di-rectly by Nginx. Therefore, no changes need be made to your current Apache hosting environment to take advantage of deploying Nginx up front. By swapping the commented-out proxy_pass line for the active one, a localhost Apache instance rather than a round robin cluster could be proxied instead.

Webservers of Xmas Yet to comeThough Nginx was designed for a very specific pur-pose and has only a fraction of the number of exten-sions written for it that Apache does, it is by no means half-baked. Like Apache, Nginx may be extended by adding first- and third-party modules, though unlike Apache these extensions must be compiled in before use.

In the last two years, module additions have included Web-Sockets, SPDY, HTTP streaming sup-port for FLV and MP4. As of OpenBSD release 5.2, Nginx has become the default HTTP server, replacing a fork of Apache 1.3. That counts as real skin in the long term game. More recently, the Nginx Inc company was founded, financed and began offering technical support similar to offerings from Red Hat. Having opened new offices in San Francisco and recommitted to maintain-ing the project as Open Source, Nginx looks to have a bright and well supported future.

As to Apache, I shan’t attempt to speculate too much. But it would be hard to imagine any dramatic change to its core architecture or the approach which has driven its success. Apache deployment options have always benefited from the range of third-party modules, and that is certain to continue: that territory is far more fully mapped in the Apache space than with Nginx.

When Apache was being designed, the range of tasks to which the webserver would be applied was unclear, even when the 2.x branch was begun in 2001. Nginx then rather gains in hindsight over its elder forbear – the flexibility so appealing in Apache will likely remain its defin-ing factor, compared to the niche in which Nginx thrives. But there’s more of gravy than of grave about Apache just as yet!

Listing 4: Rewrite and Redirect with Nginx

location /not-here-elsewhere/ { rewrite ^ http://www.example.com/temporary/resource/location redirect;}

location /not-here-elsewhere/ { rewrite ^ http://www.example.com/permanently/moved/location permanent;}

php.net

netflix.com

“We use the nginx web server for its proven scal-

ability and perfor-mance” [6]

WordPress.com

Has used nginx in loadbalancers since

2008, all backend http since 2012 [5]

Listing 3: Basic http-auth securitylocation /wp-admin/ { index index.php; auth_basic "mysite : secured area"; auth_basic_user_file /etc/nginx/conf.d/allowedusers_htpasswd;}

www.webandphp.com Web & PHP Magazine 12.13 | 7

Page 8: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialNginx

Nginx bless us, every one.So is Nginx really the best and fastest thing ever? And should I deploy it at once? Maybe. Of course, it mat-ters to analyze what kinds of content you will serve. Static content components of your sites like image and media files, CSS and JavaScript scripts will likely be served faster, either to your cache server if you have one or your end user if you do not, than by only the very latest of Apache releases (2.4.x) – and that translates to a measurable speed increase.

Are there immediate benefits other than speed? Indeed, there are many. More predictable behavior under heavy and rapidly scaling loads, lower memory and CPU requirements and higher concurrency capac-ity accompany improved static serving times. There’s a lot on offer in the simplest of configurations, even for the most modest of hosts. And with the upstream named server and load balancer directives, FastCGI and memcache caches and a slick, no-connections-dropped graceful upgrade option there’s much for the sysadmin and devops aficionados amongst you to sink your teeth into too.

Apache 2.4.x’s common Prefork-MPM/mod_php configuration can beat it on speed, but not by much, and that will always cost you both in memory and pro-cessor load. Come for the concurrency, stay for the simplified configuration and maintenance.

Should you try it right now? Yes, I think you should. It’s far from immature and there are both guided and automated installation options readily available, including the ones listed here.

If you’re still awake after the pudding and tur-key is served, or lost for what to try on after your socks, hats and holiday bathrobe there are many worse ways to waste the time – give it a try while waiting for the Bond movie. You will

likely find yourself both speeding up and simplify your serving of HTTP. That should make it a very Merry Christmas, won’t it Tiny Tim. Humbug!

Benjamin Greenaway has been a software developer for 18 years. After pioneering internet narrowcasting in the 90’s in collaboration with Virtual Futures he has led development on A/V installation projects for Pixar and Sony Entertainment and web applications for SMEs in Southern California before moving to the San Fran-

cisco Bay in 2010 and developing performance solutions for Dyn DNS and e-commerce APIs for Tzolkin TZO. He now lives in South London where he balances time writing and developing with the demands of an ever growing collection of retro computers.

References

[1] http://nginx.org

[2] https://gist.github.com/blgreenaway/6810654

[3] http://news.netcraft.com/archives/2013/07/02/ july-2013-web-server-survey.html

[4] http://w3techs.com/technologies/overview/web_server/all

[5] https://signup.netfl ix.com/openconnect/software

[6] http://nginx.com/news/choosing-nginx-growth-wordpresscom/

Listing 5: Nginx with Apache for PHPupstream apache { ip_hash; server 192.168.0.1:8080; server 192.168.0.2:8080; server 192.168.0.3:8080 weight=2; server 192.168.0.4:8080 backup; }

server { server_name www.example.com example.com; root /var/www/html/example.com/public_html; [..] location ~ \.php$ { # Proxy all requests to dynamic php content to Apache # proxy_pass 127.0.0.1:8080; use this line for one local Apache instance proxy_pass http://apache:8080; } location / { # All other static content options go here expires 30d; }}

Where can I find more help?

Visit http://nginx.org/en/docs/ for the complete directives list.

instagram.com

Pinterest.com

sourceforge.com

www.webandphp.com Web & PHP Magazine 12.13 | 8

Page 9: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialPhing

by Joey Rivera

Phing, which stands for “Phing is not GNU make”, is a command line build tool. You write an XML file with in-structions of what you need automated, call the script, and it’ll perform all those operations for you. It’s the same concept as Apache Ant which is used mainly for Java. Phing is very flexible, extendable and platform independent. It is also written in PHP.

Why do we need Phing? Efficiency, time, quality to mention a few – Phing lets you streamline processes so you don’t have to do them. Anything you or your team find yourselves doing manually daily, weekly, or monthly can be automated with a build tool such as Phing so you can focus on more important tasks.

An example of a common process is moving files from one server environment to another. Let’s say when you need to deploy your site to production, you

usually tar/zip your project folder, then ftp/sftp it up to the server. You wait patiently, and when it's uploaded, you log into the server and un-compress the file. That’s a few steps which don’t sound like much - but wouldn’t you rather make one call in the command line and let all that happen unattended, freeing up your time to be more productive?

There are various reasons why we use Phing at my job. First, people aren’t perfect and will make mistakes. You can ask a person to do the same task 100 times and chances are they’ll make a mistake at least once. On the other hand, you can ask a computer to do the same task 100 times and (assuming you asked it to do the right task) it will perform the task correctly 100 times.

The next reason was to reduce the amount of time spent by developers doing manual work. No one here likes to spend their time doing what we all see as be-ing “busy work” so to improve our quality of work-life we looked around for ways to separate ourselves from those tasks and let Phing take over. This lead us to a

let your computer do the hard work

Automate All the Phings! What if you could automate deploying your sites, restoring your database, and sending out reports? With Phing, you can do all this and more.

©iS

tock

pho

to.c

om/m

ecal

eha

www.webandphp.com Web & PHP Magazine 12.13 | 9

Page 10: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialPhing

happier team and because we were able to run these processes more often we also became more efficient.

Alright, got it – how do we get started?The easiest way to install Phing is through PEAR. The assumption here is that you already have PEAR setup on your machine. While in the command line you sim-ply want to discover the Phing channel and then install the Phing package. The commands are:

$ pear channel-discover pear.Phing.info$ pear install Phing/Phing

If you don’t have PEAR you can download the pack-aged file at [1]. After you unpack the files, make sure to add the Phing executable file to your system path so you can call it from anywhere. If you run into any is-

sues, make sure to reference the installation documen-tation [2] as it has lots of great and useful information.

You can also install Phing through composer. The only thing about that is normally I setup Phing as a system wide tool and not on a project by project basis which is how I see composer. If you did want to use composer to install Phing you can find more information at [3]. I tried this route and quickly found some dependencies were not in composer therefor not allowing me to in-stall them so I went back to PEAR for Phing.

Out of the box Phing has the capability of doing all kinds of things but depending on the use, you may need some extra dependencies. Table 1 has a few ex-ample dependencies you may want to consider after installing Phing (Table 1).

The two big ones for deployment use are SVN and/or Git depending on which you use. We still use SVN

so that’s the next thing I usually install. You can click on the links to get information on how to install those dependencies – most of which are installed through PEAR.

Don’t feel like you need to install every-thing upfront, you can just install Phing first and down the road when you find out you need something else, install that piece.

If everything is working correctly, you should be able to open up a command line window and type “Phing –v”. After hitting enter you should see something like “Phing 2.6.1” in the prompt. If you don’t, go through the install steps again to see if you missed anything.

Structure of a Phing build fileProject: At the heart of a Phing application is a build.xml file. This file contains all the in-structions you need Phing to perform. The file starts out with a project node. Inside the pro-ject you can have one or many targets (think

of them as methods you’d want to call). Each target can have one or many task – the actual individual processes to run. There are also a few other things like types, prop-erties, filters, mappers, and conditions but we’ll cover those later. Here is a sample build file taken from [4].

In this example you can see the project node at the top with a name of “FooBar” and a default property with the value “dist”. Name is simply the name you want to give this project and default, which is a re-quired property, is the target that will get called by de-fault when running Phing on this build.xml file if you do not specify the target.

The documentation is extremely helpful at explaining which properties are required and what they do [5].

Target: Targets are grouping of tasks used to achieve some result so I think of them as a method in a class. You can use as many tasks as you need in a target. Targets can also depend on other targets; in the example above, you’ll notice the “dist” target depends on the “build” target. This means, if you call the “dist” target directly and “build” has not yet ran, Phing will automatically run “build” first and then call “dist”.

Task: Within targets you usually have one or many tasks – the single pieces of executable code. These are the actions that you want to take place such as copy, delete, echo, foreach, ftp, etc. There are many tasks build-in to Phing and you can always create your own. For a list of the built-in tasks check the docs [6].

Property: The other piece you’ll be asking yourself about is variables? There are a couple ways to cre-ate variables. In Phing variables are called properties. These can be defined globally to all your targets or you can also define some specific to a target. The scope is determined by where you create your property. If you create the property in a target, then it’s usable in the target scope. You can declare properties inline, as an external file, or by asking the user for input. Below is an example showing all three:

Software Source

PHP 5.2+ http://www.php.net

PHPUnit 3.6.0+ http://www.phpunit.de

Xdebug 2.0.5+ http://www.xdebug.org

SimpleTest 1.0.1 beta+ http://simpletest.sourceforge.net

phpDocumentor http://pear.phpdoc.org

VersionControl_SVN http://pear.php.net/package/VersionControl_SVN

VersionControl_Git http://pear.php.net/package/VersionControl_Git

PHP_CodeSniffer http://pear.php.net/package/PHP_CodeSniffer

Archive_Tar http://pear.php.net/package/Archive_Tar

Services_Amazon_S3 http://pear.php.net/package/Services_Amazon_S3

HTTP_Request2 http://pear.php.net/package/HTTP_Request2

PHP Depend http://www.pdepend.org

PHP Mess Detector http://www.phpmd.org

PHP Copy/Paste Detector http://pear.phpunit.de

Table 1: A selection of Phing dependencies (source: http://www.Phing.info/docs/stable/hlhtml/index.html#ch.settingup)

www.webandphp.com Web & PHP Magazine 12.13 | 10

Page 11: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialPhing

<property name="name" value="Joey"><property file="property.file"><input propertyname="last.name">What is your last name?</input>

An external property file is a good way to store envi-ronment specific variables as well. For example, you can have a dev.properties, stage.properties, prod.properties each with the proper information. To create a properties file, simply create a new file and start add-ing key/value pairs in each line with an equal sign. You can name the file anything you like with or without an extension. I usually call my files “properties”. Ex:

name=Joeylast.name=Riveraversion=1.0.0

Keep in mind there are also various built-in properties in Phing such as:

• application.startdir: Current work directory. • env.*: Environment variables, extracted from $_SERVER.

• host.arch: System architecture, i.e. i586. Not avail-able on Windows machines.

• host.domain: DNS domain name, i.e. php.net. Not available on Windows machines.

• host.fstype: The type of the filesystem. Possible values are UNIX, WINNT and WIN32.

• host.name: Operating System hostname as re-turned by posix_uname(). Not available on Win-dows machines.

• host.os: Operating System description as set in PHP_OS variable (see PHP Manual).

You can find the entire list in the documentation [7]. The syntax to call a variable is a ${variablename}. For example:

<echo>${name}</echo><svninfo repositoryurl="${svn.repo.url}" /><equals arg1="${env}" arg2="development" />

Other Goodies: Phing also has types, filters, map-pers, and conditions. You can read the documentation to learn more about them but very high level:

• Types: more complex data types such as a FileSet to include or exclude types of files based on rules.

• Filters: These transform data such as Tidy, Strip-PhpComments.

• Mappers: Like filters but for files and directories like Flatten, RegExp, Glob

• Conditions: Allow you to create conditional state-ments such as if/else, comparisons, and can be nested.

ExamplesHello World : A quick basic hello world example would look like the following. Create a build.xml file and add the following to it:

Listing 1<?xml version="1.0" encoding="UTF-8"?>

<project name="FooBar" default="dist">

<!-- ============================================ --> <!-- Target: prepare --> <!-- ============================================ --> <target name="prepare"> <echo msg="Making directory ./build" /> <mkdir dir="./build" /> </target>

<!-- ============================================ --> <!-- Target: build --> <!-- ============================================ --> <target name="build" depends="prepare"> <echo msg="Copying files to build directory..." />

<echo msg="Copying ./about.php to ./build directory..." /> <copy file="./about.php" tofile="./build/about.php" />

<echo msg="Copying ./browsers.php to ./build directory..." /> <copy file="./browsers.php" tofile="./build/browsers.php" />

<echo msg="Copying ./contact.php to ./build directory..." /> <copy file="./contact.php" tofile="./build/contact.php" /> </target>

<!-- ============================================ --> <!-- (DEFAULT) Target: dist --> <!-- ============================================ --> <target name="dist" depends="build"> <echo msg="Creating archive..." />

<tar destfile="./build/build.tar.gz" compression="gzip"> <fileset dir="./build"> <include name="*" /> </fileset> </tar>

<echo msg="Files copied and compressed in build directory OK!" /> </target></project>

www.webandphp.com Web & PHP Magazine 12.13 | 11

Page 12: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialPhing

<?xml version="1.0" encoding="UTF-8"?><project name="HelloWorld" default="hello"> <target name="hello"> <echo>Hello ${name}</echo> </target></project>

Now, in the same folder where you placed the build.xml file, type Phing in the command line and enter. You should see “Hello ${name}”. But what we really want to do is to pass the name as an argument so it shows up. Let’s pass an argument to the script and try again. To do this in command line simply call “Phing –Dname=Joey”. This time you should see “Hello Joey”. What we did was tell Phing we want to pass a property by using –D, the property is “name” and the value is “Joey”.

If you didn’t want to pass the name as an argument, you could also declare the property in the build.xml by adding:

<?xml version="1.0" encoding="UTF-8"?><project name="HelloWorld" default="hello"> <property name="name" value="Joey"> <target name="hello"> <echo>Hello ${name}</echo> </target></project>

This declares a global property “name” with value “Joey”. If you try this example by running Phing without passing any arguments, you should see “Hello Joey”.

DeploymentsThis was our biggest area of improvement which was also our biggest headache before Phing. At first, we used to create a list of all the files that were modified for the iteration and manually copy/paste each file over

from one place to another. Quite often we’d forget one file and create problems for our customers. Then we went to another strategy where we’d export the entire application from SVN to production. This had its own problems since the entire application has thousands of files and it was time consuming and inefficient to copy over all these files just because a handful of files changed. Trying to solve this problem was why we started working with Phing.

Thanks to Phing we now follow a continuous deliv-ery approach to make sure when code is committed it ends up in the proper server within a couple minutes in an automated fashion. A continuous integration server might have made this easier but we use a Phing script and setup different cron jobs for the different environ-ments and applications we have. Our application on de-velopment gets checked often while our applications in the QA environment only get updated once a day.

We have a cron rule that calls our deployment script every 2 minutes passing it the “development” environ-ment and the name of the application to check. Based on the arguments passed, Phing checks the proper SVN repo, in this case trunk, to see if anything has changed since the last time it was checked. If something changed, it does a diff between the two revisions and deploys only the changes to the proper server location.

We deploy to production once a month. To deploy to production we call the deployment script, pass the application name and the “production” environment argument and the script will do a diff between the tag that is currently in production and the newest tag in the repo and deploys the changes. It usually takes only a few seconds to run and best of all, no files are EVER missed anymore!

The script is pretty large to put it all here but below are a few snippets of the build.xml for examples.

<svndiff repoa="${url.repo.from}" repob="${url.repo.to}" propertyname="svn.diff" />

This uses a custom task we created to compare two different svn repositories for changes. This is how we know if there are any changes and what they are. It’s ba-sically running “svninfo –xml –sumarize repoa repob”.

Listing 2 is an example of using a try/catch in case you know there are scenarios where things could break. In this case we run svn info on a repository that may or may not be there and create a property “check.repo” with the value of “broke” if it’s not found.

In this example you can see how we used an if/else to run a different command on linux vs windows. Most of the times we try to make our scripts platform independent but there are times where we need to do these types of checks.

<phingcall target="done"></phingcall>

The above line is an example of calling another target inside of a target.

In Listing 3 you can see how we used an if/else to run a different command on linux vs windows. Most of the times we try to make our scripts platform in-dependent but there are times where we need to do these types of checks.

Listing 2<trycatch property="tryworked"> <try> <svninfo repositoryurl="${url.repo.from}" element="entry" subelement="path" propertyname="check.repo" /> </try> <catch> <property name="check.repo" value="broke" override="true" /> </catch></trycatch>

www.webandphp.com Web & PHP Magazine 12.13 | 12

Page 13: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialPhing

DB Restore: Pre-Phing, we rarely used to restore da-tabases to match the data in production. This lead to multiple issues such as being unable to recreate prob-lems in our staging environment since the data didn’t match production. Or when finding an issue in our QA server, we didn’t know if this was caused by the code changes in the new iteration or a false-positive due to invalid configured data.

The reason we were restoring the database was be-cause it just took too long. Having many copies of each database (development, staging, QA, and testing) it would take a person all day to get the latest backup from production and one at a time create all databases. The next issue was after all database were created, make sure to remember to run specific scripts on spe-cific database servers to obfuscate the data and/or cre-ate account for our QA testers.

After months of trying to do the above more often always seeming to forget a step in the process we decided it was time to let Phing take over. Within a few days of planning, crafting and testing, we came up with our first functional Phing script to take over our

database restorations [8] (what we call it here). Over the last year it has been tweaked to make it more ro-bust and this is what the script does now:

• Prompts for ssh username • Cleans up environment (delete all tmp folder and create new one)

• Scp latest production db.dump file for the specific database

• Loops and sets all sites using the db’s to mainte-nance mode by adding a file to the site

• Restarts postgres to kick off any active connection to the db

• Loops and drops/recreates the databases – Restores staging from the production dump file – All others are templates of staging which in Post-gres executing much faster to create from tem-plate than to restore from scratch.

• Runs any database specific scripts • Turns all sites back on

Reporting: We have a third party vendor we use for handling loan applications for us. Every night we need to grab a report from their site to see who has applied for a loan and what the status of their applica-tion is. We had an individual log into the third party’s system every morning, click around the site to get to the reports, select the correct date range, generate and download the PDF and finally email it out to a few key people. This took enough of someone time where we felt it made sense to simply automate this with Phing.

We talked to the third party vendor and asked them to automate this report and sFTP it to us every night. We then created a Phing script that goes into our sFTP location, grabs the file, and emails it out to the few key people at a certain time of the day every day and then moves the file somewhere else. It took us but a

Listing 3<if> <equals arg1="${host.fstype}" arg2="UNIX" /> <then> <exec command="chmod -R 775 ${path.build}" /> <exec command="${copy.command} ${path.build}/. ${copy.to.path}/" checkreturn="true" /> </then> <else> <exec command='xcopy "${path.build}" "${copy.to.path}" /E /Y' checkreturn="true" /> </else></if>

couple hours to do and now we can free time from this person’s day to focus on something else.

The only tricky part about this was the email piece. For this, we used the Exec task in Phing to execute a shell command in our Linux environment. The task sim-ply called the mutt command line email client passing the proper parameters for the attachment file and re-cipients and that was it, everything worked like a charm.

ConclusionHope you enjoyed the article. We covered a few ben-efits of using Phing as well as a few examples on how we use Phing. I do recommend spending some time trying it out, I’m sure everyone could find a good use for it. If you have any questions or need help understanding the scripts above feel free to reach me at @joeyrivera.

In working with web technologies, Joey Rivera discovered a pas-sion for PHP. He has spent the last few years at Cengage Learn-ing [9] working on multiple projects and improving processes along the way. Not only does he enjoy development but he enjoys sharing as well through his blog [10] or presenting at the local Atlanta PHP

Usergroup [11]. When not in front of a computer you can find Joey at the gym, driving his car around the track, or hanging out with his wife and daughter.

References

[1] http://www.Phing.info/trac/wiki/Users/Download

[2] http://www.Phing.info/trac/wiki/Users/Installation

[3] https://packagist.org/packages/Phing/Phing

[4] http://www.Phing.info/docs/stable/hlhtml/index.html#d5e832

[5] http://www.Phing.info/docs/guide/stable/aph.html

[6] http://www.Phing.info/docs/guide/stable-legacy/

[7] http://www.Phing.info/docs/guide/stable-legacy/

[8] https://gist.github.com/webandphp/7548706

[9] http://www.cengage.com/

[10] http://www.joeyrivera.com/

[11] http://atlantaphp.org/

www.webandphp.com Web & PHP Magazine 12.13 | 13

Page 14: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialGit internals

by Ben Straub

The way we use most computer systems is through a metaphor. When you’re using a word processor, you don’t think about the byte-by-byte representa-tion of each character, or the control sequences that determine which words are italic and which are bold-face. The software abstracts that away, presenting a clean metaphor – inked characters on a sheet of paper. You write your words, decide on their font and style, and when you’re ready for your words to be on actual paper, you print.

When you’re adjusting the exposure of a photo, you don’t want think about the mathematical acrobatics necessary to change the R, G, and B bytes of every pixel just so, or the resampling algorithm needed to

adjust the size or rotation. The metaphor is something like a darkroom, and you adjust exposure and bright-ness, paint away red-eye, and erase the red wine stain on the wedding dress.

And with most version control systems, you don’t want to know how the data is stored and retrieved, or how the bytes are ordered during a network transmis-sion. You just want to write your code, and every once in a while save a snapshot to someplace safe, so the metaphor is defined on that level. The underlying data model is complicated, and you rarely (if ever) need to know what it is, because the UI is pretty effective at abstracting those details away.

With Git, the story is a little different. The metaphor it presents is a directed acyclic graph (DAG) of commit nodes, which is to say there is no metaphor – the data

Git internals for the rest of us

Git is simple (on the inside) Sometimes you actually do need to know how it works. GitHubber Ben Straub shows how learning Git’s internals helps explain its odder qualities.

Imag

e lic

ense

d b

y In

gram

Imag

e

www.webandphp.com Web & PHP Magazine 12.13 | 14

Page 15: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialGit internals

model actually is a DAG. If you try to re-use the meta-phor you learned from another system, you’re going to run into trouble.

The good news is that this data model is easy to un-derstand, and that figuring it out will make you better at using Git.

ObjectsJust about everything in a Git repository is either an object or a ref. Objects are how Git stores content. They’re stored in .git/objects, which is sometimes called the object database or ODB. Objects in the ODB are immutable; once you create one, you can’t change it. This is because Git uses an object’s SHA-1 hash to identify and find it, and if you were to change the con-tent of an object, its hash would change.

Objects come in four flavors: blobs, trees, commits, and tag annotations. Blobs are chunks of data that Git doesn’t interpret with any kind of structure, and it’s how Git stores your files. Objects are actually pretty easy to inspect (Listing 1).

Note that there’s no filename here. Git expects file renames to be fairly common, and if the filename were embedded with the content, you’d have to keep lots of copies of that object where the only difference is the filename.

You use git cat-file because Git has optimized the storage of objects. They’re gzip-compressed, and sometimes strings lots of them together into big pack-files, so if you look in .git/objects, you may not see anything you recognize as an object.

The second type of object is called a tree, and it’s how Git stores directory structures (Listing 2).

Only blobs are unstructured; Git expects a fairly spe-cific format for all the others. Each line of a tree ob-ject contains the file’s permission flags, what type it is (blobs are files, trees are subdirectories), the SHA-1 hash of the object, and a filename. So the tree type is responsible for the names and locations of things, and the blob type is responsible for their contents.

The third type of object is a commit. This is how Git represents a snapshot in history (Listing 3).

Listing 3: Inside a commit object $ git cat-file -t e365b1commit

$ git cat-file -p e365b1tree 58c796e7717809c2ca2217fc5424fdebdbc121b1parent d4291dfddfae86cfacec789133861098cebc67d4author Ben Straub <[email protected]> 1380719530 -0700committer Ben Straub <[email protected]> 1380719530 -0700

Fix typo, remove false statement

Listing 1: A blob object, one line truncated for space

# Print the object's type$ git cat-file -t d7abd6blob

# Print the first 5 lines of the object's content$ git cat-file -p d7abd6 | head -n 5<!DOCTYPE html><!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]--><!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]--><!--[if (gt IE 8)|(gt IEMobile 7)| [...] --><head>

Listing 2: Inside a tree object, SHA-1 hashes truncated for space

$ git cat-file -t 8f5b65tree

$ git cat-file -p 8f5b65 | head -n 5100644 blob 08b8e...493c0 after_footer.html100644 blob 11517...fce19 archive_post.html100644 blob 8ad5a...5b988 article.html040000 tree 5c216...c8810 asides040000 tree 52deb...e3dad custom

A commit has exactly one tree reference, which is the root directory of the commit. It has zero or more parents, which are references to other commits, and it has some metadata about the commit – who made it, when it was made, and what it’s about.

There’s just one more type of object, and it’s not used very often. It’s called a tag annotation, and it’s used to make a tag with comments.

I’ll say more about how these work later; for now, just note the object SHA that’s stored in there. That’s it! You can count the number of object types on one hand! See how simple this is?

RefsReferences (or refs) are nothing more than pointers to objects or other refs. They consist of two pieces of information: the name of the ref, and where it points. If a ref points to an object, it’s called a direct ref; if it points to another ref, it’s called a symbolic ref.

Most refs are direct. To confirm this, check the contents of anything under .git/refs/heads; they’re all

www.webandphp.com Web & PHP Magazine 12.13 | 15

Page 16: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialGit internals

plain-text files whose content is the SHA hash of the commit they point to:

$ cat .git/refs/heads/master2b67270f960563c55dd6c66495517bccc4f7fb17

Git also keeps around a few symbolic refs for specific purposes. The most commonly useful one is HEAD, which usually points to the branch you have checked out:

$ cat HEADref: refs/heads/master

Now that we know how refs work, let’s take another stab at that tag annotation object we saw earlier. Re-member that refs are basically just names for loca-tions; there’s no commentary associated with them, and you can change them at any time. Tag annotations solve both of these issues by putting ref-like informa-tion into the ODB (making it immutable, and allowing it to have more content), then making it findable by attaching a regular tag ref to it. The whole scheme looks like this:

tag (ref) --> tag_ann (odb) --> commit

Note that this opens up a whole new universe of pos-sibility: refs don’t have to point to commits. They can point to any kind of object, which means you could technically set up something like this (though it’s not clear why you’d want to):

branch --> tag --> tag_ann_a --> tag_ann_b --> blob

Three TreesTree-type objects in the ODB aren’t the only tree that Git likes to think about. During your day-to-day work, you’ll deal with three of them: HEAD, the index, and the work tree.

HEAD is the last commit that was made, and it’s the parent of your next commit. Technically, it’s a symbolic ref that points to the branch you’re on, which points to the last commit, but for the purposes of this section we’ll simplify a bit.

The index is a proposal for the next commit. When you do a checkout, Git copies the HEAD tree to the in-dex, and when you type git commit -m 'foo', it’s going to take what’s in the index and store it in the ODB as the new commit’s tree.

The work tree is a sandbox. You can safely create, update, and delete files at will in this area, knowing that Git has backups of everything. This is how Git makes your content available to the rest of the uni-verse of tools. There are a few commands whose job is mainly to deal with these three trees.

• git checkout – Copies content from HEAD into the index and work tree. It can also move HEAD first.

• git add – Copies content from the work tree to the index.

• git commit – Copies content from the index to HEAD.

Reset is Easier NowNow that we know a few things, some of Git’s seeming-ly-strange commands start to make sense. One example is git reset, one of the most hated and feared commands in all of Git. Reset generally performs three steps:

1. Move HEAD (and the branch it points to) to point to a different commit

2. Update the index to have the contents from HEAD3. Update the work tree to have the contents from

the index

And, through some oddly-named command-line op-tions, you can choose where it stops:

• git reset --soft will stop after step 1. HEAD and the checked-out branch are moved, but that’s all.

• git reset --mixed stops after step 2. The work tree isn’t touched at all, but HEAD and the index are. This is actually reset’s default; the --mixed argu-ment is optional.

• git reset --hard performs all three steps. After the first two, the work tree is overwritten with what’s in the index.

If you use reset with a path, Git actually skips the first step, since moving HEAD is a whole-repository opera-tion. The other two steps apply, though; --mixed will update the index with HEAD’s version of the file, and --hard also updates the working directory, effectively trashing any modifications you’ve made to the file since it was checked out.

The Everyday PatternLet’s take a look at a really common usage pattern with our new Git X-ray goggles on:

$ git checkout -b bug-2345 master

Listing 4: Inside a tag annotation object $ git cat-file -t 849a5e34atag

$ git cat-file -p 849a5e34aobject a65fedf39aefe402d3bb6e24df4d4f5fe4547750type committag hard_tagtagger Ben Straub <[email protected]> Fri May 11 11:47:58 2012 -0700

Tag on tag

www.webandphp.com Web & PHP Magazine 12.13 | 16

Page 17: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

www.webandphp.com

TutorialGit internals

Git creates a new branch called bug-2345, and points it at the same commit mas-ter points to. Then it moves HEAD to point to bug-2345, and updates the index and work tree to match HEAD.

You do some work, changing the files in the work tree, and now you’re ready to make a commit:

$ git add foo.txt$ git add -p bar.html

Git updates the index to match the contents of the work tree. You can even up-date it with only some of the changes from a file:

$ git commit -m 'Update foo and bar'

Git converts the index into a series of linked objects in the ODB. Blobs and trees whose contents match are re-used, and the files and directories that changed have new blobs and trees generated for them. Git then creates a new commit which points to the new root tree, and (since HEAD points to a branch) bug-2345 is moved to point to the new commit.

Go ForthWith most version-control systems, you’re encouraged to just get to know the UI layer, and the details will be safely abstracted away. Git is different; its basic data model is at a high enough level that it’s pretty easy to understand, and its UI layer is so thin, that you’ll find yourself learning the internals whether you want to or not – you’ll need to for everything except the bare minimum of usage. I hope this article has convinced you that there isn’t really that much to know, and that you earn many new abilities by going through this process. Your new understanding has made you powerful. Please use your new powers for good.

Ben Straub has always been a programmer, and loves making things work. He hacks on things at GitHub.

Buy now at: www.developerpress.com

Also available to buy on:

Make your business data driven.

$ 3.99

Page 18: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

FeatureVariables

by Julien Pauli

You all know $variables in PHP. Here we’ll show how PHP manages those variables as you write lines of code. We’ll see that our language is clever about memory man-agement of variables, and it tries to do its best to have a low memory footprint. However, a full understanding of the model is needed if you don’t want PHP to do weird things such as copying them or not freeing them.

What are PHP variables?PHP variables are represented internally by a container called zval, a C structure (Listing 1).

The value field represents the effective value (an in-teger, a string, and object ...). Then come two fields related to memory management: is_ref and refcount.

refcount is an integer indicating how many sym-bols point to this zval. A symbol is typically a PHP variable (like $a), but it can also be an internal C

variable, as zvals are also used internally by the en-gine.

is_ref is an integer representing a boolean value. It is by default set to zero, meaning that the zval has not yet been affected by a reference (&$a in PHP syntax). When set to 1, this means that the zval is a reference, and we will see together that whether or not a zval is a reference will deeply change the whole behavior of PHP when it comes to play with that zval.

Composite typesIn PHP, lots of things are zvals. For example, how many zvals can you count in this tiny script?

$a = 'foo';

Obviously yes: one. If we want to represent this with a picture, we’d do it like in Figure 1. What about this other little code?

$a = array('foo'=>'bar', 42);

There are 3 zvals: the string 'bar', the integer 42 and the array which encapsulates them. This is illustrated in Figure 2. Notice that the keys in the array, 'foo' and 1 here, are not zvals – only the values are.

Remember, in PHP, all types are zvals. Let’s have a look at objects:

class Foo { public $a = 42; protected $bar = 'default';}$obj = new Foo;

Here, we created 3 zvals as well: one for the object, in the $obj symbol, and one for each of its attributes ($a, and $bar).

References, memory management and more

how PhP manages variables

PHP 5.5 Release Manager Julien Pauli explains how PHP’s source code handles the language’s most essential – and, on the surface, simplest – feature.

©iS

tock

pho

to.c

om/d

anle

ap

www.webandphp.com Web & PHP Magazine 12.13 | 18

Page 19: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

FeatureVariables

You’ll notice that objects behave like arrays: from this point of view, yes they do. Objects, like arrays, are compound types, so they eat one zval for themselves, and one for each type they contain. That’s all simple!

How PHP manages variablesNow, let’s have a look at how PHP manages those zvals when you, as a programmer, use them in a day to day work.

First, let’s not talk about references. Look at how PHP is smart about not duplicating zval memory when you just copy a PHP variable’s content to another (Figure 3):

$a = 'foo';$b = $a;

The zval container is represented in yellow in the pic-tures. This is what consumes memory, and what you (or PHP) should absolutely prevent duplication of, and free up as soon as possible. In grey, we represent symbols: PHP variables. The grey zones don’t really consume memory. Actually they do, but so little that you really can basically forget about it. So, we can tell that the two scripts below consume the same amount of variable memory:

// Script 1$a = 'foo';$b = $a;

// Script 2$a = 'foo';

As you might have noticed, the refcount incremented when $b has just pointed to the zval. Refcount is the trick behind memory management in PHP variables: it shows how many symbols currently point to a zval container.

Copy on writeCopy On Write (abbreviated as “COW”) is a trick de-signed to save memory. It is used more generally in software engineering. It means that PHP will copy the memory (or allocate new memory region) when you write to a symbol, if this one was already pointing to a zval. For example:

$a = "foo";$b = $a;$a = 17;

Figure 4: The COW trick in action

Listing 1: Extract from zend.h in PHP source code.

struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount__gc; zend_uchar type; /* active type */ zend_uchar is_ref__gc;};

Figure 1: A representation of the zvals in a simple variable declaration

Figure 2: A representation of the zvals in a slightly more complex line

Figure 3: Copying a PHP variable’s content to another

www.webandphp.com Web & PHP Magazine 12.13 | 19

Page 20: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

FeatureVariables

Here’s another simple example, illustrat-ed in Figure 5:

$a = "foo";$b = $a;$c = $b;$b = "bar";unset($a);

Notice how PHP plays with the refcount value: it increments and decrements it as long as symbols point or leave a zval. Just enough memory is allocated.

You also can see that the unset() con-struct in PHP does not necessarily frees memory: unset() just decrements the ref-count by one. If, and only if, the refcount reaches zero, then PHP knows no more symbols point to the zval, and will free the refcount immediately and automatically.

Also, as long as we don’t play with ref-erences, is_ref remains at zero, and the behavior we just described applies: it’s logical and easy to understand.

If you want to go deeper and experi-ment by yourself, you can fetch both is_ref and refcount values from PHP land using the well-known Xdebug ex-tension, which provides a function for that: xdebug_debug_zval(). Let’s look at a last example involving arrays:

$a = array("foo"=>"bar", 1 => 42);$b = $a["foo"];$c = $b;$b = 18;unset($a['foo']);$a[1] = $b; Figure 5: How the “unset()” function affects refcounts Figure 6: Using “unset()” on array values

www.webandphp.com Web & PHP Magazine 12.13 | 20

Page 21: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

FeatureVariables

As you can see in Figure 6, the same behavior applies, and the same important rule: only when a zval’s ref-count drops to zero is the zval is freed, never before.

Functions (methods)First of all, functions and methods are the same. That being said, let’s see how they work when we talk about symbols and zvals.

What you have to remember, is that when a function is created, a scope is created with it. Aside from global variables which drill the scopes, variables created in-side a function are not reachable from the outside.

Also, keep in mind the parts that overlap scopes: function arguments and the return value have their ref-count incremented. Let’s have a look at an easy exam-ple (Listing 2 and Figure 7).

As you can see on the picture, the stack consumes the zvals, thus it increments their refcount. Remember that PHP allows you to reach the function parameters using func_get_arg() and family.

Remember also that it’s not just PHP variables that can point to a zval: The internal engine may use those zvals, thus incrementing as well their refcount.

When PHP leaves the function, it destroys its stack and parameters, just as would happen if you used un-set(). The refcount decrements, and the same rule as before is applied: if it reaches zero, PHP frees the cor-responding zval memory.

Once more, all of this is automatic and the program-mer doesn’t need to bother about allocating and free-ing memory.

ReferencesWe just talked about very classical PHP usage, thus this is how you should use PHP. Let’s talk about refer-ences now.

First of all, recall what a reference is: it is triggered when you use the & sign in PHP. A quick example:

$a = 'string';$b = &$a;$b = 1;

You know that at the end of the above script, $a and $b both contain the same value: the integer 1. What happened when you used a reference is that you tied both symbols $a and $b to the same zval. This is what you think, but wait – just using a single affectation (like $b = $a) does the same, right? We just demonstrated that in the last section ...

The answer is yes. In fact, writing $a = $b; or $a = &$b; does the same thing internally, for this single affectation line. What references really do is that they deeply change the behavior of PHP when Copy On Write comes to play (the line $b = 1;).

You can see this visually in Figure 8. First, you see that the “&” addition increases is_ref to 1, but the ref-count’s meaning is not changed: this is the number of symbols pointing to the zval.

However, the is_ref flag will change PHP behavior when you change a symbol (COW): PHP does not sep-arate the value any more, and instead directly changes it, so you have the illusion that $a and $b are tied to-gether. Simple and efficient, but take care: there are some tricks you should know about!

Let’s view another example showing that all the “du-plicate or not duplicate memory” behavior is changed with references:

$a = "string";$b = &$a;$c = $b;

Watch the third line carefully: $c = $b;.Here, PHP is forced to allocate a new memory bloc,

and to duplicate the string “string” into it, because of the preceding reference. If the reference had not have Figure 7: Using “unset()” on array values

Listing 2<?phpfunction foo($var){ $var = "bar"; return $var;}

$a = "foobaz";$b = foo($a);

www.webandphp.com Web & PHP Magazine 12.13 | 21

Page 22: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

FeatureVariables

been there, there will be one and just one zval contain-er, having a refcount of 3, like we are used to seeing.

But the reference forced PHP to duplicate it, be-cause now, when you change $c, you don’t expect to change $b do you? As $c is not a reference to $b. That’s right: notice how when using references, PHP copies memory in places you don’t necessar-ily expect. Here’s another example, in Listing 3 and Figure 10.

The behavior is as you would expect when using PHP and references, but watch how PHP has to du-plicate the bar string because of the reference. It does not allocate memory on the affectation $var = 'bar', because $var points to a reference. However, it does when the function returns, because this function returns by value, and we tell it to return what has been affected by reference (return $var;). It then duplicates the zval so that when you change what’s returned by the function, you don’t change what’s pointed to by $var and $a: this is just ex-pected PHP behavior isn’t it?

Remember one thing: references don’t (necessarily) save memory. Please, don’t think that any more. Haven’t we dispelled that myth?

With reference affectations in PHP, memory duplication is often delayed compared to value affectation. How-ever, sooner or later new memory zvals will be created – except for the case when you truly follow a reference from start to end, and never break it explicitly, or implicitly by using PHP in a way that it has to duplicate. Watch carefully this last trick about references, in Listing 5 and Figure 11. Figure 10: References and functions

Listing 3: A function with a reference as argument

<?phpfunction foo(&$var){ $var = "bar"; return $var;}

$a = "foobaz";$b = foo($a);

Figure 8: How references affect zvals

Figure 9: Unusual zval behaviour with references

www.webandphp.com Web & PHP Magazine 12.13 | 22

Page 23: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

FeatureVariables

Yes, this is very useless and silly code, but it’s worth commenting on. Can you, by yourself, guess when PHP will need to allocate a new zval and duplicate its content?

You saw that $var, in the foo() function, is passed by reference. Inside the foo() function, $var has an is_ref equals to 1. What happens when you call both strlen()and strtoupper()? Well, as those functions’ parameters are passed by value (see the manual entries), and $var is bound to a reference, PHP will duplicate the memo-ry at every call of such functions.

Yes, PHP has no way to know if strlen() will try to modify its argument. What would happen if it would? $var would be modified, as strlen() doesn’t take refer-ences as arguments. We don’t want that, so PHP is forced to duplicate the $var zval to make a new one with the exact same value. But in this case it would have to set is_ref to 0, before calling both strlen() and strtoupper(), and then free the zval just after the call! This is a waste which could impact performance: you got tricked by references.

If you hadn’t passed $var by reference to your func-tion foo(), no duplication at all would have happened (sure, you have this string concatenation to take care of, but, dear reader, it’s your job to find something better).

Don’t panic, duplicating the “barbaz” string is a matter of nanoseconds nowadays. But that’s not the case at all when arrays are involved, especially heavy, complex arrays with lots of slots inside. In such a case, the values inside the array are not du-plicated but their refcount is incremented. However, the array itself gets copied, which can be resource-consuming if it is very big (duplicating a one million slot array takes about 0.3 sec under 2013 desktop hardware running PHP 5.5).

Memory leaks and garbage collectionFirst of all, let’s define quickly what the process of garbage collection is. Garbage collection is a “mech-anism which tracks objects’ usage and frees their memory support as long as they are not reachable in their current scope, or still being used by the pro-grammer”. (This is generic definition of my own.) Ap-plied to PHP, we have already talked about this very concept in past chapters: it is the refcount mecha-nism applied to the zvals, which indeed frees the zval container as it reaches zero.

That’s right – PHP has been providing a garbage col-lection mechanism for its variables since the very be-ginning. What you might have heard about, is “Zend Garbage Collector” or “Zend GC”, which appeared with PHP 5.3. What’s that about? Well, it’s a bit confus-ing as many people thought before PHP 5.3, PHP just did not free memory automatically, which is wrong! In fact, the Zend Garbage Collector takes care of circular references for you.

This is well explained under a dedicated php.net page [1] with cool pictures like the ones in this article.

Listing 6/* create the two entities, objects here */$a = new ObjA;$b = new ObjB;

/* create the circular reference between them */$a->b = $b;$b->a = $a;

/* Decrement refcount of both entities */unset($a, $b);

/* Here, there is no way to fetch the two zvals from PHP land,but as they own each other, they are still present in memory andPHP will never free them, before PHP 5.3*/

Figure 11: Circular references

Listing 5function foo(&$var){ if (strlen($var) > 3) { return $var; } else { $var .= '_uppercased';

return strtoupper($var); }}

$value = 'barbaz';echo foo($value);

www.webandphp.com Web & PHP Magazine 12.13 | 23

Page 24: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

FeatureVariables

Circular references appears within compound types, like objects or arrays. When two composite types con-tain reference to each other, or when one composite type contains a reference to itself, this is called a circu-lar reference. This is bad because it’s hard to compute when to free them which one to begin with.

Before PHP 5.3, PHP had no way to track circular ref-erences, and as you free your variables (using unset() to drop their refcount to zero, for example), PHP would then leak the entities as they still own each other. An example is in Listing 6 and Figure 11.

Starting with PHP5.3, a complex system has been designed to track those particular cases, which tend to happen more and more frequently as users manage more and more objects in their code. With objects, it is easy to have two of them be in circular reference, as you don’t obviously notice it.

PHP now automatically tracks circular references, and frees them from time to time. Should you know you have freeable circular references, and want to force PHP to free them now, you would then use the gc_collect_cycles(); function which has been designed for that. Let’s try it with our above example (Listing 7).

Circular references eat memory. This is not severe in a web environment, as PHP should run as fast as pos-sible, and anyway it automatically cleans all resources at the end of the request, including obviously circular references PHP variables.

The problem would show up when running long liv-ing CLI scripts, aka PHPUnit tests for example. With Zend GC, your memory curve should stay relatively straight.

ConclusionWe tried to show in this article what PHP does under-neath the surface when you use its simplest and most essential feature: variables.

PHP represents variables internally using containers called zvals, and it keeps track of how many symbols (PHP variables) point to each zval, so that it can free the zval memory when the number of symbols reaches zero.

We also showed how efficient PHP is when it comes to copy variables in a PHP script. PHP won’t copy the zval associated, in a huge majority of cases. It will only duplicate the zval when it is forced to, and that’s not easy to track at first sight.

Using PHP variable references heavily can change the zval copy behavior in a way which is not necessarily easy to track. Usually, you should not use references, as about 97 % of the behaviors you want to implement with PHP can be done with no references at all.

We have not shown all of the tricky features PHP relies on, but you should now have a good starting point of understanding how PHP behaves when we talk about variables and references.

Don’t forget that PHP is written in C, and open source. Sure, its source code is not very easy to deal with, but with a good understanding of C and a little effort, you can start understanding lots of things when reading the source.

If you don’t want to take this path, then don’t as-sume anything from PHP, especially not that using ref-erences everywhere will save memory: in most cases, this is wrong.

Listing 7/* create the two entities */$a = new ObjA;$b = new ObjB;

/* create the circular reference between them */$a->b = $b;$b->a = $a;

/* Decrement refcount of both entities */unset($a, $b);

/* Force PHP to clean the circular reference */$cleaned = gc_collect_cycles();

/* Display how many zvals have been freed bythe circular reference garbage collector */

echo $cleaned; /* 2 */

Further reading

PHP duplicating memory with references: http://lxr.php.net/xref/PHP_5_5/Zend/zend_execute.c#909

PHP circular references garbage collector: http://www.php.net/gc

Xdebug to track variables internals: http://www.xdebug.org

Valgrind/massif, low level memory profiler: http://valgrind.org/docs/manual/ms-manual.html

Wikipedia page about garbage collector: http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)

References

[1] http://www.php.net/gc

Julien Pauli is a web and system architect. He’s been using PHP for a decade together with frameworks such as Symfony. He is now a PHP contributor and PHP 5.5 release manager, and tries to make PHP better and more efficient.

www.webandphp.com Web & PHP Magazine 12.13 | 24

Page 25: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialStructuring CSS

by Ragnar Kurm

This is the second and final part of Ragnar Kurm’s guide to Many Layouts Side-By-Side (MLSBS), a meth-odology for dealing with massive CSS layouts. See the November 2013 issue for part one [1], which cov-ers “smarter CSS” using a preprocessor and perfor-mance-aware selectors.

StructuringIf CSS files grow too large, they can become convo-luted, hard to manage and difficult to get an overview

of. However, many smaller files have disadvantages of their own. Therefore, there are two processes to reshaping CSS:

1. Splitting it up into managable chunks2. Joining it back together for distribution

Splitting it upWhy would we need to split up a CSS file? In short, it makes it structured and manageable, and it becomes easy to gain an overview of your CSS. Every time you

Replace yourself with a small Makefile

Compile Your style: structuring and automating Css Oversized CSS files? Split your monolithic styles into easily-managed chunks – and then put them back together using SASS and Make.

©iStockphoto.com/PeterAustin

www.webandphp.com Web & PHP Magazine 12.13 | 25

Page 26: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialStructuring CSS

add some HTML construction (logo, title, main menu, comments list, breadcrumbs, etc) you should create a corresponding SASS file specific to that element.

Suppose we chose to get rid of a secondary menu in a site we were building. In this case, we would also remove the relevant style – by deleting a file. If you change some of these elements, you know exactly where to find corresponding style.

Usually, if a single style file gets big, it is a sign of convolution. It’s not possible to have too many files – in fact, more is generally better. Don’t worry about the browser having load each one separately: we will deal with that issue a bit later.

For a larger project I am working on, my style-pieces are mostly less than 1kb, though few of them are up to 5kb, and each of these files contain CSS for four different layouts (one general and three width-specific layouts).

As I use Drupal extensively, I mostly split CSS in a fairly Drupal-specific way. But you can set it up accord-ing to your framework or environment and it would not be dramatically different.

There are many professionals who have shared their way of structuring style. The best source is probably SMACSS [2]. There are other ways of structuring CSS, but I have yet to read into them in detail. For now, I am concentrating on MLSBS. My main categories are:

• Definitions file (collection of reusable things, described below)

• Elements (small structural elements) • Structural (major structure of the page) • Fields (both when being edited and displayed. For example, a form may have a field ‘Product title’, and upon saving a whole product is displayed including the field ‘Product title’)

• Views (listings, tables, grids) • Nodes (pages of certain types, an article, a product, an event, a person)

• Pages (typeless pages like frontpage, 404 page, contact page)

Definitions file: This is file where I collect reusable info and it is included by all .sass files. More specifi-cally it contains:

Paths providing a base for external URLs, for example '$path_img: /style/images/'.Automatic image style dimensions to match Drupal Configuration > Image Styles. For example: $image_style_thumbnail_width: 100pxImage dimensions, which are are automatically extract-ed from actual images (more on this later).General dimensions such as margins, certain element widths, different layout siz-es, etc.Colors to maintain a consist-ent color scheme.CSS snippets stored in reus-able SASS mixins, for exam-ple: rounded().

Overview of other pieces: The kind of structure I use is shown in diagrammatic form in Figure 1. Note that in many categories list is given from more general to more specific.

Joining the piecesIt is impractical to feed all these style pieces individu-

ally. Too many requests will slow down page render-ing. Therefore it is more convenient to join them either before or after compiling. It is also worth considering if and how to group them. There are many methods to do this, but it needs at least a bit of automation – in-cluding pieces together in .sass file or using shell script for concatenation, for example. More convenient way is to use Make/Makefile.

It is important that whichever way you find conveni-ent for you the compilation and assembly should be in

Figure 1: Example structure of a big SASS project

www.webandphp.com Web & PHP Magazine 12.13 | 26

Page 27: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialStructuring CSS

subsecond range, for example 300ms, because this is a frequently-repeated procedure. 1. Include all pieces together (perhaps in a file named 'combined.sass'):

@import "includes/defs.sass"@import "elements/admin-menu.sass"@import "elements/ads.sass"@import "elements/feedback.sass"...

2. Compile the file:

sass --watch combined.scss:combined.css

By adding --watch, If you change any of included files, the target will be automatically recompiled.

Combining style files on the flySome frameworks offer the option to use specific CSS pieces only if they are needed – combined, minimized, compressed and delivered to the client. This might sound like a good idea, but think how many possibilities there are. It is a mathematical permutation of a number of style files – and this number could be big. If you have hundreds or thousands of these combined-minimized-compressed files cached on your server – does it really pay off?

Though I have not carried out any evaluation or benchmarks, I have not chosen to add more complex-ity to my system. I usually deliver only two files to the browser – one generic and one layout-specific (both minimized and compressed) – so that they can be cached easily. It will be explained further in the end of “Media Queries” chapter.

Automated imagework: ImageMagickImageMagick [3] is a free software suite to create, edit, compose, or convert bitmap images. It’s a Swiss army knife for command line image manipulation, and

can be used to automate mechanical operations that you might otherwise carry out in, say, GIMP.

There are two major ways in which we will use Im-ageMagick: to modify existing graphics (or generate it) and secondly to extract file information and feed it back to style files.

Image modificationSuppose your designer delivers you 2 000 x 1 500 px logo which will be used on different pages, in different sizes, and – to complicate things even further – differ-ent layouts (screen sizes) require different versions. So you are going to end up number of different sizes multiplied by a number of layouts. Imagine if the logo needs to be changed – the image will need to be con-verted again many times. This time-consuming pro-cess leads to resistance to change of these graphical elements.

Fortunately, ImageMagick has a solution for these issues, allowing us to work with ease on graphics. One of the utilities that ImageMagick provides is: convert – convert between image formats as well as resize an image, blur, crop, despeckle, dither, draw on, flip, join, re-sample, and much more:

$ convert logo.png -geometry 200x150 logo.jpg

This takes the logo in any format and scales it down to 200 x 150, keeping the aspect ratio. It could not be

any simpler. Another great utility that comes with Im-ageMagick is: identify – describe the format and char-acteristics of one or more image files:

$ identify logo.jpglogo.jpg JPEG 114x150 114x150+0+0 8-bit PseudoClass 256c 832B 0.000u 0:00.000

So we can see that the logo was converted to 114 x 150 px. It is very handy to look up image dimensions with identify rather than execute a full graphical editor.

To automate things further – from time to time there is a need to know exact size of an image inside pre-processor style file, i. e. In a .sass file. For example when you need to fit elements well together. With identify and a small shell script (Listing 1), we can do that painlessly.

This is a simplified version of the shell script [4] needed to extract image dimensions and output them as variables in .sass format:

$ dimensions.sh logo.jpg$WIDTH_LOGO: 114px$HEIGHT_LOGO: 150px

Ideally you would like to get dimensions for all your static theme images and import them into the style files. It frees you from editing style while editing im-ages, because you know that all things will match to-gether automatically without breaking anything.

For simplicity, Figure 2 is a workflow for one image. Similarly one can construct images.sass which con-tains info for all images.

UsageThe following example is given for one file, but can generalized for all image files:

$ dimensions.sh logo.jpg > logo.sass

Listing 1#!/bin/shimg="$1"label='echo "$img" | tr 'a-z-' 'A-Z_' | sed 's/\.[A-Z]*$//''identify -format "\$WIDTH_$label: %wpx" "$img"identify -format "\$HEIGHT_$label: %hpx" "$img"

www.webandphp.com Web & PHP Magazine 12.13 | 27

Page 28: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialStructuring CSS

In the style file:

@import "logo.sass"#logo width: $WIDTH_LOGO height: $HEIGHT_LOGO

All of this image conversion and dimension thing starts to make more sense when it is automatic.

Image creationImageMagick tools are not limited to conversion or identification. It has virtually unlimited options to deal with graphics. For example, you can automatically wa-termark images, generate pretty graphical texts with your own font, generate tile images for background,

or even generate dynamically pretty menu buttons. (In the latter case, you need to to your own caching if the button text remains the same.)

And these operations are often one-liners. Fig-ures  3–6 and Listing 2 demonstrate what can be achieved from ImageMagick command line tools. Many of these are one-liners, although some take cou-ple of lines.

Futher info about image generation can be found on the official ImageMagick site [5].

Media QueriesFor the sake of completion, I’ll add a few words about media queries. In order to make your page responsive and able to show multiple layouts (one at a time, of course) depending on the screen width, you will need

to deploy media queries, which instruct brows-ers to use certain styles only when conditions are met.

As this is a core part of responsive design, there is plenty of information al-ready available. Here’s a few links to start you off:

• Media Queries: W3C Recommendation [6] • CSS Tricks [7] • 7 Habits of Highly

Effective Media Queries [8]

What I would like to add from my experience with responsive design is that I used two files. Figure 2: SASS workflow for images

Figure 3: ImageMagick example

Figure 4: ImageMagick example

Figure 5: ImageMagick example

Figure 6: ImageMagick example

www.webandphp.com Web & PHP Magazine 12.13 | 28

Page 29: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialStructuring CSS

One is a general file, dimension-independent and containing things like colors etc. In addition to this file, I used just one style per layout. It so happens that layout-specific files tend to be almost identical except for dimension values.

Usually, if I have three layouts (narrow, normal, wide) then I would have four CSS files in total (one is a ‘gen-

eral’ layout). This is actually a bit simplified, because frameworks (Drupal, etc) tend to add their own files too.

I constructed media queries in a way that the general .css file is always loaded, but only one layout-specific file is loaded. I did not find much use stacking them and burdening browser rendering, because they would almost completely overwrite each other.

Make and MakefileBefore we get to the final step, it’s worth introducing Make, a package and command line utility. It is mainly used to compile program code, but it is not specific to that. So it can be used very creatively.

Essentially one executes make, which then reads Makefile in the current directory and executes relevant rules. Makefile contains rules* which specify targets (files) and sources (also files) that it depends on. If a dependency file has been updated then the target is remade. Though it allows to specify simple dependen-cies like target and its direct dependencies, it actually works based on arbitrary size of dependency trees. It will go through only affected branch and will redo nec-essary operations called recipes. Recipes are always indented by one tab. Here’s a very simple example Makefile:

typesetting.css: typesetting.sass sass typesetting.sass typesetting.css

Listing 2# Figure 3$ convert \ bg.jpg \ -crop 600x200+0+0 \ -fill '#0008' \ -draw 'rectangle 10,130,400,190' \ -fill white \ -pointsize 40 \ -annotate +30+175 'The Image'

# Figure 4$ convert \ -size 600x200 xc:white \ -font MeriendaOne-Regular.ttf \ -pointsize 80 \ -fill black \ -annotate +10+135 'Dark Shadows' \ -channel RGBA \ -blur 0x5 \ -ordered-dither h8x8a,3 # Figure 5 $ convert \ bg.jpg \ -crop '550x100+0+0' \ tmp.png$ convert \

-size 600x300 xc:lightblue \ -background lightblue \ -fill white \ -stroke grey60 \ -draw "rectangle 0,0 560,110" tmp.png -geometry +5+5 -composite -rotate -5 \ -draw "rectangle 0,0 560,110" tmp.png -geometry +5+5 -composite -rotate -5 \ -draw "rectangle 0,0 560,110" tmp.png -geometry +5+5 -composite -rotate +5 \ -trim \ +repage \ -flatten \ -gravity center \ -background lightblue \ -extent 600x300$ rm -f tmp.png

# Figure 6$ convert \ -size 600x200 xc:white \ -font MeriendaOne-Regular.ttf \ -pointsize 80 \ -fill green \ -stroke green -strokewidth 25 -annotate +35+130 'Heavy Stroke' \ -stroke white -strokewidth 20 -annotate +35+130 'Heavy Stroke' \ -stroke green -strokewidth 15 -annotate +35+130 'Heavy Stroke' \ -stroke white -strokewidth 10 -annotate +35+130 'Heavy Stroke' \ -stroke green -strokewidth 5 -annotate +35+130 'Heavy Stroke' \ -stroke none -annotate +35+130 'Heavy Stroke'

Listing 3@import url("general.css");

@media (max-width: 800px) { @import url("narrow.css");}

@media (min-width: 1000px) { @import url("normal.css");}

@media (min-width: 1200px) { @import url("wide.css");}

www.webandphp.com Web & PHP Magazine 12.13 | 29

Page 30: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialStructuring CSS

By executing make from the command line, it com-piles typesetting.sass into typesetting.css – only if typesetting.sass is newer than typesetting.css.

Automatic variablesRules can be generalized by using automatic variables and this gives great power to Make:

• $@: The file name of the target of the rule. $@ is the name of whichever target caused the rule’s recipe to be run.

• $<: The name of the first prerequisite. • $^: The names of all the prerequisites, with spaces between them.

• $*: The stem with which an implicit rule matches. In a static pattern rule, the stem is part of the file name that matched the % in the target pattern.

Makefile examplesHere’s another simple example with SASS:

typesetting.css: typesetting.sass sass $< $@

This produces the same result as our first Makefile, but is more general. $< will be replaced by typesetting.sass and $@ will be replaced by typesetting.css. List-ing 4 shows another example.

This is a more sophisticated real-life example:

1. It defines variable IMAGES as list of images (logo and title) and adds the extension .jpg to them.

2. If make is executed the first rule all will be run. This is “virtual” target. File with the same name (all) will never be built, but it serves purpose of having dependencies, IMAGES which are created or recre-ated if necessary.

3. There is a rule to convert arbitrary .png files to .jpg. It will echo “Converting filename” to terminal, but not the actual command itself, and then silently converts .png to .jpg assuming ImageMagick is installed. Only these images will be (re)created which are listed as dependencies or sources for target all and have source (the PNG file) newer than the target (the JPEG), if the target already exists.

4. Any image in IMAGES depends on the Makefile. So when the developer adjusts something in Make-file then all specified images will be recreated upon executing make from the command line.

In context of working with SASS, CSS and images the Make does all the housekeeping. It converts all the images, compiles .sass files and assembles them as CSS. With ease you can add your own logic to it. In a sense it creates second meta-layer to your CSS (the first meta-layer being SASS).

If you have good editor then you can even directly ex-ecute make from the editor to save a few keystrokes. For further reading please see the introduction in GNU Make documentation [9].

Multiple Layouts Side By Side (MLSBS)As stated earlier, the goal was to be able edit style side-by-side. Let’s see how all these steps fit together in order to accomplish this. SASS and Make/Makefile are central to this.

First we use SASS and its plugin to work on single style pieces which contain style for one element, but have multiple layouts within, side-by-side. SASS al-lows us to conditionally extract style for the layouts one at a time. We use the SASS plugin to tell SASS which part we need. Listing  5 is the most simple example.

Remember to use the additional command line argu-ment to activate the plugin:

$ LAYOUT=narrow sass --require env.rb element.sass element.narrow.css$ LAYOUT=narrow sass --require env.rb element.sass element.wide.css

So we run SASS for each layout we have and extract-compile respective parts. As a result we save these with different names.

Now you may start to worry about having way too many CSS pieces. After all, the total will be the num-ber of layouts (mobile, narrow, normal, wide, etc) mul-tiplied by number of styled elements (logo, title, menu, etc). Maybe it is a big number, but it will be handled automatically.

Listing 5$LAYOUT: env(LAYOUT)

@if $LAYOUT == "narrow" #logo background-image: url(logo-narrow.png)

@if $LAYOUT == "wide" #logo background-image: url(logo-wide.png)

Listing 4IMAGES = $(addsuffix .jpg, \ logo \ title \)all: $(IMAGES)%.jpg: %.png @echo "Converting $*" @convert $< $@$(IMAGES): Makefile

www.webandphp.com Web & PHP Magazine 12.13 | 30

Page 31: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

TutorialStructuring CSS

The next step in the process is to join all CSS pieces belonging to the same layout. For example we concat-enate all ‘wide’ layout CSS pieces. In the end of this step we will have only few files which equals to num-ber of layouts we have (Figure 7).

Now we are able to do many tricks with style pre-processor SASS and commandline imagework suite ImageMagick. Using these tools means executing additional commands to get desired result, repeat-edly. Probably first idea would be to use a script which would compile preprocessor files and derive neces-sary images etc. But the problem here is that the shell script would compile files which would not need to be compiled and prepare images that are already pre-pared resulting to slow and inefficient workflow.

This is where Make/Makefile, as covered above, come in. You can see an example Makefile for MLSBS [10] in my boilerplate on GitHub [11].

Putting it all togetherSo, to return to our summary of MLSBS from part 1, we’ve now covered every aspect of the workflow:

• Style Preprocessor: SASS • SASS plugin: Awareness of Environment • Style and Evaluation: Matching and Specificity • Structuring: Splitting and Joining • Automated imagework with ImageMagick • Media Queries • Automation with Make/Makefile

Of course, there’s no need to adopt all of these at once. Individually they are still very useful and can save time: for example splitting files into manageable chunks with SASS; checking an image’s dimensions on the command line using ImageMagick; or just using more efficient selectors.

Ragnar Kurm began programming in his teens and later studied In-formatics at Tallinn Technical University. He currently runs his own company, and before that worked for ten years at an ISP. Ragnar has extensive programming experience in all major languages (ca 20–30) and continues to learn. In recent years, he has spent the ma-

jority of his time building webpages, but he loves backend programming most.

Figure 7: Layout schematics

Together, though, I find them to be an immensely powerful workflow that takes the pain out of writing CSS. I hope it helps you too!

References

[1] http://webandphp.com/compile-your-style-part1-smarter-css

[2] http://smacss.com

[3] http://www.imagemagick.org/script/index.php

[4] https://github.com/ragnarkurm/compile-your-style/blob/master/img/wh

[5] http://www.imagemagick.org/Usage/

[6] http://www.w3.org/TR/css3-mediaqueries/

[7] http://css-tricks.com/resolution-specific-stylesheets/

[8] http://bradfrostweb.com/blog/post/7-habits-of-highly-effective-media-queries/

[9] http://www.gnu.org/software/make/manual/make.html#Introduction

[10] https://github.com/ragnarkurm/compile-your-style/blob/master/css/Makefile

[11] https://github.com/ragnarkurm/compile-your-style/

www.webandphp.com Web & PHP Magazine 12.13 | 31

Page 32: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of
Page 33: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

ColumnTesting

Software is never perfect. Failures of software make the news and damage the reputation of companies and organizations. A rather spectacular example of such a failure lead to the loss of the Mars Climate Orbiter. The mission of this robotic space probe, which roughly cost 655 million USD [1], was the study of the atmos-phere and the climate of our planetary neighbour. On September 23, 1999 the probe approached Mars at a wrong angle and disintegrated. The cause for the loss of the Mars Climate Orbiter was published on Septem-ber 30, 1999: “The peer review preliminary findings in-dicate that one team used English units (e. g., inches, feet and pounds) while the other used metric units for a key spacecraft operation. This information was criti-cal to the maneuvers required to place the spacecraft in the proper Mars orbit.” [2].

We can assume that the two teams mentioned in the report above tested their individual components of the software (in isolation from the other component) rigorously with unit tests. Considering the outcome, however, we have to assume not a single integration test was performed to ensure that the two compo-nents work correctly when used together. It appears that these two components collaborated for the first time in the orbit of Mars. This is not an integration test but rather a “disintegration test”.

Dr. Edward Weiler, NASA’s Associate Administrator for Space Science, made an interesting observation in the peer review preliminary findings: “The problem here was not the error, it was the failure of NASA’s systems engineering, and the checks and balances in our processes to detect the error. That’s why we lost

the spacecraft.” The cause for the loss of the Mars Climate Orbiter was not just a technical error in the navigation unit’s source code but rather rooted in com-munication and process problems. Had the two teams communicated with each other, they would have been aware that one team used metric units while the other team used English units. And had the process called for integration testing of the two components in ad-dition to testing them isolated from each other, the mistake would have been exposed as well.

One of the most important tasks in software test-ing is to find the smallest scope in which a test case can be implemented. The smaller the scope in which a test is run, the faster it can be executed and the more precise its result. Unit Tests test one unit of code in isolation from all collaborators. Integration Tests verify the interaction of two or more collaborators in isola-tion from the rest of the system. Edge-to-Edge Tests exercise the software as end-to-end as possible in a single process (and without using a web browser or a web server). End-to-End Tests, or System Tests, look at the whole system and in the case of a web applica-tion send a HTTP request from a web browser to a web server running the software to inspect the HTTP response that is sent back.

Bio

Sebastian Bergmann is a mastermind of PHP development and PHP quality assurance. He has contributed instrumentally to transform-ing PHP into a reliable platform for large-scale, mission-critical projects. Companies and PHP developers around the world benefit from the tools that he has written.

there’s more to software quality than a few unit tests and system tests. All levels of your software should be covered, writes sebastian Bergmann.

end-to-end tests: not the be-all and end-all

by Sebastian Bergmann

www.webandphp.com Web & PHP Magazine 12.13 | 33

Page 34: nginx: A beginner’s guide by Ragnar Kurm - · PDF fileby Ragnar Kurm end-to-end tests by Sebastian Bergmann open source spotlight: PhP-CPP nginx: A beginner’s guide ... host of

ColumnTesting

www.webandphp.com

In a previous installment of this column I wrote that “[a]cceptance tests tell you that you are building the right product by ensuring that the software does what it is supposed to be doing. Unit Tests tell that you are building the product right by ensuring that the code works correctly.”

It is easy – and seductive – to implement accept-ance tests using tools that exercise the software in an end-to-end fashion. Especially teams that are new to testing and/or have to deal with legacy software that is not testable on the unit-level often walk into the trap of testing their application’s core domain logic through the frontend. This indirect way of test-ing is slow and fragile. It is slow because the whole application is executed in a large scope to test an aspect of the application that should be tested in a small scope. It is fragile because the tests for the do-main logic have to be adapted when the frontend’s HTML templates change. To make it worse, these tests are performed in a scope that is so large that a failing test only tell the developer that something does not work without providing information point-ing to the root cause. While there is a place for these kinds of tests in the test mix for an application, for instance to test cross-browser compatibility, a team would be ill-advised to solely rely on end-to-end tests as these are cumbersome to write and maintain, prone to errors, and slow to execute.

Acceptance tests should instead be implemented using edge-to-edge tests. These are easier to write and faster to execute than old-fashioned end-to-end tests. More importantly, they require minimal main-tenance and deliver highly reliable results. When the architecture of the software allows for both unit tests and edge-to-edge tests then it will also be easy to adopt the practices of Experiment-Driven Develop-ment and Testing in Production that Eric Ries wrote about in his book “The Lean Startup”. The promise

of being able to develop both the business model as well as the software that implements it should be reason enough for enterprises to invest in a modern, highly decoupled software architecture. And when the members of the software development team communicate well, both among themselves and with the other stakeholders, then there is not much that can really impede the success of the project.

References

[1] http://mars.jpl.nasa.gov/msp98/orbiter/fact.html

[2] http://mars.jpl.nasa.gov/msp98/news/mco990930.html

About

PublisherSoftware & Support Media Ltd

Editorial Office Address86 Great Suffolk StLondon SE1 0BEwww.sandsmedia.com

Editor: Elliot Bentley ([email protected])Authors: Sebastian Bergmann, Benjamin Greenaway, Ragnar Kurm, Julien Pauli, Joey Rivera, Ben Straub Creative Director: Jens MainzLayout: Tobias Dorn, Flora Feher, Andrea Horn, Petra Rüth

Sales:Ellen May+44 207 199 [email protected]

Contents copyright © 2013 Software & Support Media Ltd. All rights reserved. No part of this publication may be repro-duced, redistributed, posted online or reused by any means in any form, including print, electronic, photocopy, internal network, Web or any other method, without prior written permission of Software & Support Media Ltd.

The views expressed are solely those of the authors and do not reflect the views or position of their firm, any of their clients, or Publisher. Regarding the information, Publisher dis-claims all warranties as to the accuracy, completeness, or ade-quacy of any information, and is not responsible for any errors, omissions, in adequacies, misuse, or the consequences of us-ing any information provided by Pub lisher. Rights of disposal of rewarded articles belong to Publisher. All mentioned trademarks and service marks are copyrighted by their respective owners.

www.webandphp.com Web & PHP Magazine 12.13 | 34