"Curiosity is the very basis of education and if you tell me that curiosity killed the cat, I say only the cat died nobly." - Arnold Edinborough

Edit: Part 2 is now available.

This is the first entry in a short series I’ll do on caching in PHP. During this series I’ll explore some of the options that exist when caching PHP code and provide a unique (I think) solution that I feel works well to gain high performance without sacrificing real-time data.

Caching in PHP is usually done on a per-object basis, people will cache a query or some CPU intensive calculations to prevent redoing these CPU intensive operations. This can get you a long way. I have an old site which uses this method and gets 105 requests per second on really old hardware.

An alternative that is used, for example in the Super Cache WordPress plug-in, is to cache the full-page data. This essentially mean that you create a page only once. This introduces the problem of stale data which people usually solve by checking whether data is still valid or by using a TTL caching mechanism and accepting stale data.

The method I propose is a spin on full-page caching. I’m a big fan of nginx and I tend to use it to solve a lot of my problems, this case is no exception. Nginx has a built-in Memcached module, with this we can store a page in Memcached and have nginx serve it – thus never touching PHP at all. This essentially turns this:

flattr this!

I love PHP, I really do… just, sometimes you fall into these situations where you just can’t help bang your head against the table until even the table starts bleeding.

I’m currently working on a blog series about intelligent caching with PHP. During the preparation for this I had to create a framework which could demonstrate the caching concepts I was going to be discussing, and what better than using namespaces for it. Namespaces makes auto loading easy as pie, they give you an incredible freedom in class naming due to the extra encapsulation layer and in general they’re just brilliant. Except for this.

$controller = '\Evil\Controller\News';
$data = $controller::dataKeyInvalidates($invalidate);

It simply wouldn’t work. I was certain it worked fine without namespaces so for kicks I tried this:

$data = \Evil\Controller\News::dataKeyInvalidates($invalidate);

And it ran without problems. Fun. What eventually let me figure out what was going on was by echoing the variable passed to my auto loader. When I used a variable to reference the class name the auto loader was passed “\Evil\Controller\News” when I didn’t the auto loader was passed “Evil\Controller\News”. Obviously some magic goes on inside PHP that translates \Evil\Controller\News into “Evil\Controller\News”. Setting $controller to ‘Evil\Controller\News’ made it work perfectly fine.

So to recap this:

// Does not work.
$controller = '\Evil\Controller\News';
$data = $controller::dataKeyInvalidates($invalidate); 

// Works.
$controller = 'Evil\Controller\News';
$data = $controller::dataKeyInvalidates($invalidate); 

// Works.
$data = \Evil\Controller\News::dataKeyInvalidates($invalidate); 

// Does not work.
$data = Evil\Controller\News::dataKeyInvalidates($invalidate);

flattr this!

Performance is often important to people using nginx – and for good reason, of course. Sadly, while many people will optimize their software stack they will rarely work on optimizing the back-end code; and even more rarely will they eliminate single points of failure. Such was also the case when SitePoint recently published an article about uploading large files with PHP. This post will discuss a method to accept uploads that will scale far better and not offer malicious users an easy DoS vector.

The Problem

File uploads are used in many places, depending on your site people might be adding avatars, personal pictures, music or any other type of file. The size of uploads can vary a lot but in the end it doesn’t really matter much, you’re still offering a malicious user a single point of failure where he can direct his denial of service attack.

Allow me to illustrate. Lets say you have an upload form for people to upload pictures, you run Apache in pre-fork mode with mod_php and 50 max children, otherwise known as the standard Apache setup.

Each time Apache accepts an upload one of these processes is going to be busy for the duration of the upload. Do you see the problem here? File uploads to PHP are essentially really long-running scripts and you’re going to run out of Apache processes quickly. It might not even be a malicious user, you could be a victim of your own popularity.

If you’re using nginx then you’re already better off as nginx will buffer the file upload to disk and only pass it to your fastcgi back-end once the file upload is complete. If you’re uploading a 1 GB file nginx is still going to send 1 GB of data over fastcgi, though, but we can do something about that.

flattr this!