Template for PHP service (/etc/init.d) script I wanted a template for a service script that is versatile and easily configurable.

Along with producing similar outputs to the SSH and Samba daemons, I request the code to be as clean, simple and self explanatory as possible.  Hence I removed all the comments.

Sample usage:

$ service mydaemon restart
mydaemon stop/waiting
mydaemon start/running, process 30549


Sample of similar command with the SSH daemon:

$ service ssh restart
ssh stop/waiting
ssh start/running, process 30577


Here is my service.php script:

#!/usr/bin/php
&lt;?php

    define('NAME',      basename($argv[0]));
    define('RUNAS',     'root');
    define('DIR',       __DIR__);
    define('CMD',       __DIR__.'/thread.php');
    define('SUDO',      'sudo -u '.RUNAS.' ');
    define('LOG_FILE',  '/dev/null');
    define('PID_FILE',  '/var/run/'.NAME.'.pid');

    function writeln($string)
    {
        echo $string.PHP_EOL;
    }

    class service
    {
        public static function unset_pid()
        {
            if (is_file(PID_FILE)) unlink(PID_FILE);
        }

        public static function get_pid()
        {
            if (!is_file(PID_FILE)) return null;

            $pid=file_get_contents(PID_FILE);

            $process_status=null;
            if (!empty($pid) &amp;&amp; ctype_digit($pid)) $process_status=shell_exec('ps '.$pid);

            if (empty($process_status) || strpos($process_status, CMD, 0)===false)
            {
                service::unset_pid();
                return null;
            }

            return $pid;
        }

        public static function is_running()
        {
            return (!empty(service::get_pid()));
        }

        public static function start()
        {
            if (service::is_running())
            {
                writeln('start: Job is already running: '.NAME);
                return true;
            }

            $new_pid=shell_exec('cd '.DIR.';'.SUDO.CMD.' &gt;&gt; '.LOG_FILE.' 2&gt;&amp;1 &amp; printf $!;');
            file_put_contents(PID_FILE, $new_pid);
            service::status();

            return service::is_running();
        }

        public static function stop()
        {
            if (!service::is_running())
            {
                writeln('stop: Unknown instance:');
                return true;
            }

            shell_exec('kill '.service::get_pid());

            for ($seconds=0; $seconds&lt;60; $seconds++)
            {
                if (!service::is_running()) break;
                sleep(1);
            }

            if (service::is_running())
            {
                writeln('Not stopped; may still be shutting down or shutdown may have failed.');
                return false;
            }

            service::status();

            return !service::is_running();
        }

        public static function restart()
        {
            if (!service::stop())
            {
                writeln('Aborting restart.');
                return false;
            }

            return service::start();
        }

        public static function status()
        {
            $running=service::is_running();
            if ($running) writeln(NAME.' start/running, process '.service::get_pid()); else writeln(NAME.' stop/waiting');
            return $running;
        }

    };

    if (count($argv)!=2)
    {
        if (count($argv)&gt;2) writeln('Too many arguments given.');
        $argv=array($argv[0], '');
    }

    switch (strtolower($argv[1]))
    {   
        case 'start':

            service::start();
            break;

        case 'stop':

            service::stop();
            break;

        case 'restart':

            service::restart();
            break;

        case 'status':

            service::status();
            break;

        default:

            if (!empty($argv[1])) writeln('Unknown option: '.$argv[1]);
            writeln('Usage: '.$argv[0].' {start|stop|restart|status}');
            break;
    }

?&gt;


Any suggestions for improvements will be appreciated.
from stop:

        if (service::is_running())
        {
            writeln('Not stopped; may still be shutting down or shutdown may have failed.');
            return false;
        }

        service::status();

        return !service::is_running();


from start:

        service::status();

        return service::is_running();


Hmm, looks like a similar pattern... Can we combine this in a separate function?

What does service::status do?

    public static function status()
    {
        $running=service::is_running();
        if ($running) writeln(NAME.' start/running, process '.service::get_pid()); else writeln(NAME.' stop/waiting');
        return $running;
    }


... Wait, it prints a few things and then returns whether it's running.

So why the double is_running call?

I'd just return the result of service::status in these cases. It'd be more correct too; what if a service stops between your logging and the return statement? You'd log that it's running and then return that it's ... not running. Good way to have logs showing "everything is fine" whilst things aren't doing what they're supposed to do.