Lock in $30 Savings on PRO—Offer Ends Soon! ⏳
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
560
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
470
Accelerating OTT video platforms with Varnish - London Video Tech meetup 2020
thijsferyn
0
410
't Oncachebare cachen
thijsferyn
0
410
Caching the uncacheable with Varnish - PHP UG FFM 19
thijsferyn
1
840
Developing cacheable PHP applications - PHP Barcelona 2019
thijsferyn
0
680
Caching the uncacheable with Varnish - FullstackEU 2019
thijsferyn
0
510
Varnish beyond basic web acceleration - Symfony Live Berlin 2019
thijsferyn
0
440
Developing cacheable PHP applications
thijsferyn
0
470
Varnish beyond basic web acceleration - DAHO.AM 2019
thijsferyn
0
450
Other Decks in Technology
See All in Technology
AWS Trainium3 をちょっと身近に感じたい
bigmuramura
1
140
今年のデータ・ML系アップデートと気になるアプデのご紹介
nayuts
1
310
re:Inventで気になったサービスを10分でいけるところまでお話しします
yama3133
1
120
打 造 A I 驅 動 的 G i t H u b ⾃ 動 化 ⼯ 作 流 程
appleboy
0
290
技術以外の世界に『越境』しエンジニアとして進化を遂げる 〜Kotlinへの愛とDevHRとしての挑戦を添えて〜
subroh0508
1
440
Databricks向けJupyter Kernelでデータサイエンティストの開発環境をAI-Readyにする / Data+AI World Tour Tokyo After Party
genda
1
110
MLflowで始めるプロンプト管理、評価、最適化
databricksjapan
1
190
re:Invent 2025 ~何をする者であり、どこへいくのか~
tetutetu214
0
210
プロンプトやエージェントを自動的に作る方法
shibuiwilliam
0
1.1k
AWSセキュリティアップデートとAWSを育てる話
cmusudakeisuke
0
250
Microsoft Agent 365 についてゆっくりじっくり理解する!
skmkzyk
0
250
eBPFとwaruiBPF
sat
PRO
4
2.6k
Featured
See All Featured
Learning to Love Humans: Emotional Interface Design
aarron
274
41k
For a Future-Friendly Web
brad_frost
180
10k
Building Applications with DynamoDB
mza
96
6.8k
Bash Introduction
62gerente
615
210k
Into the Great Unknown - MozCon
thekraken
40
2.2k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.6k
The Power of CSS Pseudo Elements
geoffreycrofte
80
6.1k
Java REST API Framework Comparison - PWX 2021
mraible
34
9k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
A designer walks into a library…
pauljervisheath
210
24k
Visualization
eitanlees
150
16k
Build The Right Thing And Hit Your Dates
maggiecrowley
38
3k
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%!