Cli the other sapi pbc11

92
CLI, the other SAPI php PHPBarcelona Conference Friday October 28th 2011 Barcelona, Spain Thijs Feryn Evangelist +32 (0)9 218 79 06 [email protected]

description

Slides for my pbc11 talks in Barcelona

Transcript of Cli the other sapi pbc11

Page 1: Cli the other sapi pbc11

CLI,  the  other  SAPI

php

PHPBarcelona  ConferenceFriday  October  28th  2011Barcelona,  Spain

Thijs  FerynEvangelist+32  (0)9  218  79  [email protected]

Page 2: Cli the other sapi pbc11

About  me

I’m  an  Evangelist  at  Combell

Page 3: Cli the other sapi pbc11

About  me

I’m  a  board  member  at  PHPBenelux

Page 4: Cli the other sapi pbc11

Follow  me  on  Twi+er:  @ThijsFeryn

Give  me  feedback:  h+p://joind.in/4323

Page 5: Cli the other sapi pbc11
Page 6: Cli the other sapi pbc11

SAPI?

The  way  you  interact  with  PHP

Page 7: Cli the other sapi pbc11

Common  SAPIs

Page 8: Cli the other sapi pbc11

Common  SAPIs

• Apache/Apache  2

• FPM

• FastCGI

• ISAPI

• CLI

• GTK

Page 9: Cli the other sapi pbc11

The  CLI  SAPI

PHP  script  execuYon  via  the  command  line  interface

Page 10: Cli the other sapi pbc11

When  to  use

Page 11: Cli the other sapi pbc11

When  to  use

• In  crons

• For  batch  tasks

• For  worker  processes

• Daemons

• Process  control

• InteracYon  with  other  binaries

Page 12: Cli the other sapi pbc11
Page 13: Cli the other sapi pbc11

CLI 101

Page 14: Cli the other sapi pbc11

CLI 101

The PHP binary

Passing arguments

Reading from STDIN

I/O with pipes

Page 15: Cli the other sapi pbc11

CLI 101Invoking a script with the

PHP binary

php  file.php

Page 16: Cli the other sapi pbc11

CLI 101Passing arguments

php  file.php  arg1  arg2

Page 17: Cli the other sapi pbc11

CLI 101interpreting arguments

<?phpecho "Number of arguments {$argc}\n";foreach($argv as $key=>$argument){    echo "Argument # {$key}: {$argument}\n"; }

Page 18: Cli the other sapi pbc11

CLI 101interpreting arguments

<?phpecho "Number of arguments {$argc}\n";foreach($argv as $key=>$argument){    echo "Argument # {$key}: {$argument}\n"; }

Argument  countArgument  

array

Page 19: Cli the other sapi pbc11

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

Page 20: Cli the other sapi pbc11

CLI 101interpreting arguments

$argc

$argv

$_SERVER[‘argc’]

$_SERVER[‘argv’]

!!! register_argc_argv !!!

Page 21: Cli the other sapi pbc11

CLI 101getopt

<?php$arguments = getopt('ab:c::');var_dump($arguments);

Page 22: Cli the other sapi pbc11

CLI 101getopt

<?php$arguments = getopt('ab:c::');var_dump($arguments);

OpYonal  value

Flag  (no  value)

Required  value

Page 23: Cli the other sapi pbc11

CLI 101php  getopt.php  -­‐a  -­‐b  2  -­‐c3array(3)  {    ["a"]=>    bool(false)    ["b"]=>    string(1)  "2"    ["c"]=>    string(1)  "3"}

No  spacing  for  opYonal  arguments

Page 24: Cli the other sapi pbc11

CLI 101getopt: longopts

<?php$arguments = getopt('',array('arg1','arg2:','arg3::'));var_dump($arguments);

Page 25: Cli the other sapi pbc11

CLI 101php  getopt2.php  -­‐-­‐arg1  -­‐-­‐arg2  123  -­‐-­‐arg3=xarray(3)  {    ["arg1"]=>    bool(false)    ["arg2"]=>    string(3)  "123"    ["arg3"]=>    string(1)  "x"}

Mind  the  “=”  sign

Page 26: Cli the other sapi pbc11

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);

Page 27: Cli the other sapi pbc11

CLI 101$  cat  test.txt  |  php  stdin.php  enOowTeerhT$

Page 28: Cli the other sapi pbc11

CLI 101$  cat  test.txt  |  php  stdin.php  enOowTeerhT$

Output  file

Convert  output  to  input  with  pipes

Page 29: Cli the other sapi pbc11

Comparing  the  Apache  &  CLI  SAPI

Page 30: Cli the other sapi pbc11

Comparing  the  Apache  &  CLI  SAPI

Web  based  SAPI’s• HTTP  is  a  stateless  protocol

• Request/response  based

• Limited  interacYon

• Sessions  &  cookies  as  workaround

• ExecuYon  Ymeouts

• Limited  request/response  size

Page 31: Cli the other sapi pbc11

Comparing  the  Apache  &  CLI  SAPI

CLI  SAPI• Controlable  state

• Controlable  script  execuYon

• ConYnuous  interacYon

• No  need  for  sessions

• No  execuYon  Ymeouts

Page 32: Cli the other sapi pbc11

The  PHP  binary

php

Page 33: Cli the other sapi pbc11

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

Page 34: Cli the other sapi pbc11

InteracLve  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  >

Page 35: Cli the other sapi pbc11

InteracLve  mode  (-­‐a)

$  php  -­‐aInteractive  shell

php  >  stri[TAB][TAB]strip_tags          stripcslashes    stripslashes      stristr                stripos                php  >  stri

Tab  compleYon

Page 36: Cli the other sapi pbc11

Run  code  (-­‐r)

$  php  -­‐r  "echo  date('Y-­‐m-­‐d  H:i:s');"2011-­‐03-­‐02  22:04:45$

Page 37: Cli the other sapi pbc11

Config  directory  (-­‐c)

$  php  -­‐c  /custom/dir/php.ini  script.php

Page 38: Cli the other sapi pbc11

Define  custom  INI  seRng  (-­‐d)

$  php  -­‐d  max_execution_time=20  -­‐r  '$foo  =  ini_get("max_execution_time");  var_dump($foo);'string(2)  "20"$

Page 39: Cli the other sapi pbc11

Get  INI  informaLon  (-­‐i)

$  php  -­‐i  |  grep  “log_”define_syslog_variables  =>  Off  =>  Offlog_errors  =>  On  =>  Onlog_errors_max_len  =>  1024  =>  1024$

Filtering  items

Page 40: Cli the other sapi pbc11

Syntax/lint  check  (-­‐l)

$  php  -­‐l  myFile.phpNo  syntax  errors  detected  in  myFile.php$

Only  checks  parse  

errors

Page 41: Cli the other sapi pbc11

Module  list  (-­‐m)

$  php  -­‐m[PHP  Modules]bcmathbz2calendarCorectypecurldatedba$

Page 42: Cli the other sapi pbc11

Syntax  highlighLng  (-­‐s)

$  php  -­‐s  helloworld.php  >  helloworld.html$

<?phpecho  "Hello  world";

Page 43: Cli the other sapi pbc11

Syntax  highlighLng  (-­‐s)

<?phpecho "Hello world";

<code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">echo&nbsp;</span><span style="color: #DD0000">"Hello&nbsp;world"</span><span style="color: #007700">;</span></span>

Page 44: Cli the other sapi pbc11

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$

Page 45: Cli the other sapi pbc11

FuncLon  reflecLon  (-­‐-­‐rf)

$  php  -­‐-­‐rf  json_encodeFunction  [  <internal:json>  function  json_encode  ]  {

   -­‐  Parameters  [2]  {        Parameter  #0  [  <required>  $value  ]        Parameter  #1  [  <optional>  $options  ]    }}$

Page 46: Cli the other sapi pbc11

Class  reflecLon  (-­‐-­‐rc)

$  php  -­‐-­‐rc  stdclassClass  [  <internal:Core>  class  stdClass  ]  {    -­‐  Constants  [0]  {    }    -­‐  Static  properties  [0]  {    }    -­‐  Static  methods  [0]  {    }    -­‐  Properties  [0]  {    }    -­‐  Methods  [0]  {    }}$

Page 47: Cli the other sapi pbc11

Extension  reflecLon  (-­‐-­‐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  ]            }        }...}

Page 48: Cli the other sapi pbc11

Extension  INI  informaLon  (-­‐-­‐ri)

$  php  -­‐-­‐ri  pdo

PDO

PDO  support  =>  enabledPDO  drivers  =>  mysql,  sqlite,  sqlite2$

Page 49: Cli the other sapi pbc11

Back  on  track

Page 50: Cli the other sapi pbc11

Back  to  I/O

Page 51: Cli the other sapi pbc11

Input  &  output

Web• $_SERVER

• $_GET

• $_POST

• $_COOKIE

• $_SESSION

• $_ENV

CLI• $_SERVER

• $argc/$argv

• $_ENV

• getopt()

• STDIN/STDOUT/STDERR

Page 52: Cli the other sapi pbc11

Change  your  mindset

Page 53: Cli the other sapi pbc11

Change  your  mindset

Don’t  use  sessions  &  cookies

Just  use  local  variables

Page 54: Cli the other sapi pbc11

Change  your  mindset

If  you  don’t  need  HTTP,  use  CLI

Avoid  overhead

E.g.  cronjobs

Page 55: Cli the other sapi pbc11

Change  your  mindset

Current  directory  !=  webroot

➡Use  dirname(__FILE__)

➡Use  chdir()

➡Use  getcwd()

CLI  scripts  are  executable  everywhere

Page 56: Cli the other sapi pbc11

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);

Page 57: Cli the other sapi pbc11

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);

Page 58: Cli the other sapi pbc11

STDIN

<?php

while(!feof(STDIN)){    $line = trim(fgets(STDIN));    if(strlen($line) > 0){        echo strrev($line).PHP_EOL;    }}

Page 59: Cli the other sapi pbc11

STDIN

<?php

while(!feof(STDIN)){    $line = trim(fgets(STDIN));    if(strlen($line) > 0){        echo strrev($line).PHP_EOL;    }}

Stream  that  is  opened  by  default

Page 60: Cli the other sapi pbc11

STDIN

$  php  -­‐r  "var_dump(STDIN);"resource(1)  of  type  (stream)$

The  proof  !

Stream  that  is  opened  by  default

Page 61: Cli the other sapi pbc11

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;}

Page 62: Cli the other sapi pbc11

Wordcount  example

$  cat  wordcount.txt  Barcelona  ThijsThijsBarcelonaThijs  PHPThijsBarcelona$  cat  wordcount.txt    |  php  wordcount.php  PHP:  1Thijs:  4Barcelona:  3$

Page 63: Cli the other sapi pbc11

STDOUT

<?php$handle = fopen('php://stdout','w');fwrite($handle,'Hello world');fclose($handle);

STDOUT  ==  

echo

Page 64: Cli the other sapi pbc11

STDOUT

<?phpfwrite(STDOUT,'Hello world');

Page 65: Cli the other sapi pbc11

STDERR

<?php$handle = fopen('php://stderr','w');fwrite($handle,'Serious error!');fclose($handle);

Page 66: Cli the other sapi pbc11

STDERR

<?phpfwrite(STDERR,'Serious error!');

Page 67: Cli the other sapi pbc11

Mixing  STDOUT  &  STDERR

<?phpfwrite(STDOUT,'STDOUT output'.PHP_EOL);fwrite(STDERR,'STDERR output'.PHP_EOL);

$  php  stdmix.php  STDOUT  outputSTDERR  output$

Page 68: Cli the other sapi pbc11

Mixing  STDOUT  &  STDERR

<?phpfwrite(STDOUT,'STDOUT output'.PHP_EOL);fwrite(STDERR,'STDERR output'.PHP_EOL);

$  php  stdmix.php  STDOUT  outputSTDERR  output$

Looks  the  same

Page 69: Cli the other sapi pbc11

Mixing  STDOUT  &  STDERR

$  php  stdmix.php  >  /dev/null  STDERR  output$

$  php  stdmix.php  &>    /dev/null$

Page 70: Cli the other sapi pbc11

Mixing  STDOUT  &  STDERR

$  php  stdmix.php  >  /dev/null  STDERR  output$

$  php  stdmix.php  &>    /dev/null$

STDOUT  is  caught

STDOUT  &  STDERR  are  

caught

Page 71: Cli the other sapi pbc11

AlternaLve  output

<?phpfclose(STDOUT);$handle = fopen(realpath(dirname(__FILE__).'/output.txt'),'a');echo "Hello world!".PHP_EOL;fclose($handle);

Page 72: Cli the other sapi pbc11

AlternaLve  output

<?phpfclose(STDOUT);$handle = fopen(realpath(dirname(__FILE__).'/output.txt'),'a');echo "Hello world!".PHP_EOL;fclose($handle);

echo  output  is  wrioen  

to  file

Page 73: Cli the other sapi pbc11

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$

Page 74: Cli the other sapi pbc11

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$

Page 75: Cli the other sapi pbc11

Shebang  !

Page 76: Cli the other sapi pbc11

Shebang  !

#!/usr/bin/php<?phpecho "Hello world".PHP_EOL;

$  chmod  +x  shebang.php$  ./shebang.phpHello  world$

Page 77: Cli the other sapi pbc11

Encore

Page 78: Cli the other sapi pbc11

Process  Control  should  not  be  enabled  within  a  web  server  environment  and  unexpected  results  may  happen  if  any  

Process  Control  funcYons  are  used  within  a  web  server  environment.

Page 79: Cli the other sapi pbc11

Forking

<?php$pid = pcntl_fork();if ($pid == -1) {

//Forking failed} else if ($pid) {

//Parent logic} else {

//Child logic}

Copy  program  execuYon

PID  value  determines  context

PID  of  child  process

Page 80: Cli the other sapi pbc11

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;}

Page 81: Cli the other sapi pbc11

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  terminaYon

Page 82: Cli the other sapi pbc11

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);

Page 83: Cli the other sapi pbc11

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  terminaYon

Process  interrupYon

Catch  signals

Page 84: Cli the other sapi pbc11

POSIX  process  control  funcLons<?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);}

Page 85: Cli the other sapi pbc11

POSIX  process  control  funcLons

<?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  PID

child  PID

Page 86: Cli the other sapi pbc11

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;}

Page 87: Cli the other sapi pbc11

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

Page 88: Cli the other sapi pbc11

Jeroen  Keppens:  @jkeppenshttp://www.slideshare.net/jkeppens/

zendcon-­‐2011-­‐php-­‐in-­‐the-­‐dark

Talk  dedicated  to  

process  control  in  PHP

Check  this  guy  out  !

Page 89: Cli the other sapi pbc11

•January  27th  &  28th  2012•Best  Western  Hotel  Ter  Elst  Antwerp  (Belgium)

•Call  For  Papers  CLOSED•Schedule  &  Ycket  announcements  in  a  couple  of  weeks

Page 90: Cli the other sapi pbc11
Page 91: Cli the other sapi pbc11

Q&A

Page 92: Cli the other sapi pbc11

Thanks  !