cli, the other sapi

76
CLI, the other SAPI Using PHP on the command line in a Linux environment Thijs Feryn - [email protected]

Upload: combell-group

Post on 14-Jan-2015

5.119 views

Category:

Technology


7 download

DESCRIPTION

PHP isn't only used as a web-based scripting language, it can also be used on the command line. This talks explains the benefits of command line PHP. Additionally, process control using CLI PHP is explained.

TRANSCRIPT

Page 1: CLI, the other SAPI

CLI, the other SAPIUsing PHP on the command line in a Linux

environmentThijs Feryn - [email protected]

Page 2: CLI, the other SAPI

• Thijs Feryn (http://blog.feryn.eu)• Support manager at COMBELL• Zend Certified PHP 5 developer• I love the LAMP stack• Working on my MySQL certification• Open-source contributor• Nerd/geek of some sort

Who am I?

Page 3: CLI, the other SAPI

Who’s COMBELL?

Page 4: CLI, the other SAPI

• Largest independent hoster in Belgium• Founded in 1999 (a decade of COMBELL)• Focus on premium/quality hosting• More than 25 000 customers• More than 100 000 domains• More than 20 000 websites• More than 1000 servers• More than 800 resellers

Summarized: authorative partner for all hosted activity

Who’s COMBELL?

Page 5: CLI, the other SAPI

• Who’s a developer?

• Who’s a PHP developer?

• Who has ever used the PHP CLI?

• Who is used to working on Linux?

• Who has experience with process forking?

Who are you?

Page 6: CLI, the other SAPI

1. SAPI ... schmapi? (definition)2. Common PHP SAPI’s (overview)3. The CLI SAPI (how to use, possibilities, when to use)4. Apache vs CLI (a comparison)5. PHP binary options6. CLI in action (some examples)7. PCNTL == $fooDoo (the magic of process control)8. Wake the daemons (putting it all together)9. Q & A (the obligatory epilogue)

What’s up?

Page 7: CLI, the other SAPI

Definition

SAPI ... schmapi?

Wikipedia says: “The Server Application Programming Interface

(SAPI) is the generic term used to designate direct module interfaces to

web server applications”

In concreto: the SAPI is the way your server interacts with PHP

Page 8: CLI, the other SAPI

Overview

• Apache/Apache 2

• CGI

• FastCGI

• ISAPI

• CLI

• GTK

Common SAPI’s

Page 9: CLI, the other SAPI

Enabling the SAPI you need

• CLI is included by default• Add the right parameter to enable the Apache

Common SAPI’s

./configure --with-apxs=/location/of/your/apache/module

SAPI when compiling from source

Page 10: CLI, the other SAPI

Definition

The CLI SAPI

Php.net says: As of version 4.3.0, PHP supports a new SAPI type (Server Application Programming Interface) named CLI which means Command Line Interface. As the name implies, this SAPI type main focus is on developing shell (or desktop as well) applications with PHP.

In Concreto: PHP scripts are no longer exclusively called via the web browser. Using CLI, PHP scripts can be executed from the command line of the server which offers a vast array of benefits

Page 11: CLI, the other SAPI

When to use

• In cron’s

• For batches

• Process control

• Linux interactivity (e.g.: pipes)

The CLI SAPI

Page 12: CLI, the other SAPI

CLI 101

• Each CLI script is called via the PHP binary

• Arguments can be passed

• Arguments can be interpreted via special variables

• Input can be passed via STDIN

• Output can be returned via STDOUT

• Errors can be returned via STDERR

• I/O via pipes is possible

The CLI SAPI

$ php cli.php

Page 13: CLI, the other SAPI

CLI 101: arguments

• Passing arguments

• Interpreting arguments via $_SERVER

• $_SERVER[‘argc’] = counts the number of arguments

• $_SERVER[‘argv’][0] = scriptname (cli.php)

• $_SERVER[‘argv’][1] = first argument (arg1)

• $_SERVER[‘argv’][2] = second argument (arg2)

The CLI SAPI

$ php cli.php arg1 arg2

Page 14: CLI, the other SAPI

CLI 101: arguments

If ‘register_argc_argv’ is enabled 2 extra local variables are registered:

• $argc: counts the number of arguments

• $argv: array which stores the arguments

• $argv[0] = scriptname (cli.php)

• $argv[1] = first argument (arg1)

• $argv[2] = second argument (arg2)

The CLI SAPI

Page 15: CLI, the other SAPI

CLI 101: arguments & getopt()

• Gets command line arguments & values based on an input variable containing all the options:

• Individual characters (= flags, do not accept values)

• Characters followed by colon (input value required)

• Characters followed by 2 colons (input value optional)

• Long options only work well in PHP 5.3

• Check out Zend_Console_Getopt, it has some nice features similar to getopt()

The CLI SAPI

$options = getopt(‘ab:c::’);

Page 16: CLI, the other SAPI

CLI 101: input

• Reading from STDIN by opening a stream

• Reading a single line from STDIN

The CLI SAPI

$handle = fopen('php://stdin', 'r');

$stdin = trim(fgets(STDIN));

Page 17: CLI, the other SAPI

CLI 101: output

• Writing to STDOUT by opening a stream

• Writing a single line to STDERR

The CLI SAPI

$handle = fopen('php://stdout', 'w');

fwrite(STDOUT,‘output’);

Page 18: CLI, the other SAPI

CLI 101: errors

• Writing to STDERR by opening a stream

• Writing a single line to STDERR

The CLI SAPI

$handle = fopen('php://stderr', 'w');

fwrite(STDERR,‘error’);

Page 19: CLI, the other SAPI

CLI 101: piping

Using STDIN, STDOUT & STDERR streams you can easily benefit from the piping mechanisms in Linux to interact with other binaries

The CLI SAPI

$ cat input.ext | php myCliScript.php > output.ext

$ php myCliScript.php | grep filterText > output.ext

Page 20: CLI, the other SAPI

CLI 101: piping

You can also combine it with arguments

The CLI SAPI

$ php myCliScript.php arg1 arg2 > output.ext

$ cat input.ext | php myCliScript.php arg1 arg2 arg3 | grep filterText > output.ext

Page 21: CLI, the other SAPI

State means everything

Apache VS CLI

Apache• HTTP is stateless a protocol

• Limited interactivity

• Sessions & cookies as workaround for these drawbacks

• Execution timeouts

• Limited packet size

Page 22: CLI, the other SAPI

State means everything

Apache VS CLI

CLI• Controllable state

• More interactivity

• No (need for) sessions

• No execution timeouts

Page 23: CLI, the other SAPI

Ins & outs: input

Apache VS CLI

Apache$_GET

$_POST

$_COOKIE

$_SESSION

$_SERVER

$_ENV

CLI$_SERVER[‘argv’]

$argv

$_ENV

getopt()

STDIN

Page 24: CLI, the other SAPI

Ins & outs: output

Apache VS CLI

ApacheHTTP output only

Limited packet size

CLISTDOUT

STDERR

Page 25: CLI, the other SAPI

CLI usage, Apache mentality

Apache VS CLI

• Don’t use sessions or cookies, just use a local variables

• Don’t “get” your input, “read” it

• No execution timeouts

• Bundled output (HTTP): in response message

• Distributed output (CLI): via STDOUT. Available when needes

Page 26: CLI, the other SAPI

CLI usage, Apache mentality

Apache VS CLI

• OVERHEAD ALERT: don’t use HTTP via crons (e.g. via lynx or wget), use the php binary.

• CLI mode doesn’t change the CWD (current working directory). Be careful with path reference

• Use “dirname(__FILE__)”

• Use “chdir()”

Page 27: CLI, the other SAPI

CLI options reference

PHP binary options

Usage: php [options] [-f] <file> [--] [args...] php [options] -r <code> [--] [args...] php [options] [-B <begin_code>] -R <code> [-E <end_code>] [--] [args...] php [options] [-B <begin_code>] -F <file> [-E <end_code>] [--] [args...] php [options] -- [args...] php [options] -a

-a Run interactively -c <path>|<file> Look for php.ini file in this directory -n No php.ini file will be used -d foo[=bar] Define INI entry foo with value 'bar' -e Generate extended information for debugger/profiler -f <file> Parse and execute <file>. -h This help -i PHP information -l Syntax check only (lint) -m Show compiled in modules -r <code> Run PHP <code> without using script tags <?..?> -B <begin_code> Run PHP <begin_code> before processing input lines -R <code> Run PHP <code> for every input line -F <file> Parse and execute <file> for every input line -E <end_code> Run PHP <end_code> after processing all input lines -H Hide any passed arguments from external tools. -s Display colour syntax highlighted source. -v Version number -w Display source with stripped comments and whitespace. -z <file> Load Zend extension <file>.

args... Arguments passed to script. Use -- args when first argument starts with - or script is read from stdin

--ini Show configuration file names

--rf <name> Show information about function <name>. --rc <name> Show information about class <name>. --re <name> Show information about extension <name>. --ri <name> Show configuration for extension <name>.

Page 28: CLI, the other SAPI

Run code

PHP binary options

$ php -r “echo \"Give me some output\";”

Give me some output

$

• Binary option: -r

• Meaning: parse & run PHP code that is passed as an argument

Example

Page 29: CLI, the other SAPI

Interactive mode

PHP binary options

$ php -a

$ php > echo "Give me some interactive output";

Give me some interactive output

$ php>

• Binary option: -a

• Meaning: running PHP interactively in a true command line environment

• Requirements: PHP compiled with readline support

Example

Page 30: CLI, the other SAPI

Define configuration

PHP binary options

$ php -d max_execution_time=20 -r “echo ini_get("max_execution_time");”20$

• Binary option: -d

• Meaning: define INI configuration settings at runtime

Example

Page 31: CLI, the other SAPI

Lint check

PHP binary options

• Binary option: -l

• Meaning: perform a “lint” check on a PHP file. Validates the syntax of a script. Errors are printed via STDOUT. Shell return codes are “0” or “1”

• Notice:

• Doesn’t work combined with the “-r” option.

• Only checks for parsing errors & cannot retrieve fatal errors (e.g. undefined functions)

Page 32: CLI, the other SAPI

List modules

PHP binary options

$ php -m

[PHP Modules]

xmltokenizerstandardsessionposixpcreoverloadmysqlmbstringctype

[Zend Modules]

• Binary option: -m

• Meaning: prints all loaded PHP & Zend modules

Example

Page 33: CLI, the other SAPI

Syntax highlighting

PHP binary options

$ echo "<?php var_dump($_SERVER);" | php -s

<code><span style="color: #000000">

<span style="color: #0000BB">&lt;?php&nbsp;var_dump</span><span style="color: #007700">();<br /></span>

</span>

$

• Binary option: -s

• Meaning: format PHP code into highlighted HTML code

• Notice: doesn’t work with the “-r” option.

Example

Page 34: CLI, the other SAPI

Version information

PHP binary options

$ php -v

PHP 5.2.4-2ubuntu5.3 with Suhosin-Patch 0.9.6.2 (cli) (built: Jul 23 2008 06:44:49)

Copyright (c) 1997-2007 The PHP Group

Zend Engine v2.2.0, Copyright (c) 1998-2007 Zend Technologies

with Xdebug v2.0.3, Copyright (c) 2002-2007, by Derick Rethans

$

• Binary option: -v

• Meaning: displays version information

Example

Page 35: CLI, the other SAPI

Function reflection

PHP binary options

$ php --rf var_dumpFunction [ <internal:standard> function var_dump ] { - Parameters [2] { Parameter #0 [ <required> $var ] Parameter #1 [ <optional> $... ] }}$

• Binary option: --rf

• Meaning: displays function API information

• Requirements: PHP must be compiled with “Reflection” support

Example

Page 36: CLI, the other SAPI

Class reflection

PHP binary options

• Binary option: --rc

• Meaning: displays class API information

• Requirements: PHP must be compiled with “Reflection” support

Page 37: CLI, the other SAPI

Class reflection

PHP binary options

$ php --rc stdclass

Class [ <internal> class stdClass ] { - Constants [0] { } - Static properties [0] { } - Static methods [0] { } - Properties [0] { } - Methods [0] { }}

$

Example

Page 38: CLI, the other SAPI

Read from STDIN + distributed output

CLI in action

<?php/** * Read input from STDIN and print input with line numbers. * Quit when blank rule entered. */$line = 0;do{ $line++; $input = trim(fgets(STDIN)); if(strlen($input) > 0){ echo "$line# $input".PHP_EOL; }else{ break; }}while (true); Code

Page 39: CLI, the other SAPI

Read from STDIN + distributed output

CLI in action

$ php cli.php

this1# thisis2# ismy3# myoutput4# output

$

Output

Page 40: CLI, the other SAPI

Read from STDIN + bundled output

CLI in action

<?php/** * Read input from STDIN and print input with line numbers. * Quit when blank rule entered. * Bundle output and print at the end of the script. */$line = 0;$output = '';do{ $line++; $input = trim(fgets(STDIN)); if(strlen($input) > 0){ $output.= "$line# $input".PHP_EOL; }else{ break; }}while (true);echo $output; Code

Page 41: CLI, the other SAPI

Read from STDIN + bundled output

CLI in action

$ php cli.php

thisismyoutput

1# this2# is3# my4# output

$ Output

Page 42: CLI, the other SAPI

Working with arguments

CLI in action

<?php/** * Parse all arguments starting at index 1. * If format is "--key" or "-key", parse key and assign "true" as value * If format is "--key=value" or "-key=value", parse key and extract value * Else, value is argument, key is argument index */for($i=1;$i<$argc;$i++) { if(preg_match('/^(\-+)([a-zA-Z0-9_\-]+)(=([a-zA-Z0-9_\-])+)?$/',$argv[$i],$matches)){ $key = $matches[2]; if(array_key_exists(4,$matches)){ $value = $matches[4]; } else { $value = true; } } else { $key = $i; $value = $argv[$i]; } echo "Key: $key - Value: $value".PHP_EOL;}

Code

Page 43: CLI, the other SAPI

Working with arguments

CLI in action

$ php cli.php --flag1 -flag2 --option1=value1 -option2=value2 unNamedArgument

Key: flag1 - Value: 1Key: flag2 - Value: 1Key: option1 - Value: 1Key: option2 - Value: 2Key: 5 - Value: unNamedArgument

$Output

Page 44: CLI, the other SAPI

Shell binary

CLI in action

#!/usr/bin/php<?php/** * Print the current time. * This binary directly uses the PHP binary. * When the script has execute permissions it can be called as "./cli" instead of "php cli.php" */echo "The current time is ".date('H:i:s').PHP_EOL;

Code

$ chmod +x ./cli

$

$ ./cli

The current time is 17:43:08

$

Permissions

Call script + output

Page 45: CLI, the other SAPI

Linux interaction & piping

CLI in action

$ php -r 'for($i=0;$i<10;$i++) echo $i.PHP_EOL;' | wc -l

10

$

• Pass PHP code to binary using the “run” flag

• Print 10 lines

• Pipe output from PHP script as input for the “word count” binary

• Add the “-l” flag to count the number of lines

• Output 10

Page 46: CLI, the other SAPI

Using getopt()

CLI in action

<?php$shortopts = "";$shortopts .= "f:"; // Required value$shortopts .= "v::"; // Optional value$shortopts .= "abc"; // These options do not accept values

$options = getopt($shortopts);var_dump($options);

$ php cli.php -a -v -f value

array(3) { ["a"]=> bool(false) ["v"]=> bool(false) ["f"]=>string(5) "value"}

Code

Output

Page 47: CLI, the other SAPI

The magic of process control

PCNTL == $fooDoo

Php.net says: Process Control support in PHP implements the Unix style of process creation, program execution, signal handling and process termination. Process Control should not be enabled within a web server environment and unexpected results may happen if any Process Control functions are used within a web server environment.

InstallationAdd “--enable-pcntl” configuration option when compiling PHP

Page 48: CLI, the other SAPI

Forking is not a culinary term

PCNTL == $fooDoo

• pcntl_fork() copies the program execution into a child process

• Workload can be distributed between parent & child(s) via PID checking

• Allow “multithreadish’ parallel execution by forking multiple child processes

• Use a shared resource to define the workload (e.g.: file, array, DB, IPC, ...)

Wikipedia says: In computing, when a process forks, it creates a copy of itself, which is called a "child process." The original process is then called the "parent process". More generally, a fork in a multithreading environment means that a thread of execution is duplicated, creating a child thread from the parent thread.

Page 49: CLI, the other SAPI

PCNTL voodoo/$fooDoo

PCNTL == $fooDoo

• After forking, your logic is distributed in different PHP processes

• Forking too many childs can cause performance issues

• When using infinite loops, build in sleeps to avoid performance issues

• Only use PCNTL in CLI mode

• Be absolutely sure you master & control your child processes

• Avoid zombie processes

• Be able to kill your child processes at any time

• Only kil your own processes

Be very careful when forking child processes, because there are risks involved (hence the term $fooDoo)

Page 50: CLI, the other SAPI

Forking example

PCNTL == $fooDoo

<?php$pid = pcntl_fork();if ($pid == -1) { die('could not fork');} else if ($pid) { echo "[parent] I am the parent process and my child process has PID $pid".PHP_EOL; echo "[parent] Waiting for child termination".PHP_EOL; pcntl_wait($status); echo "[parent] Exiting".PHP_EOL;} else { for($i=0;$i<10;$i++){ echo "[child] Loop $i, sleeping for a second ...".PHP_EOL; sleep(1); } echo "[child] Exiting".PHP_EOL; exit;}

Page 51: CLI, the other SAPI

<?phpfor($i=0;$i<10;$i++){ $pid = pcntl_fork(); if ($pid == -1) { die('could not fork'); } else if ($pid == 0) { echo "[child] Child $i doing stuff".PHP_EOL; sleep(1); echo "[child] Child $i exiting".PHP_EOL; exit; } else { echo "[parent] Starting parent $i".PHP_EOL; pcntl_wait($status); echo "[parent] Ending parent $i".PHP_EOL; }}

Multiple forking

PCNTL == $fooDoo

Page 52: CLI, the other SAPI

<?phpecho "[parent] Starting parent".PHP_EOL;for($i=0;$i<10;$i++){ $pid = pcntl_fork(); if ($pid == -1) { die('could not fork'); } else if ($pid == 0) { echo "[child] Child $i doing stuff".PHP_EOL; sleep($i); echo "[child] Child $i exiting".PHP_EOL; exit; } }echo "[parent] Ending parent".PHP_EOL;exit;

Multiple forking without waiting

PCNTL == $fooDoo

Page 53: CLI, the other SAPI

Signals

PCNTL == $fooDoo

Wikipedia says: A signal is a limited form of inter-process communication used in Unix, Unix-like, and other POSIX-compliant operating systems. Essentially it is an asynchronous notification sent to a process in order to notify it of an event that occurred. When a signal is sent to a process, the operating system interrupts the process' normal flow of execution. Execution can be interrupted during any non-atomic instruction. If the process has previously registered a signal handler, that routine is executed. Otherwise the default signal handler is executed.

Page 54: CLI, the other SAPI

Signals

PCNTL == $fooDoo

• Communication between 2 processes

• Process sends asynchronous notification of an event

• Signal handlers can be used to execute custom logic

• Otherwise default signal handlers

Page 55: CLI, the other SAPI

Signals: SIGTERM

PCNTL == $fooDoo

• SIGTERM is used to terminate a process in a ‘nice’ way

• Much more gentle than SIGKILL

• Allows cleanup and closure of process

• Issued via ‘kill’ (no kill -9)

Page 56: CLI, the other SAPI

Signals: SIGINT

PCNTL == $fooDoo

• SIGINT is used to terminate a process via interruption

• Stops program execution just like SIGTERM

• Issued by a terminal (via CTRL+C)

Page 57: CLI, the other SAPI

Signals: SIGCHLD

PCNTL == $fooDoo

• SIGCHLD is sent to the parent when a child process is terminated

• Common when using process forking

• SIGCHLD is by default ignored and a zombie process is created

• Only sent when the parent issues a ‘wait’ call (avoids zombies)

Page 58: CLI, the other SAPI

<?phpdeclare(ticks = 1);function sig_handler($signo){

switch ($signo) { case SIGTERM: echo "SIGTERM".PHP_EOL; exit(); break; case SIGINT: echo "SIGINT".PHP_EOL; exit(); break; }

}pcntl_signal(SIGTERM, "sig_handler");pcntl_signal(SIGINT, "sig_handler");sleep(100);

Signals: example of SIGTERM & SIGINT

PCNTL == $fooDoo

Page 59: CLI, the other SAPI

<?phpdeclare(ticks = 1);$max=5;$simultaneous=0;$childId=0;

function sig_handler($signo) { global $simultaneous,$childId; switch ($signo) { case SIGCHLD: $simultaneous--; echo "SIGCHLD received for child #$childId".PHP_EOL; echo "Decrementing to $simultaneous".PHP_EOL; }}

pcntl_signal(SIGCHLD, "sig_handler");

Signals: example of SIGCHLD

PCNTL == $fooDoo

Page 60: CLI, the other SAPI

for ($childId=0;$childId<10;$childId++){ $pid=pcntl_fork(); if ($pid == -1) { die("could not fork"); } else if ($pid) { if ( $simultaneous >= $max ){ pcntl_wait($status); } else { $simultaneous++; echo "Increment to $simultaneous".PHP_EOL; } } else { echo "Starting new child #$childId ".PHP_EOL; echo "Now we de have $simultaneous simultaneous child processes".PHP_EOL; sleep(rand(3,5)); exit; }}

Signals: example of SIGCHLD

PCNTL == $fooDoo

Page 61: CLI, the other SAPI

POSIX functions

PCNTL == $fooDoo

Wikipedia says: POSIX or "Portable Operating System Interface for Unix" is the collective name of a family of related standards specified by the IEEE to define the application programming interface (API), along with shell and utilities interfaces for software compatible with variants of the Unix operating system, although the standard can apply to any operating system.

Page 62: CLI, the other SAPI

POSIX functions

PCNTL == $fooDoo

In PHP: POSIX functions in PHP allow you to interact with the POSIX interface of the operating system. For process control functions we mainly use POSIX to retrieve PID information and terminate/kill processes

Page 63: CLI, the other SAPI

POSIX functions

PCNTL == $fooDoo

• Determine the PID of the current process

• pcntl_fork() return value for the parent process is the same as posix_getpid() for the child process

posix_getpid()

• Determine the PID of the parent of the process

• posix_getpid() value for the parent process is the same as posix_getppid() for the child process

• posix_getppid() value for the parent process is the PID of the bash session

posix_getppid()

Page 64: CLI, the other SAPI

<?phpecho "[prefork] PID POSIX: ".posix_getpid().", parent PID: ".posix_getppid().PHP_EOL;for($i=0;$i<3;$i++){ $pid = pcntl_fork(); if ($pid == -1) { die('could not fork'); } else if ($pid == 0) { echo "[child] ID: $i, PID: ".posix_getpid().", parent PID: ".posix_getppid().PHP_EOL; exit; } else { echo "[parent] PID : ".posix_getpid().", parent PID: ".posix_getppid().PHP_EOL; pcntl_wait($status); }}

POSIX functions: example of posix_getpid() & posix_getppid()

PCNTL == $fooDoo

Page 65: CLI, the other SAPI

POSIX functions

PCNTL == $fooDoo

• Send a signal to a certain process

• posix_kill($pid,0): gets PID status

• true: pid exists

• false: pid no longer exists

• posix_kill($pid,9) or posix_kill($pid,SIGKILL): kill a process

• posix_kill($pid,15) or posix_kill($pid,SIGTERM): terminate a process

posix_kill()

Page 66: CLI, the other SAPI

<?php$pid=pcntl_fork(); if ($pid == -1) { die("could not fork");} else if ($pid) { $exists = posix_kill($pid,0)?'still':'no longer'; echo "[parent] Child process $pid $exists exists".PHP_EOL; echo "[parent] Killing child process $pid".PHP_EOL; posix_kill($pid,SIGKILL); echo "[parent] Child process $pid killed".PHP_EOL; pcntl_wait($status); $exists = posix_kill($pid,0)?'still':'no longer'; echo "[parent] Child process $pid $exists exists".PHP_EOL; } else { while(true){ sleep(100); } exit;}

POSIX functions: example of posix_kill()

PCNTL == $fooDoo

Page 67: CLI, the other SAPI

#!/usr/bin/php<?phpdate_default_timezone_set('Europe/Brussels');$options = getopt('p:d:');/** * Determine pidfile */if(!array_key_exists('p',$options)){ die('No pidfile specified'.PHP_EOL);}define('PIDFILE',$options['p']);/** * Determine datadir */if(!array_key_exists('d',$options)){ die('No data directory specified'.PHP_EOL);}else{ if(!is_dir($options['d'])){ die('Data directory does not exist'.PHP_EOL); }}define('DATADIR',$options['d']);

The daemon (1)

Wake the daemons

Page 68: CLI, the other SAPI

/** * Delete pidfile on startup */if(file_exists(PIDFILE)){ unlink(PIDFILE);}/** * Delete pidfile after SIGINT or SIGTERM */function signal_handler($sig){ if(file_exists(PIDFILE)){ unlink(PIDFILE); }}/** * Set signal handler */pcntl_signal(SIGINT,'signal_handler');pcntl_signal(SIGTERM,'signal_handler');

The daemon (2)

Wake the daemons

Page 69: CLI, the other SAPI

/* * Setup daemon */$pid=pcntl_fork(); if ($pid == -1) { die("could not fork".PHP_EOL);} else if ($pid) { exit; }/** * System settings */posix_setsid();chdir("/");/** * Store PID */$handle = fopen(PIDFILE,'w+');fwrite($handle,posix_getpid());fclose($handle);

The daemon (3)

Wake the daemons

Page 70: CLI, the other SAPI

/** * Perform daemon logic */while(true){ $handle = fopen(DATADIR.'/thijs_'.date('YmdHis'),'w+'); fwrite($handle,'abc123'); fclose($handle); sleep(10);}

The daemon (4)

Wake the daemons

Page 71: CLI, the other SAPI

#!/usr/bin/php<?php/** * Count args */if($argc < 2){ die("\tUsage: php ".basename(__FILE__)." start|stop|status|restart".PHP_EOL);}/** * Init params */define('PIDFILE','/tmp/daemon.pid');define('DAEMONBIN','/home/thijs/test/pcntl/daemon.php');define('DATADIR','/tmp');function startDaemon(){ echo "Starting daemon".PHP_EOL; $start = DAEMONBIN.' -p'.PIDFILE.' -d '.DATADIR; passthru($start);}

The startup script (1)

Wake the daemons

Page 72: CLI, the other SAPI

function stopDaemon(){ if(file_exists(PIDFILE)){ $pid = (int)trim(file_get_contents(PIDFILE)); if(posix_kill($pid,0)){ if(posix_kill($pid,SIGKILL)){ echo 'Daemon stopped'.PHP_EOL; } else { echo 'Error stopping daemon'.PHP_EOL; } } else { echo 'Daemon no longer active, deleting pidfile'.PHP_EOL; } unlink(PIDFILE); } else { echo 'Daemon stopped'.PHP_EOL; }}

The startup script (2)

Wake the daemons

Page 73: CLI, the other SAPI

function statusDaemon(){ if(file_exists(PIDFILE)){ $pid = (int)trim(file_get_contents(PIDFILE)); if(posix_kill($pid,0)){ echo'Daemon is running'.PHP_EOL; } else { echo 'Daemon no longer active, but pidfile still exists'.PHP_EOL; } } else { echo'Daemon is not running'.PHP_EOL; }}

The startup script (3)

Wake the daemons

Page 74: CLI, the other SAPI

switch ($argv[1]){ case 'start': startDaemon(); break; case 'stop': stopDaemon(); break; case 'status': statusDaemon(); break; case 'restart': stopDaemon(); sleep(2); startDaemon(); break; default: die("\tUsage: ".basename(__FILE__)." start | stop | status | restart".PHP_EOL);}

The startup script (4)

Wake the daemons

Page 75: CLI, the other SAPI

Q & A

Page 76: CLI, the other SAPI

THANKS !