Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
CLI, the other SAPI (PHPDAY)
Search
Thijs Feryn
May 21, 2012
Technology
2
440
CLI, the other SAPI (PHPDAY)
The PHPDay edition of my "CLI, the other SAPI" talk.
Thijs Feryn
May 21, 2012
Tweet
Share
More Decks by Thijs Feryn
See All by Thijs Feryn
Caching the uncacheable with Varnish - PHP London 2020
thijsferyn
0
340
Accelerating OTT video platforms with Varnish - London Video Tech meetup 2020
thijsferyn
0
280
't Oncachebare cachen
thijsferyn
0
250
Caching the uncacheable with Varnish - PHP UG FFM 19
thijsferyn
1
480
Developing cacheable PHP applications - PHP Barcelona 2019
thijsferyn
0
520
Caching the uncacheable with Varnish - FullstackEU 2019
thijsferyn
0
390
Varnish beyond basic web acceleration - Symfony Live Berlin 2019
thijsferyn
0
320
Developing cacheable PHP applications
thijsferyn
0
330
Varnish beyond basic web acceleration - DAHO.AM 2019
thijsferyn
0
300
Other Decks in Technology
See All in Technology
Gitlab本から学んだこと - そーだいなるプレイバック / gitlab-book
soudai
3
130
Postman v10リリース後を振り返る / Looking back at Postman v10 after release
yokawasa
1
160
ユーザーストーリーのレビューを自動化したみたの
bun913
1
420
複雑な構成要素を持つUIとの向き合い方 〜新・支出グラフでの実例〜 / B43 TECH TALK
nakamuuu
0
140
どうするコスト最適化のトレードオフ
tetsuyaooooo
1
510
Google Cloud Next '24でブログを10本書いた方法と勉強会を沸かせた方法
yasumuusan
0
290
現代CSSフレームワークの内部実装とその仕組み
poteboy
8
3.6k
Next'24 事例セッションの紹介とクラウド資格を活用したキャリア形成について語りMuscle
yasumuusan
1
440
障害対応をちょっとずつよくしていくための 演習の作りかた
heleeen
0
140
AWSに詳しくない人でも始められるコスト最適化ガイド
yuhta28
0
190
Compose Compiler Metricsを使った実践的なコードレビュー
tomorrowkey
1
220
Google Cloud Next '24 Recap(Cloud Run/k8s)
mokocm
0
110
Featured
See All Featured
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
17
1.4k
10 Git Anti Patterns You Should be Aware of
lemiorhan
648
58k
Fantastic passwords and where to find them - at NoRuKo
philnash
37
2.5k
Fashionably flexible responsive web design (full day workshop)
malarkey
398
65k
Code Review Best Practice
trishagee
55
15k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
9
8.3k
Building Flexible Design Systems
yeseniaperezcruz
319
37k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
226
51k
How GitHub (no longer) Works
holman
304
140k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
2
3.4k
What’s in a name? Adding method to the madness
productmarketing
PRO
16
2.6k
The Mythical Team-Month
searls
216
42k
Transcript
CLI,%the%other%SAPI Thijs%Feryn Evangelist +32%(0)9%218%79%06
[email protected]
php
About%me I’m%an%Evangelist%at%Combell
About%me I’m%a%board%member%at%PHPBenelux
Follow%me%on%Twi+er:%@ThijsFeryn Give%me%feedback:%h+p://joind.in/6393
None
SAPI? The%way%you%interact%with%PHP
Common%SAPIs
Common%SAPIs • Apache/Apache%2 • FPM • FastCGI • ISAPI •
CLI • GTK
The%CLI%SAPI PHP%script%execuWon%via%the%command%line%interface
When%to%use
When%to%use • In%crons • For%batch%tasks • For%worker%processes • Daemons •
Process%control • InteracWon%with%other%binaries
None
CLI 101
CLI 101 The PHP binary Passing arguments Reading from STDIN
I/O with pipes
CLI 101 Invoking a script with the PHP binary php#file.php
CLI 101 Passing arguments php#file.php#arg1#arg2
CLI 101 interpreting arguments <?php echo "Number of arguments {$argc}\n";
foreach($argv as $key=>$argument){ echo "Argument # {$key}: {$argument}\n"; }
CLI 101 interpreting arguments <?php echo "Number of arguments {$argc}\n";
foreach($argv as $key=>$argument){ echo "Argument # {$key}: {$argument}\n"; } Argument% count Argument% array
CLI 101 interpreting arguments $"php"args.php"arg1"arg2 Number"of"arguments"3 Argument"#"0:"args.php Argument"#"1:"arg1 Argument"#"2:"arg2 $
The% PHP%file%is%an% argument%too
CLI 101 interpreting arguments $argc $argv $_SERVER[‘argc’] $_SERVER[‘argv’] !!! register_argc_argv
!!!
CLI 101 getopt <?php $arguments = getopt('ab:c::'); var_dump($arguments);
CLI 101 getopt <?php $arguments = getopt('ab:c::'); var_dump($arguments); OpWonal% value
Flag% (no%value) Required% value
CLI 101 php"getopt.php":a":b"2":c3 array(3)"{ ""["a"]=> ""bool(false) ""["b"]=> ""string(1)""2" ""["c"]=> ""string(1)""3"
} No% spacing%for% opWonal% arguments
CLI 101 getopt: longopts <?php $arguments = getopt('',array('a rg1','arg2:','arg3::')); var_dump($arguments);
CLI 101 php"getopt2.php"::arg1"::arg2"123"::arg3=x array(3)"{ ""["arg1"]=> ""bool(false) ""["arg2"]=> ""string(3)""123" ""["arg3"]=> ""string(1)""x"
} Mind% the%“=”%sign
CLI 101 REading 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" enO owT eerhT $
CLI 101 $"cat"test.txt"|"php"stdin.php" enO owT eerhT $ 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%interacWon • Sessions%&%cookies%as%workaround
• ExecuWon%Wmeouts • Limited%request/response%size
Comparing%the%Apache%&%CLI%SAPI CLI%SAPI • Controlable%state • Controlable%script%execuWon • ConWnuous%interacWon • No%need%for%sessions
• No%execuWon%Wmeouts
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
InteracLve%mode%("a) $"php":a Interactive"shell php">"echo"5+8; 13 php">"function"addTwo($n) php">"{ php"{"return"$n"+"2; php"{"} php">"var_dump(addtwo(2));
int(4) php">
InteracLve%mode%("a) $"php":a Interactive"shell php">"stri[TAB][TAB] strip_tags"""""stripcslashes"" stripslashes"""stristr"""""""" stripos"""""""" php">"stri Tab% compleWon
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%seRng%("d) $"php":d"max_execution_time=20":r"'$foo"=" ini_get("max_execution_time");" var_dump($foo);' string(2)""20" $
Get%INI%informaLon%("i) $"php":i"|"grep"“log_” define_syslog_variables"=>"Off"=>"Off log_errors"=>"On"=>"On log_errors_max_len"=>"1024"=>"1024 $ Filtering% items
Syntax/lint%check%("l) $"php":l"myFile.php No"syntax"errors"detected"in"myFile.php $ Only% checks%parse% errors
Module%list%("m) $"php":m [PHP"Modules] bcmath bz2 calendar Core ctype curl date
dba $
Syntax%highlighLng%("s) $"php":s"helloworld.php">"helloworld.html $ <?php echo""Hello"world";
Syntax%highlighLng%("s) <?php echo "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":v PHP"5.3.3:1ubuntu9.3"with"Suhosin:Patch" (cli)"(built:"Jan"12"2011"16:07:38)" Copyright"(c)"1997:2009"The"PHP"Group Zend"Engine"v2.3.0,"Copyright"(c)"1998:2010" Zend"Technologies $
FuncLon%reflecLon%(""rf) $"php"::rf"json_encode Function"["<internal:json>"function" json_encode"]"{ "":"Parameters"[2]"{ """"Parameter"#0"["<required>"$value"] """"Parameter"#1"["<optional>"$options"] ""} } $
Class%reflecLon%(""rc) $"php"::rc"stdclass Class"["<internal:Core>"class"stdClass"]"{ "":"Constants"[0]"{ ""} "":"Static"properties"[0]"{ ""} "":"Static"methods"[0]"{ ""} "":"Properties"[0]"{
""} "":"Methods"[0]"{ ""} } $
Extension%reflecLon%(""re) $"php"::re"json Extension"["<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%informaLon%(""ri) $"php"::ri"pdo PDO PDO"support"=>"enabled PDO"drivers"=>"mysql,"sqlite,"sqlite2 $
BuiltYin%webserver%("S) $"php":S"localhost:1234 PHP"5.4.0"Development"Server"started"at"Mon"May" 14"09:43:28"2012 Listening"on"localhost:1234 Document"root"is"/var/www/cli.dev Press"Ctrl:C"to"quit. $ PHP% 5.4
BuiltYin%webserver%("S) [Mon"May"14"09:44:42"2012]"192.168.72.1:53147" [200]:"/ [Mon"May"14"09:44:42"2012]"192.168.72.1:53148" [200]:"/?=PHPE9568F34:D428:11d2:A769:00AA001ACF42 [Mon"May"14"09:44:42"2012]"192.168.72.1:53149" [200]:"/?=PHPE9568F35:D428:11d2:A769:00AA001ACF42
BuiltYin%webserver%("S) $"php":S"localhost:1234"router.php PHP"5.4.0"Development"Server"started"at"Mon"May" 14"09:43:28"2012 Listening"on"localhost:1234 Document"root"is"/path/to/docroot Press"Ctrl:C"to"quit. $ Router
BuiltYin%webserver%("t) $"php":S"localhost:1234":t"/path/to/docroot PHP"5.4.0"Development"Server"started"at"Mon"May" 14"09:43:28"2012 Listening"on"localhost:1234 Document"root"is"/path/to/docroot Press"Ctrl:C"to"quit. $ Custom% docroot
Back%on%track
Back%to%I/O
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 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
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" Italy"Thijs Thijs Italy Thijs"PHPDAY Thijs Italy $"cat"wordcount.txt""|"php"wordcount.php" PHPDAY:"1
Thijs:"4 Italy:"3 $
STDOUT <?php $handle = fopen('php://stdout','w'); fwrite($handle,'Hello world'); fclose($handle); STDOUT% ==%
echo
STDOUT <?php fwrite(STDOUT,'Hello world');
STDERR <?php $handle = fopen('php://stderr','w'); fwrite($handle,'Serious error!'); fclose($handle);
STDERR <?php fwrite(STDERR,'Serious error!');
Mixing%STDOUT%&%STDERR <?php fwrite(STDOUT,'STDOUT output'.PHP_EOL); fwrite(STDERR,'STDERR output'.PHP_EOL); $"php"stdmix.php" STDOUT"output STDERR"output $
Mixing%STDOUT%&%STDERR <?php fwrite(STDOUT,'STDOUT output'.PHP_EOL); fwrite(STDERR,'STDERR output'.PHP_EOL); $"php"stdmix.php" STDOUT"output STDERR"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
AlternaLve%output <?php fclose(STDOUT); $handle = fopen(realpath(dirname(__FILE__).'/ output.txt'),'a'); echo "Hello world!".PHP_EOL;
fclose($handle);
AlternaLve%output <?php fclose(STDOUT); $handle = fopen(realpath(dirname(__FILE__).'/ output.txt'),'a'); echo "Hello world!".PHP_EOL;
fclose($handle); echo% output%is%wriqen% to%file
Piping $"php":r"'for($i=0;$i<10;$i++)"echo"$i.PHP_EOL;' 0 1 2 3 4 5 6 7
8 9 $"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:"Thijs Where"do"you"live:"Belgium Hello"Thijs"from"Belgium $
Shebang%!
Shebang%! #!/usr/bin/php <?php echo "Hello world".PHP_EOL; $"chmod"+x"shebang.php $"./shebang.php Hello"world $
Encore
Process%Control%should%not%be%enabled% within%a%web%server%environment%and% unexpected%results%may%happen%if%any% Process%Control%funcWons%are%used%within% a%web%server%environment.
Forking <?php $pid = pcntl_fork(); if ($pid == -1) {
//Forking failed } else if ($pid) { //Parent logic } else { //Child logic } Copy% program% execuWon 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% terminaWon
Signals <?php declare(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 <?php declare(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% terminaWon Process% interrupWon Catch%signals
POSIX%process%control%funcLons <?php echo "[prefork] PID: ".posix_getpid().", parent PID: ".posix_getppid().PH P_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%funcLons <?php echo "[prefork] PID: ".posix_getpid().", parent PID: ".posix_getppid().PH P_EOL;
$pid = pcntl_fork(); if ($pid == -1) { die('could not fork'); } else if ($pid == 0) { echo "[child] PID: ".posix_getpid().", paren t PID: ".posix_getppid().PHP_EOL; exit; } else { echo "[parent] PID: ".posix_getpid().", pare nt PID: ".posix_getppid().PHP_EOL; pcntl_wait($status); } Prefork%PID% ==% parent%PID Parent%PID% of%parent%==% session%PID parent% PID child%PID child%PID
POSIX%process%control%funcLons <?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%funcLons <?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
Jeroen%Keppens:%@jkeppens http://www.slideshare.net/jkeppens/phpYinYtheYdark Talk% dedicated%to% process%control% in%PHP Check%this% guy%out%!
None
Q&A
Thanks%!