Tag Archives: PHP

Slides for my Talk on Asset Fingerprinting with PHP

I recently held a talk at the Berlin PHP user group meetup on “Asset Fingerprinting and Cache Busting with PHP”. Asset fingerprinting is an approach taken from Rails that allows you to set far-future cache expiry dates for static files and still have the browser re-load them whenever they change. In my talk I show how you can do that with PHP. There’s also some demo code on GitHub.

Here are the slides, have fun!

Using PECL/Memcached to store sessions

This post is the second part of my earlier article about installing and setting up the Memcached server and PECL/Memcached PHP client on CentOS 5.5.

Let’s assume you have PECL/Memcached up and running and want to use it as a session handler. I’ll talk below about why you’d want to do this (and why not) and how to get there.

Is storing sessions with Memcached a good idea?

As usual: it depends.
Regular file-based session storage is reliable and reasonably fast. It has its drawbacks though, especially when you want to scale: First of all, if you have several servers behind a load balancer, you need to make sure that a visitor always gets the same session if he is assigned to another server in-between. This is difficult if sessions are stored locally on each server. Also, a LOT of these tiny session files can pile up fast on your server, which makes server backups more difficult. Also, when you’re on a cheap cloud server, file I/O speed might not be optimal. So you start thinking about a RAM-based solution. One way to do this would be a tmpfs partition to store session files in memory. But remember, you still need a central place to store sessions. In comes Memcached.
Memcached operates in-memory only, and can be run on one or more central servers. Great, right? Yes and no. Memcached is not a database, but an LRU (“least-recently-used”) cache with a fixed size. If there is not enough room, the oldest items will be removed. If we use it for session storage, some people might be logged out randomly. Duh. So, if you want to use Memcached, you have to weigh its advantages and drawbacks. It’s certainly not a good option if you have important sessions (like shopping carts) that you cannot afford to lose. On the other hand, if it’s OK to lose a session once in a while, Memcached might be a good solution for you. It’s very fast and easy to set up, and it is supported as a session handler by PHP out of the box. You can mitigate the risk by assigning enough RAM, and by adding a “remember me” feature (if it’s not a security concern, depending on the type of your site). If you use a custom session handler, you can even use Memcached purely as a caching front-end for a database session store and get the best of both worlds.

How to set up Memcached as PHP session handler

There are two ways to use Memcached as your session handler: if you have no special needs, you can simply set some PHP ini options and you’re done. This was good enough in my situation and I’ll describe this solution here. If you want to use advanced options, like using persistent connections or using a combined Memcached/MySQL solution, you will need to use a custom session handler (not described here).

The easy way: set PHP ini options

As PHP comes with support for Memcached as session storage baked in, you only need to set two options and you’re good to go. You can either set these in your php.ini file, or at run-time in your application.
; either put this in php.ini
; replace or comment out the existing two options
session.save_handler = memcached
; change server:port to fit your needs
session.save_path="127.0.0.1:11211"

# or, include this in your application startup code
ini_set('session.save_handler', 'memcached');
ini_set('session.save_path', '127.0.0.1:11211');

Note: There are a few gotchas here, and this is actually what made me write this post. Most other blog posts about this topic use PECL/Memcache, not PECL/Memcached. Both have a different API and different options. If you’re using PECL/Memcached (like me), make sure to include the “d” in the handler name (“memcached”). Also, the save path must NOT include the protocol (just server IP and port). You CAN specify a comma-separated list of servers, but you CANNOT specify options here, like you can with PECL/Memcache. If you need special options, you must use a custom session handler, as mentioned above.

That’s it, we’re done! Now go ahead, restart Apache, and test your shiny new Memcached sessions.

How to set up the Memcached PHP client library on CentOS 5

As we are currently building community features for our game download deal discovery site Deals4Downloads.com, I started investigating Memcached as a caching and session storage option. There are already many blog posts out there about this, but as many of them are unclear or even misleading, and I stumbled into every gotcha out there along the way, I thought I’d share some helpful tips here on how to get it all running. I’ll explain below what you’ll need to get Memcached along with PECL/Memcached (note the “d”) for your PHP site on CentOS 5.5. I’m not a pro sysadmin and I won’t go into every detail, but you’ll get the gist.

Memcache, Memcached, what’s with the name?

There are two parts to this equation: a server component and a PHP client component. You will need both. For the PHP client, there are two options, one of which even shares the name with the server component, which has caused a good deal of confusion.

Installing and setting up the Memcached server

You’ll need to install the Memcached server component first to be able to store and read values. Fortunately, this is the easy part: install package, configure and start server, add firewall rule to secure server, done.

Installation

Memcached is available as a ready-made package in my favorite repository, Remi, so we can install it with:

yum --enablerepo=remi install memcached

This should hopefully proceed without any problems. If you don’t have the Remi repository, you should first add it to your system, or use the repo of your choice.

Configuration

Next we need to edit the server’s configuration, start it and add it to the system start configuration. As far as I see it, you have two options here: either use the provided start script from the RPM, or add your own. You can set several parameters, like the IP and port that the service runs on, the user, and the amount of memory assigned (keep in mind that this is a fixed value).
# Option 1: edit and use the RPM start script
#adapt options here, like memory available
vi /etc/init.d/memcached
# start service
/etc/init.d/memcached start
# add to system boot config
chkconfig memcached on

# Option 2: start server manually and add custom start command to /etc/rc.local
# start server as daemon
/usr/bin/memcached -d -m 1024 -u httpd -l 127.0.0.1
# next, add the above command to /etc/rc.local to make it run at boot-time

A word about the parameters shown above:
-d start as daemon
-u user name for Memcached (adapt to your needs)
-m amount of memory assigned, in MB
-l (this is an L) IP address to listen on

Making it more secure

I’ll assume you will use your Memcache server only locally. It’s a good idea to add an IpTables rule to block all outside requests to this server. Add a line like this to your IpTables config (I won’t show this in detail here):
-A INPUT -p tcp --dport 11211 -j ACCEPT
If you want to set up a dedicated Memcached server and access it from another server, you will have to change the above accordingly.

Testing your Memcached server

Let’s test our new server a bit. I’ll show you some tools with output from my test server below:
# Is the service running?
root@D4D-TEST01 ~: netstat -tap | grep memcached
tcp 0 0 *:11211 *:* LISTEN 29441/memcached
tcp 0 0 *:11211 *:* LISTEN 29441/memcached

# see some stats with memcached-tool (installed along with RPM):
root@D4D-TEST01 ~: memcached-tool 127.0.0.1:11211 stats
#127.0.0.1:11211 Field Value
accepting_conns 1
auth_cmds 0
auth_errors 0
bytes 1867
bytes_read 81117
bytes_written 54550
[... etc]

Let’s connect with Telnet and set and get a value. You can set values with “set [keyname] [flag] [expirytime] [bytes]” and get values with “get “. If you set a value, you specify the keyname and the options first, press Enter, and then specify the value on the next line. You can read more about these commands here for example.

root@D4D-TEST01 ~: telnet localhost 11211
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
set mykey 0 900 6
mydata
STORED
get mykey
VALUE mykey 0 6
mydata
END

This is a bit clumsy of course, and what we really want is to set values from PHP. Time to install the PHP client component.

Again: Memcache, Memcached – what’s up?

This is where the confusion starts: there are two PHP client libraries available (both in PECL): one is called “Memcache” (or PECL/Memcache) and one is called “Memcached” (or PECL/Memcached). Yep, the second one is named exactly like the server. For a comparison, see for example here and here. The short of it: PECL/Memcache is older, less actively developed, and more widely used. PECL/Memcached relies on the libmemcached library, is newer and has more features. Most blog posts you’ll find are about PECL/Memcache, and that can be a bit misleading if you want to start out with PECL/Memcached.
After weighing my options, I decided to go with PECL/Memcached, and I’ll show you how to get it below.

Installing PECL/Memcached

If you just want the current stable version, get it from a suitable RPM. You will need libmemcached, too.

yum --enablerepo=remi install libmemcached
yum --enablerepo=remi install php5-memcached

After reading about some bugs in that version, I decided to use the current beta though, so I had to get it from PECL, which proved to be a bit more challenging. To make a long story short, you will definitely need zlib and libmemcached first, and probably their development libs as well (plus PECL of course):
yum --enablerepo=remi install zlib zlib-devel
yum --enablerepo=remi install libmemcached libmemcached-devel
pecl install memcached-beta

That should do the trick. You might have to add
extension=memcached.so

to your php.ini, if it’s not there already. If you call up phpinfo() (after restarting Apache), it should look like this:
phpinfo output for PECL/Memcached

Testing, again

So let’s test our new client with a little PHP script:
<?php
$mc = new Memcached();
$mc->addServer('localhost', 11211);
$mc->set('testkey', 'Hello there');
echo $mc->get('testkey');

Keep in mind that the APIs for Memcache and Memcached are very different, so most examples you see on the net won’t work for PECL/Memcached. The correct version of the documentation (as opposed to the one for Memcache) is here.
If you want to use persistent connections, make sure that you only add a server when none is defined yet, lest you end up with hundreds of them:
if (!count($mc->getServerList()))
$mc->addServer("localhost", 11211);

That’s about it. You now have a working Memcached setup and can use it for your caching purposes.

You can also use Memcached to store your sessions, but that will be covered in my next post.