Cli the other SAPI confoo11
-
Upload
combell-group -
Category
Technology
-
view
3.257 -
download
2
description
Transcript of Cli the other SAPI confoo11
CLI, the other SAPI
Thijs FerynEvangelist+32 (0)9 218 79 [email protected]
ConfooThursday March 10th 2011Montreal, Canada
php
About me
I’m an Evangelist at Combell
About me
I’m a board member at PHPBenelux
I live in the wonderful city of Bruges
MPBecker -‐ Bruges by Night hWp://www.flickr.com/photos/galverson2/3715965933
Follow me on Twi+er: @ThijsFeryn
Read my blog: h+p://blog.feryn.eu
Give me feedback: h+p://joind.in/2852
SAPI according to Wikipedia
“The Server Applica^on Programming Interface (SAPI) is the generic term used to designate direct module interfaces to web server applica^ons”
SAPI according to Wikipedia
The way you interact with PHP
Common SAPIs
• Apache/Apache 2
• CGI
• FastCGI
• ISAPI
• CLI
• GTK
The CLI SAPI according to php.net
As of version 4.3.0, PHP supports a new SAPI type (Server Applica^on 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) applica^ons with PHP
The CLI SAPI according to php.net
PHP script execu^on via the command line interface
When to use
• In crons
• For batch tasks
• For worker processes
• Daemons
• Process control
• Interac^on with other binaries
CLI 101
CLI 101
The PHP binary
Passing arguments
Reading from STDIN
I/O with pipes
CLI 101Invoking a script with the
PHP binary
php file.php
CLI 101Passing arguments
php file.php arg1 arg2
CLI 101interpreting arguments
<?phpecho "Number of arguments {$argc}\n";foreach($argv as $key=>$argument){ echo "Argument # {$key}: {$argument}\n"; }
CLI 101interpreting arguments
<?phpecho "Number of arguments {$argc}\n";foreach($argv as $key=>$argument){ echo "Argument # {$key}: {$argument}\n"; }
Argument countArgument
array
CLI 101interpreting arguments
$ php args.php arg1 arg2Number of arguments 3Argument # 0: args.phpArgument # 1: arg1Argument # 2: arg2$
The PHP file is an argument too
CLI 101interpreting arguments
$argc
$argv
$_SERVER[‘argc’]
$_SERVER[‘argv’]
!!! register_argc_argv !!!
CLI 101getopt
<?php$arguments = getopt('ab:c::');var_dump($arguments);
CLI 101getopt
<?php$arguments = getopt('ab:c::');var_dump($arguments);
Op^onal value
Flag (no value)
Required value
CLI 101php getopt.php -‐a -‐b 2 -‐c3array(3) { ["a"]=> bool(false) ["b"]=> string(1) "2" ["c"]=> string(1) "3"}
No spacing for op^onal arguments
CLI 101getopt: longopts
<?php$arguments = getopt('',array('arg1','arg2:','arg3::'));var_dump($arguments);
CLI 101php getopt2.php -‐-‐arg1 -‐-‐arg2 123 -‐-‐arg3=xarray(3) { ["arg1"]=> bool(false) ["arg2"]=> string(3) "123" ["arg3"]=> string(1) "x"}
Mind the “=” sign
CLI 101REading From STDIN
<?php$handle = fopen('php://stdin','r');while(!feof($handle)){ $line = trim(fgets($handle)); if(strlen($line) > 0){ echo strrev($line).PHP_EOL; }}fclose($handle);
CLI 101$ cat test.txt | php stdin.php enOowTeerhT$
CLI 101$ cat test.txt | php stdin.php enOowTeerhT$
Output file
Convert output to input with pipes
Comparing the Apache & CLI SAPI
Comparing the Apache & CLI SAPI
Web based SAPI’s• HTTP is a stateless protocol
• Request/response based
• Limited interac^on
• Sessions & cookies as workaround
• Execu^on ^meouts
• Limited request/response size
Comparing the Apache & CLI SAPI
CLI SAPI• Controlable state
• Controlable script execu^on
• Con^nuous interac^on
• No need for sessions
• No execu^on ^meouts
Measuring the state
Input & output
Input & output
Web• $_SERVER
• $_GET
• $_POST
• $_COOKIE
• $_SESSION
• $_ENV
CLI• $_SERVER
• $argc/$argv
• $_ENV
• getopt()
• STDIN/STDOUT/STDERR
Change your mindset
Change your mindset
Don’t use sessions & cookies
Just use local variables
Change your mindset
Don’t “get” your input
Just “read” it
Change your mindset
Don’t bundle your output
You can use distributed output
Change your mindset
If you don’t need HTTP, use CLI
Avoid overhead
E.g. cronjobs
Change your mindset
Current directory != webroot
➡Use dirname(__FILE__)
➡Use chdir()
➡Use getcwd()
CLI scripts are executable everywhere
The PHP binary
php
The PHP binary
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
InteracOve mode (-‐a)
$ php -‐aInteractive shell
php > echo 5+8;13php > function addTwo($n)php > {php { return $n + 2;php { }php > var_dump(addtwo(2));int(4)php >
InteracOve mode (-‐a)
$ php -‐aInteractive shell
php > stri[TAB][TAB]strip_tags stripcslashes stripslashes stristr stripos php > stri
Tab comple^on
Run code (-‐r)
$ php -‐r "echo date('Y-‐m-‐d H:i:s');"2011-‐03-‐02 22:04:45$
Config directory (-‐c)
$ php -‐c /custom/dir/php.ini script.php
Define custom INI seSng (-‐d)
$ php -‐d max_execution_time=20 -‐r '$foo = ini_get("max_execution_time"); var_dump($foo);'string(2) "20"$
Get INI informaOon (-‐i)
$ php -‐i | grep “log_”define_syslog_variables => Off => Offlog_errors => On => Onlog_errors_max_len => 1024 => 1024$
Filtering items
Syntax/lint check (-‐l)
$ php -‐l myFile.phpNo syntax errors detected in myFile.php$
Only checks parse
errors
Module list (-‐m)
$ php -‐m[PHP Modules]bcmathbz2calendarCorectypecurldatedba$
Syntax highlighOng (-‐s)
$ php -‐s helloworld.php > helloworld.html$
<?phpecho "Hello world";
Syntax highlighOng (-‐s)
<?phpecho "Hello world";
<code><span style="color: #000000"><span style="color: #0000BB"><?php<br /></span><span style="color: #007700">echo </span><span style="color: #DD0000">"Hello world"</span><span style="color: #007700">;</span></span>
Version info (-‐v)
$ php -‐vPHP 5.3.3-‐1ubuntu9.3 with Suhosin-‐Patch (cli) (built: Jan 12 2011 16:07:38) Copyright (c) 1997-‐2009 The PHP GroupZend Engine v2.3.0, Copyright (c) 1998-‐2010 Zend Technologies$
FuncOon reflecOon (-‐-‐rf)
$ php -‐-‐rf json_encodeFunction [ <internal:json> function json_encode ] {
-‐ Parameters [2] { Parameter #0 [ <required> $value ] Parameter #1 [ <optional> $options ] }}$
Class reflecOon (-‐-‐rf)
$ php -‐-‐rc stdclassClass [ <internal:Core> class stdClass ] { -‐ Constants [0] { } -‐ Static properties [0] { } -‐ Static methods [0] { } -‐ Properties [0] { } -‐ Methods [0] { }}$
Extension reflecOon (-‐-‐re)
$ php -‐-‐re jsonExtension [ <persistent> extension #20 json version 1.2.1 ] {... -‐ Functions { Function [ <internal:json> function json_encode ] {
-‐ Parameters [2] { Parameter #0 [ <required> $value ] Parameter #1 [ <optional> $options ] } }...}
Extension INI informaOon (-‐-‐ri)
$ php -‐-‐ri pdo
PDO
PDO support => enabledPDO drivers => mysql, sqlite, sqlite2$
Back on track
Back to I/O
STDIN
<?php$handle = fopen('php://stdin','r');while(!feof($handle)){ $line = trim(fgets($handle)); if(strlen($line) > 0){ echo strrev($line).PHP_EOL; }}fclose($handle);
STDIN
<?php$handle = fopen('php://stdin','r');while(!feof($handle)){ $line = trim(fgets($handle)); if(strlen($line) > 0){ echo strrev($line).PHP_EOL; }}fclose($handle);
STDIN
<?php
while(!feof(STDIN)){ $line = trim(fgets(STDIN)); if(strlen($line) > 0){ echo strrev($line).PHP_EOL; }}
STDIN
<?php
while(!feof(STDIN)){ $line = trim(fgets(STDIN)); if(strlen($line) > 0){ echo strrev($line).PHP_EOL; }}
Stream that is opened by default
STDIN
$ php -‐r "var_dump(STDIN);"resource(1) of type (stream)$
The proof !
Stream that is opened by default
Wordcount example
<?php$wordArray = array();while(!feof(STDIN)){ $line = trim(fgets(STDIN)); if(strlen($line) > 0){ foreach(preg_split('/[\s]+/',$line) as $word){ if(!array_key_exists($word,$wordArray)){ $wordArray[$word] = 0; } $wordArray[$word]++; } }}ksort($wordArray);foreach($wordArray as $word=>$count){ echo "$word: $count".PHP_EOL;}
Wordcount example
$ cat wordcount.txt CanadaThijsCanadaThijsThijsConfoo$ cat wordcount.txt | php wordcount.php Canada: 2Confoo: 1Thijs: 3$
STDOUT
<?php$handle = fopen('php://stdout','w');fwrite($handle,'Hello world');fclose($handle);
STDOUT ==
echo
STDOUT
<?phpfwrite(STDOUT,'Hello world');
STDERR
<?php$handle = fopen('php://stderr','w');fwrite($handle,'Serious error!');fclose($handle);
STDERR
<?phpfwrite(STDERR,'Serious error!');
Mixing STDOUT & STDERR
<?phpfwrite(STDOUT,'STDOUT output'.PHP_EOL);fwrite(STDERR,'STDERR output'.PHP_EOL);
$ php stdmix.php STDOUT outputSTDERR output$
Mixing STDOUT & STDERR
<?phpfwrite(STDOUT,'STDOUT output'.PHP_EOL);fwrite(STDERR,'STDERR output'.PHP_EOL);
$ php stdmix.php STDOUT outputSTDERR output$
Looks the same
Mixing STDOUT & STDERR
$ php stdmix.php > /dev/null STDERR output$
$ php stdmix.php &> /dev/null$
Mixing STDOUT & STDERR
$ php stdmix.php > /dev/null STDERR output$
$ php stdmix.php &> /dev/null$
STDOUT is caught
STDOUT & STDERR are
caught
AlternaOve output
<?phpfclose(STDOUT);$handle = fopen(realpath(dirname(__FILE__).'/output.txt'),'a');echo "Hello world!".PHP_EOL;fclose($handle);
AlternaOve output
<?phpfclose(STDOUT);$handle = fopen(realpath(dirname(__FILE__).'/output.txt'),'a');echo "Hello world!".PHP_EOL;fclose($handle);
echo output is wriWen
to file
Piping
$ php -‐r 'for($i=0;$i<10;$i++) echo $i.PHP_EOL;'0123456789$ php -‐r 'for($i=0;$i<10;$i++) echo $i.PHP_EOL;' | wc -‐l 10$
Readline
<?php$name = readline("What's your name: ");$location = readline("Where do you live: ");echo PHP_EOL."Hello $name from $location\n";
$ php readline.php What's your name: ThijsWhere do you live: Belgium
Hello Thijs from Belgium$
Shebang !
#!/usr/bin/php<?phpecho "Hello world".PHP_EOL;
$ chmod +x shebang.php$ ./shebang.phpHello world$
Encore
PCNTL according to php.net
Process Control support in PHP implements the Unix style of process crea^on, program execu^on, signal handling and process termina^on.
Process Control should not be enabled within a web server environment and unexpected results may happen if any
Process Control func^ons are used within a web server environment.
Forking according to Wikipedia
In compu^ng, when a process forks, it creates a copy of itself
Forking
<?php$pid = pcntl_fork();if ($pid == -1) {
//Forking failed} else if ($pid) {
//Parent logic} else {
//Child logic}
Copy program execu^on
PID value determines context
PID of child process
Forking
<?php$pid = pcntl_fork();if ($pid == -1) { die('could not fork');} else if ($pid) { echo "[parent] Starting".PHP_EOL; pcntl_wait($status); echo "[parent] Exiting".PHP_EOL;} else { echo "[child] Starting".PHP_EOL; for($i=0;$i<3;$i++){ echo "[child] Loop $i".PHP_EOL; sleep(1); } echo "[child] Exiting".PHP_EOL; exit;}
Forking
<?php$pid = pcntl_fork();if ($pid == -1) { die('could not fork');} else if ($pid) { echo "[parent] Starting".PHP_EOL; pcntl_wait($status); echo "[parent] Exiting".PHP_EOL;} else { echo "[child] Starting".PHP_EOL; for($i=0;$i<3;$i++){ echo "[child] Loop $i".PHP_EOL; sleep(1); } echo "[child] Exiting".PHP_EOL; exit;}
Perform forking
Wait for child termina^on
Signals
A signal is a limited form of inter-‐process communica^on used in Unix, Unix-‐like, and other POSIX-‐compliant opera^ng
systems. Essen^ally it is an asynchronous no^fica^on sent to a process in order to
no^fy it of an event that occurred.
Signals
<?phpdeclare(ticks = 1);function sig_handler($signo){ switch ($signo) { case SIGTERM: echo PHP_EOL."SIGTERM".PHP_EOL; exit(); break; case SIGINT: echo PHP_EOL."SIGINT".PHP_EOL; exit(); break; }}pcntl_signal(SIGTERM, "sig_handler");pcntl_signal(SIGINT, "sig_handler");sleep(100);
Signals
<?phpdeclare(ticks = 1);function sig_handler($signo){ switch ($signo) { case SIGTERM: echo PHP_EOL."SIGTERM".PHP_EOL; exit(); break; case SIGINT: echo PHP_EOL."SIGINT".PHP_EOL; exit(); break; }}pcntl_signal(SIGTERM, "sig_handler");pcntl_signal(SIGINT, "sig_handler");sleep(100);
Process termina^on
Process interrup^on
Catch signals
POSIX process control funcOons
<?phpecho "[prefork] PID: ".posix_getpid().", parent PID: ".posix_getppid().PHP_EOL;$pid = pcntl_fork();if ($pid == -1) { die('could not fork');} else if ($pid == 0) { echo "[child] 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 process control funcOons
<?phpecho "[prefork] PID: ".posix_getpid().", parent PID: ".posix_getppid().PHP_EOL;$pid = pcntl_fork();if ($pid == -1) { die('could not fork');} else if ($pid == 0) { echo "[child] 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);}
Prefork PID ==
parent PID
Parent PID of parent == session PID
parent PID
child PIDchild PID
POSIX process control funcOons
<?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,SIGTERM); 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 process control funcOons
<?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,SIGTERM); 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;}
“KILL 0” checks existence
Send SIGTERM signal
Child process is dead
Some PCNTL guidelines
✓Detect your CWD
✓Use PID files
✓Control you file privileges
✓Detach you session
✓Avoid rogue child processes
✓Cleanup your garbage
Jeroen Keppens: @jkeppenshttp://www.slideshare.net/jkeppens/php-‐in-‐the-‐dark
Talk dedicated to
process control in PHP
Check this guy out !
Q&A
Thanks !