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
610
2
Share
CLI, the other SAPI (PHPDAY)
The PHPDay edition of my "CLI, the other SAPI" talk.
Thijs Feryn
May 21, 2012
More Decks by Thijs Feryn
See All by Thijs Feryn
Caching the uncacheable with Varnish - PHP London 2020
thijsferyn
0
510
Accelerating OTT video platforms with Varnish - London Video Tech meetup 2020
thijsferyn
0
440
't Oncachebare cachen
thijsferyn
0
440
Caching the uncacheable with Varnish - PHP UG FFM 19
thijsferyn
1
910
Developing cacheable PHP applications - PHP Barcelona 2019
thijsferyn
0
720
Caching the uncacheable with Varnish - FullstackEU 2019
thijsferyn
0
540
Varnish beyond basic web acceleration - Symfony Live Berlin 2019
thijsferyn
0
470
Developing cacheable PHP applications
thijsferyn
0
500
Varnish beyond basic web acceleration - DAHO.AM 2019
thijsferyn
0
500
Other Decks in Technology
See All in Technology
Choose your own adventure in agentic design patterns
glaforge
0
140
実践ハーネスエンジニアリング:TAKTで実現するAIエージェント制御 / Practical Harness Engineering: AI Agent Control Enabled by TAKT
nrslib
11
4.5k
AI時代 に増える データ活用先
takahal
0
230
Microsoft 365 / Microsoft 365 Copilot : 自分の状態を確認する「ラベル」について
taichinakamura
0
220
[最強DB講義]推薦システム | 基礎編
recsyslab
PRO
1
170
AI와 협업하는 조직으로의 여정
arawn
0
420
M5Stack CoreS3とZephyr(RTOS)で Edge AIっぽいことしてみた
iotengineer22
0
190
弁護士ドットコム株式会社 エンジニア職向け 会社紹介資料
bengo4com
1
150
みんなで作るAWS Tips 100連発 (FinOps編)
schwrzktz
1
300
Keeping Ruby Running on Cygwin
fd0
0
150
ネットワーク運用を楽にするAWS DevOps Agent活用法!! / 20260421 Masaki Okuda
shift_evolve
PRO
2
210
Revisiting [CLS] and Patch Token Interaction in Vision Transformers
yu4u
0
360
Featured
See All Featured
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
320
Un-Boring Meetings
codingconduct
0
270
How to Think Like a Performance Engineer
csswizardry
28
2.5k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.2k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
1.9k
Building AI with AI
inesmontani
PRO
1
900
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
260
Darren the Foodie - Storyboard
khoart
PRO
3
3.3k
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
220
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
122
21k
Deep Space Network (abreviated)
tonyrice
0
120
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%!