$30 off During Our Annual Pro Sale. View Details »

CLI, the other SAPI (PHPDAY)

CLI, the other SAPI (PHPDAY)

The PHPDay edition of my "CLI, the other SAPI" talk.

Thijs Feryn

May 21, 2012
Tweet

More Decks by Thijs Feryn

Other Decks in Technology

Transcript

  1. CLI,%the%other%SAPI
    Thijs%Feryn
    Evangelist
    +32%(0)9%218%79%06
    [email protected]
    php

    View Slide

  2. About%me
    I’m%an%Evangelist%at%Combell

    View Slide

  3. About%me
    I’m%a%board%member%at%PHPBenelux

    View Slide

  4. Follow%me%on%Twi+er:%@ThijsFeryn
    Give%me%feedback:%h+p://joind.in/6393

    View Slide

  5. View Slide

  6. SAPI?
    The%way%you%interact%with%PHP

    View Slide

  7. Common%SAPIs

    View Slide

  8. Common%SAPIs
    • Apache/Apache%2
    • FPM
    • FastCGI
    • ISAPI
    • CLI
    • GTK

    View Slide

  9. The%CLI%SAPI
    PHP%script%execuWon%via%the%command%line%interface

    View Slide

  10. When%to%use

    View Slide

  11. When%to%use
    • In%crons
    • For%batch%tasks
    • For%worker%processes
    • Daemons
    • Process%control
    • InteracWon%with%other%binaries

    View Slide

  12. View Slide

  13. CLI 101

    View Slide

  14. CLI 101
    The PHP binary
    Passing arguments
    Reading from STDIN
    I/O with pipes

    View Slide

  15. CLI 101
    Invoking a script with the PHP
    binary
    php#file.php

    View Slide

  16. CLI 101
    Passing arguments
    php#file.php#arg1#arg2

    View Slide

  17. CLI 101
    interpreting arguments
    echo "Number of arguments {$argc}\n";
    foreach($argv as $key=>$argument){
    echo "Argument # {$key}: {$argument}\n";
    }

    View Slide

  18. CLI 101
    interpreting arguments
    echo "Number of arguments {$argc}\n";
    foreach($argv as $key=>$argument){
    echo "Argument # {$key}: {$argument}\n";
    }
    Argument%
    count
    Argument%
    array

    View Slide

  19. 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

    View Slide

  20. CLI 101
    interpreting arguments
    $argc
    $argv
    $_SERVER[‘argc’]
    $_SERVER[‘argv’]
    !!! register_argc_argv !!!

    View Slide

  21. CLI 101
    getopt
    $arguments = getopt('ab:c::');
    var_dump($arguments);

    View Slide

  22. CLI 101
    getopt
    $arguments = getopt('ab:c::');
    var_dump($arguments);
    OpWonal%
    value
    Flag%
    (no%value)
    Required%
    value

    View Slide

  23. 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

    View Slide

  24. CLI 101
    getopt: longopts
    $arguments = getopt('',array('a
    rg1','arg2:','arg3::'));
    var_dump($arguments);

    View Slide

  25. 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

    View Slide

  26. CLI 101
    REading From STDIN
    $handle = fopen('php://stdin','r');
    while(!feof($handle)){
    $line = trim(fgets($handle));
    if(strlen($line) > 0){
    echo strrev($line).PHP_EOL;
    }
    }
    fclose($handle);

    View Slide

  27. CLI 101
    $"cat"test.txt"|"php"stdin.php"
    enO
    owT
    eerhT
    $

    View Slide

  28. CLI 101
    $"cat"test.txt"|"php"stdin.php"
    enO
    owT
    eerhT
    $
    Output%
    file
    Convert%
    output%to%
    input%with%
    pipes

    View Slide

  29. Comparing%the%Apache%&%CLI%SAPI

    View Slide

  30. 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

    View Slide

  31. Comparing%the%Apache%&%CLI%SAPI
    CLI%SAPI
    • Controlable%state
    • Controlable%script%execuWon
    • ConWnuous%interacWon
    • No%need%for%sessions
    • No%execuWon%Wmeouts

    View Slide

  32. The%PHP%binary
    php

    View Slide

  33. The%PHP%binary
    Usage:"php"[options]"[:f]""[::]"[args...]
    """""""php"[options]":r""[::]"[args...]
    """""""php"[options]"[:B"]":R""
    [:E"]"[::]"[args...]
    """""""php"[options]"[:B"]":F""
    [:E"]"[::]"[args...]
    """""""php"[options]"::"[args...]
    """""""php"[options]":a

    View Slide

  34. 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">

    View Slide

  35. InteracLve%mode%("a)
    $"php":a
    Interactive"shell
    php">"stri[TAB][TAB]
    strip_tags"""""stripcslashes""
    stripslashes"""stristr""""""""
    stripos""""""""
    php">"stri
    Tab%
    compleWon

    View Slide

  36. Run%code%("r)
    $"php":r""echo"date('Y:m:d"H:i:s');"
    2011:03:02"22:04:45
    $

    View Slide

  37. Config%directory%("c)
    $"php":c"/custom/dir/php.ini"script.php

    View Slide

  38. Define%custom%INI%seRng%("d)
    $"php":d"max_execution_time=20":r"'$foo"="
    ini_get("max_execution_time");"
    var_dump($foo);'
    string(2)""20"
    $

    View Slide

  39. 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

    View Slide

  40. Syntax/lint%check%("l)
    $"php":l"myFile.php
    No"syntax"errors"detected"in"myFile.php
    $
    Only%
    checks%parse%
    errors

    View Slide

  41. Module%list%("m)
    $"php":m
    [PHP"Modules]
    bcmath
    bz2
    calendar
    Core
    ctype
    curl
    date
    dba
    $

    View Slide

  42. Syntax%highlighLng%("s)
    $"php":s"helloworld.php">"helloworld.html
    $
    echo""Hello"world";

    View Slide

  43. Syntax%highlighLng%("s)
    echo "Hello world";

    <?php
    >echo style="color:
    #DD0000">"Hello world"style="color: #007700">;

    View Slide

  44. 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
    $

    View Slide

  45. FuncLon%reflecLon%(""rf)
    $"php"::rf"json_encode
    Function"[""function"
    json_encode"]"{
    "":"Parameters"[2]"{
    """"Parameter"#0"[""$value"]
    """"Parameter"#1"[""$options"]
    ""}
    }
    $

    View Slide

  46. Class%reflecLon%(""rc)
    $"php"::rc"stdclass
    Class"[""class"stdClass"]"{
    "":"Constants"[0]"{
    ""}
    "":"Static"properties"[0]"{
    ""}
    "":"Static"methods"[0]"{
    ""}
    "":"Properties"[0]"{
    ""}
    "":"Methods"[0]"{
    ""}
    }
    $

    View Slide

  47. Extension%reflecLon%(""re)
    $"php"::re"json
    Extension"[""extension"#20"json"version"1.2.1"]"{
    ...
    "":"Functions"{
    """"Function"[""function"json_encode"]"{
    """""":"Parameters"[2]"{
    """"""""Parameter"#0"[""$value"]
    """"""""Parameter"#1"[""$options"]
    """"""}
    """"}
    ...
    }

    View Slide

  48. Extension%INI%informaLon%(""ri)
    $"php"::ri"pdo
    PDO
    PDO"support"=>"enabled
    PDO"drivers"=>"mysql,"sqlite,"sqlite2
    $

    View Slide

  49. 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

    View Slide

  50. 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

    View Slide

  51. 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

    View Slide

  52. 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

    View Slide

  53. Back%on%track

    View Slide

  54. Back%to%I/O

    View Slide

  55. Input%&%output
    Web
    • $_SERVER
    • $_GET
    • $_POST
    • $_COOKIE
    • $_SESSION
    • $_ENV
    CLI
    • $_SERVER
    • $argc/$argv
    • $_ENV
    • getopt()
    • STDIN/STDOUT/
    STDERR

    View Slide

  56. Change%your%mindset

    View Slide

  57. Change%your%mindset
    Don’t%use%sessions%&%cookies
    Just%use%local%variables

    View Slide

  58. Change%your%mindset
    If%you%don’t%need%HTTP,%use%CLI
    Avoid%overhead
    E.g.%
    cronjobs

    View Slide

  59. Change%your%mindset
    Current%directory%!=%webroot
    ➡Use%dirname(__FILE__)
    ➡Use%chdir()
    ➡Use%getcwd()
    CLI%
    scripts%are%
    executable%
    everywhere

    View Slide

  60. STDIN
    $handle = fopen('php://stdin','r');
    while(!feof($handle)){
    $line = trim(fgets($handle));
    if(strlen($line) > 0){
    echo strrev($line).PHP_EOL;
    }
    }
    fclose($handle);

    View Slide

  61. STDIN
    $handle = fopen('php://stdin','r');
    while(!feof($handle)){
    $line = trim(fgets($handle));
    if(strlen($line) > 0){
    echo strrev($line).PHP_EOL;
    }
    }
    fclose($handle);

    View Slide

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

    View Slide

  63. STDIN
    while(!feof(STDIN)){
    $line = trim(fgets(STDIN));
    if(strlen($line) > 0){
    echo strrev($line).PHP_EOL;
    }
    }
    Stream%
    that%is%opened%
    by%default

    View Slide

  64. STDIN
    $"php":r""var_dump(STDIN);"
    resource(1)"of"type"(stream)
    $
    The%
    proof%!
    Stream%
    that%is%opened%
    by%default

    View Slide

  65. Wordcount%example
    $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;
    }

    View Slide

  66. 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
    $

    View Slide

  67. STDOUT
    $handle = fopen('php://stdout','w');
    fwrite($handle,'Hello world');
    fclose($handle);
    STDOUT%
    ==%
    echo

    View Slide

  68. STDOUT
    fwrite(STDOUT,'Hello world');

    View Slide

  69. STDERR
    $handle = fopen('php://stderr','w');
    fwrite($handle,'Serious error!');
    fclose($handle);

    View Slide

  70. STDERR
    fwrite(STDERR,'Serious error!');

    View Slide

  71. Mixing%STDOUT%&%STDERR
    fwrite(STDOUT,'STDOUT output'.PHP_EOL);
    fwrite(STDERR,'STDERR output'.PHP_EOL);
    $"php"stdmix.php"
    STDOUT"output
    STDERR"output
    $

    View Slide

  72. Mixing%STDOUT%&%STDERR
    fwrite(STDOUT,'STDOUT output'.PHP_EOL);
    fwrite(STDERR,'STDERR output'.PHP_EOL);
    $"php"stdmix.php"
    STDOUT"output
    STDERR"output
    $
    Looks%
    the%same

    View Slide

  73. Mixing%STDOUT%&%STDERR
    $"php"stdmix.php">"/dev/null"
    STDERR"output
    $
    $"php"stdmix.php"&>""/dev/null
    $

    View Slide

  74. Mixing%STDOUT%&%STDERR
    $"php"stdmix.php">"/dev/null"
    STDERR"output
    $
    $"php"stdmix.php"&>""/dev/null
    $
    STDOUT%
    is%caught
    STDOUT%
    &%STDERR%are%
    caught

    View Slide

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

    View Slide

  76. AlternaLve%output
    fclose(STDOUT);
    $handle = fopen(realpath(dirname(__FILE__).'/
    output.txt'),'a');
    echo "Hello world!".PHP_EOL;
    fclose($handle);
    echo%
    output%is%wriqen%
    to%file

    View Slide

  77. 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
    $

    View Slide

  78. Readline
    $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
    $

    View Slide

  79. Shebang%!

    View Slide

  80. Shebang%!
    #!/usr/bin/php
    echo "Hello world".PHP_EOL;
    $"chmod"+x"shebang.php
    $"./shebang.php
    Hello"world
    $

    View Slide

  81. Encore

    View Slide

  82. 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.

    View Slide

  83. Forking
    $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

    View Slide

  84. Forking
    $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;
    }

    View Slide

  85. Forking
    $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

    View Slide

  86. Signals
    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);

    View Slide

  87. Signals
    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

    View Slide

  88. POSIX%process%control%funcLons
    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);

    View Slide

  89. POSIX%process%control%funcLons
    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

    View Slide

  90. POSIX%process%control%funcLons
    $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;
    }

    View Slide

  91. POSIX%process%control%funcLons
    $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

    View Slide

  92. Jeroen%Keppens:%@jkeppens
    http://www.slideshare.net/jkeppens/phpYinYtheYdark
    Talk%
    dedicated%to%
    process%control%
    in%PHP
    Check%this%
    guy%out%!

    View Slide

  93. View Slide

  94. Q&A

    View Slide

  95. Thanks%!

    View Slide