Writing a PHP daemon application
There is a special group of applications that require a different PHP script execution model. For example:
- A chat server (or any other kind of socket server therefore)
- A HTML5 WebSocket server
- A web crawler, data harvester or any other real-time service
All of the mentioned applications need to be run in the background as daemons – something that PHP was never designed/supposed to be good at. The plain C language is a weapon of choice when it comes to writing a daemon implementation, but then again, if the application in question does not depend on high performance and concurrency – PHP can do the job quite well.
This article contains some of my past experiences with daemon-like PHP scripts. Hopefully it will be useful to the rest of PHP community.
Using PHP command line interface
CLI executable should be used for running daemon scripts. A simple invocation would look like this:
php /path/to/run.php
Further command line arguments can be used to fine-tune your daemon process:
php \ -f /path/to/run.php \ -c /path/to/custom/php.ini \ -d error_log=/var/log/chatserver
In the example above a custom php.ini configuration file will be used and all daemon related error messages will be logged to a separate /var/log/chatserver file.
PHP command line process has slightly different configuration from other SAPIs. The most important change is that script execution time limit is disabled by default and so you do not need to concern yourself with set_time_limit() calls or max_execution_time INI setting. Other configuration options should be tweaked depending on your requirements. You may want to disable memory limit for example:
# From command line php ... -d memory_limit=-1
The run loop of a daemon
A daemon should not terminate as is the case with a regular PHP-HTTP request (or crontab job therefore). To achieve this one can write a run loop like this:
while (true) { ... // Process tasks }
And a socket server might have the following loop implementation:
// Initialize and bind non-blocking listening server socket $server_socket = ...; while (true) { // Accept new client connections if(($client_socket = socket_accept($server_socket)) !== false) { ... } ... // Process all connected client sockets }
Provided loops do not block on anything and would quickly consume 100% CPU. It depends on your implementation but you may want to hang for a while at certain point with a sleep() or usleep() function to avoid that.
Using upstart to control daemon process
A daemon has to run in the background and needs to be controlled from command line. It also should start/stop on server reboots. To achieve this on a Unix-like system one can write a System-V init script or an upstart job. I am a huge fan of upstart and prefer it for its features and simplicity. Note that upstart is the default init daemon in Ubuntu and if you are running that you are more than likely have everything ready and in place.
Imagine you want to write a control script for a PHP chat server. With upstart you need to create a new job at /etc/init/chatserver.conf:
# The default run-level for Ubuntu/Debian is 2 start on runlevel 2 stop on runlevel [!2] # Upstart can respawn your daemon process on segfault/crashes/etc respawn respawn limit 2 10 # A daemon should not run as a root user # We are using "www" user here exec sudo -u www php -f /path/to/run.php ...
Controlling your daemon from command line is now trivial:
start chatserver restart chatserver stop chatserver
A System-V control script would be a bit more complicated and actual implementation would depend on target distribution. However, one could use Debian start-stop-daemon or similar utility to simplify things significantly.
Custom process title with proctitle extension
While at this point you should have a fully working daemon setup there are still some extras you may want to consider adding. One of them is a custom process title functionality that is provided in Linux/BSD systems using setproctitle() call (and then visible in ps command output). PHP has a tiny wrapper/binding around this feature in PECL proctitle extension.
To install it – run the following from command line (and then enable this extension in your php.ini configuration):
pecl install proctitle-alpha
Building on that chat server idea you can provide a number of active client connections in the process title. It should be updated periodically when the number changes with the following function call:
setproctitle('chatserver ('.count($client_sockets).' clients)');
Running a ps axf command would result in:
PID TTY STAT TIME COMMAND 442 ? Ss 0:00 nginx: master process nginx 443 ? S 2:07 \_ nginx: worker process ... ... 472 ? Ss 58:00 chatserver (3 clients)
Handling daemon log files
As already pointed out previously – you can easily override default php.ini configuration from CLI to fit your daemon implementation. One thing worth considering is setting up file-level error logging and redirecting daemon log entries to a separate file with error_log directive.
Once you have this configured – any general PHP warnings/errors will be logged automatically based on your error_reporting directive. You can also log other daemon-related log entries using the following function call:
error_log('Rejecting client - maximum number of clients reached');
Further, you may want to configure logrotate to rotate your old daemon log files. A simple logrotate configuration entry would look like this:
(Located at /etc/logrotate.d/chatserver on Ubuntu)
/var/log/chatserver {
weekly;
rotate 4;
}This would rotate chat server log file every week (keeping up to 4 old rotated log files).
A word on parallel processing, forking and the like
You may have already heard that PHP lacks any kind of kernel-level threading support. And I would go as far as to say PHP is the wrong tool if you need this kind of behavior in your daemon application. Still, it’s worth mentioning that there are some hacks/methods floating around that may be worth considering if you truly need this functionality.
One relatively safe option is to use process forking with pcntl_fork() function call (part of Process Control extension). Keep in mind that PHP processes are fat and multiple forked childs will use a lot of memory. You may want to custom-compile your PHP CLI binary to disable any extensions/features that are not used in your daemon application. Another issue you may run across is inter-process communication and data sharing between your daemon processes. You may want to look at Semaphore extension that has some IPC facilities.
There is also this brave attempt worth checking that has an implementation of user-land PHP threading. The functional interface looks really great and tempting but it does require a custom PHP re-compile with some patching. I haven’t had the chance to try this threading support myself so If you did had a look at it – be sure to leave a comment or two.

