Home
About
Search
🌐
English Română
  • PHP CLI Input/Output from keyboard, pipe or arguments

    Citește postarea în română

    Feb 26, 2011
    Share on:

    Somewhere in the certification guide there is a chapter dedicated to “streams”.

    A small part of it represents the input, output and error streams from PHP.  C/C++ has famous stdio.h library, but few people knows that input from keyboard is possible in PHP too.

    In short, this can be achieved with PHP://STDIN, PHP://STDOUT and PHP://STDERR.

    As this subject is panicking a lot of developers that are studding for ZCE, let’s get the confusion out. A stream represents a flow of information, just like when your reading and internal or external file using fopen.

    But as a programmer best understands from cod, let’s get to more practical stuff.

    Input

    For input there is PHP://STDIN.

    The next script is reading input from the keyboard:

     1#!/usr/bin/php
     2<?php
     3// initializing the input stream
     4$input = fopen('php://stdin', 'r');
     5
     6// welcome message
     7echo 'Type "exit" and then enter to exit' . PHP_EOL;
     8
     9// reading the stream input
    10while($line = fgets($input, 1024)) {
    11 // exit condition with line terminator
    12 if($line == 'exit' . PHP_EOL) {
    13    echo 'bye bye' . PHP_EOL;
    14    break;
    15 }
    16 // displaying the input from the keyboard
    17 echo 'You say: ' . $line . PHP_EOL;
    18}
    19
    20// close stream
    21fclose($input);
    

    The first line of code is specially for Linux/Unix, and Windows users can remove it.

    The cod above must be placed in to a file, like for instance testStream.php.

    You must have execution rights for that file, witch can be achieved with:

    1chmod +x testStream.php
    2
    

    Then the file can be executed in Linux directly with:

    1$./testStream.php
    2
    

    In Windows you must give the absolute path to PHP, if the path is not already in the system include path:

    1>c:\php\php.exe testStream.php
    2
    

    Notice that the input is with “\n” or “\r\n” at the end of the line, that’s why I’m testing “exit” with the line terminator (PHP_EOL). I’m using PHP_EOL so it can work with both Linux/Unix and Windows.

    Output

    For output there is PHP://STDOUT.

    Unlike input, the output is a lot less relevant. Basically the output is the standard one which can be achieved with echo and print.

    But for educational purpose let’s modify the previous file to use PHP://STDOUT:

     1#!/usr/bin/php
     2<?php
     3// initializing the input stream
     4$input = fopen('php://stdin', 'r');
     5
     6// initializing the output stream
     7$output = fopen('php://stdout', 'w');
     8
     9// welcome message
    10fwrite($output, 'Type "exit" and then enter to exit' . PHP_EOL);
    11// reading the steam input
    12while($line = fgets($input, 1024)) {
    13 // exit condition with line terminator
    14 if($line == 'exit' . PHP_EOL) {
    15    fwrite($output, 'bye bye' . PHP_EOL);
    16    break;
    17 }
    18 // displaying the input from the keyboard
    19 fwrite($output, 'You say: ' . $line . PHP_EOL);
    20}
    21
    22// close input stream
    23fclose($input);
    24
    25// close output stream
    26fclose($output);
    

    Basically there isn’t any change in the script, is just that the output was displayed using PHP://STDOUT explicitly.

    Error

    A more interesting subject then the output is the error stream.

    Basically is more relevant in the Unix/Linux environment, probably is relevant in Windows too but I don’t know how to capture it. If your reading this blog and you know how to do this please leave a comment below.

    And again let’s change the script so that error messages will use the proper stream. I’ll output an error each time the user enters more then 5 characters (I’m sorry but I don’t have a lot of ideas right now):

     1#!/usr/bin/php
     2<?php
     3// initializing the input stream
     4$input = fopen('php://stdin', 'r');
     5
     6// initializing the output stream
     7$output = fopen('php://stdout', 'w');
     8
     9// initializing the error stream
    10$err = fopen('php://stderr', 'w');
    11
    12// welcome message
    13fwrite($output, 'Type "exit" and then enter to exit' . PHP_EOL);
    14
    15// reading the steam input
    16while($line = fgets($input, 1024)) {
    17 // exit condition with line terminator
    18 if($line == 'exit' . PHP_EOL) {
    19    fwrite($output, 'bye bye' . PHP_EOL);
    20    break;
    21 }
    22
    23 if(strlen($line) > 5) {
    24    fwrite($err, 'WARNING! Input greater then 5 characters: ' . $line);
    25    continue;
    26 }
    27
    28 // displaying the input from the keyboard
    29 fwrite($output, 'Ai scris: ' . $line . PHP_EOL);
    30}
    31
    32// close input stream
    33fclose($input);
    34
    35// close output stream
    36fclose($output);
    37
    38// close error stream
    39fclose($err);
    40
    

    By default in Linux error messages are displayed to the screen, but there are scenarios when the errors are redirected for instance to a log file .

    To redirect the error messages to a log file 2>> is used like in the following example:

    1$./testStream 2>>testStream.log
    2
    

    Input from PIPE (|)

    Let’s take the fallowing scenario: the output of a previous operation contains a serious of email addresses that are both valid and invalid. There should be two files: valid.txt with valid addresses and invalid.txt with invalid ones. The email addresses will be send to the script using pipe.

    The list of email addresses will be simulated using a file called email.txt:

    1valid_addres@yahoo.com
    2another_valid@yahoo.co.uk
    3invalid@y.c
    4good@gmail.com
    5invalid addres@hotmail.com
    6foo
    7
    

    The name of the script will be emailTest.php:

     1#!/usr/bin/php
     2<?php
     3// initializing the input stream
     4$input = fopen('php://stdin', 'r');
     5
     6// initializing error stream
     7$err = fopen('php://stderr', 'w');
     8
     9// unlike the previous cases, here is tested for the end of the file
    10// because the input is not coming from keyboard
    11while(!feof($input)) {
    12 // the value is trimmed to remove line terminators
    13 $line = trim(fgets($input, 1024));
    14
    15 // test email address
    16 if(filter_var($line, FILTER_VALIDATE_EMAIL)) {
    17    // direct output, equivalent to php://stdout stream
    18    echo $line . PHP_EOL;
    19 } else {
    20    // invalid addresses are redirected to the php://stderr stream
    21    // to be intercepted later
    22    fputs($err, $line . PHP_EOL);
    23 }
    24}
    25
    26// close input stream
    27fclose($input);
    28
    29// close error stream
    30fclose($err);
    

    For testing I’ll simulate the output of email addresses with the cat command:

    1cat email.txt |./emailTest.php >valid.txt 2>invalid.txt
    2
    

    Now the files valid.txt and invalid.txt from the current directory contain the proper values.

    Processing like this is very useful for complex operations. Basically is an alternative to Shell Scripting (linux) or Batch Scripting (windows), which are not as flexible.

    Script arguments

    Often is useful to send direct arguments to a script to have, for instance, a different functionality.

    Let’s change the previous scenario to receive the name of the file that contains the email address, as a script argument.

    The script arguments are automatically stored in the $argv variable. Notice the first element of the array ($argv[0]) is the name of the script!

    The modified example is as follows:

     1#!/usr/bin/php
     2<?php
     3
     4// the count stars at 1 to eliminate the name of the script
     5for ($i = 1; $i < count($argv); $i++) {
     6  // initializing the input stream
     7  $input = fopen($argv[$i], 'r');
     8
     9  // initializing error stream
    10  $err = fopen('php://stderr', 'w');
    11
    12  if(!$input) {
    13   continue;
    14  }
    15
    16  // unlike the previous cases, here is tested for the end of the file
    17  // because the input is not coming from keyboard
    18  while(!feof($input)) {
    19   // the value is trimmed to remove line terminators
    20   $line = trim(fgets($input, 1024));
    21
    22   // test email address
    23   if(filter_var($line, FILTER_VALIDATE_EMAIL)) {
    24     // direct output, equivalent to php://stdout stream
    25     echo $line . PHP_EOL;
    26   } else {
    27     // invalid addresses are redirected to the php://stderr stream
    28     // to be intercepted later
    29     fputs($err, $line . PHP_EOL);
    30   }
    31  }
    32
    33  // close input stream
    34  fclose($input);
    35
    36  // close error stream
    37  fclose($err);
    38}
    

    Now just run the script with arguments:

    1$./argTest.php email.txt >valid.txt 2>invalid.txt
    

Claudiu Perșoiu

Programming, technoloy and more
Read More

Recent Posts

  • Moving away from Wordpress
  • Custom path for Composer cache
  • Magento2 and the ugly truth
  • A bit of PHP, Go, FFI and holiday spirit
  • How to make use of the Xiaomi Air Conditioning Companion in Home Assistant in only 20 easy steps!
  • How I use Magento2 on my local with Docker and Docker Compose
  • About passion, programming and heating systems
  • The Books for Zend Certified Engineer 2017

PHP 49 MISCELLANEOUS 44 JAVASCRIPT 13 MAGENTO 7 MYSQL 7 BROWSERS 6 DESIGN-PATTERNS 5 LINUX-UNIX 2 WEB-STUFF 2 GO 1

PHP 35 JAVASCRIPT 14 PHP5.3 11 MAGENTO 7 PHP6 7 MYSQL 6 PHP5.4 6 ZCE 6 CERTIFICARE 5 CERTIFICATION 5 CLOSURES 4 DESIGN-PATTERNS 4 HACK 4 ANDROID 3
3D1 ADOBE-AIR2 ANDROID3 ANONYMOUS-FUNCTIONS3 BOOK1 BROWSER2 CARTE1 CERTIFICARE5 CERTIFICATION5 CERTIFIED1 CERTIFIED-DEVELOPER1 CHALLENGE1 CHM1 CLASS1 CLI2 CLOSURES4 CODE-QUALITY1 CODEIGNITER3 COLLECTIONS1 COMPOSER1 CSS1 DEBUG1 DESIGN-PATTERNS4 DEVELOPER1 DEVELOPMENT-TIME1 DOCKER1 DOCKER-COMPOSE1 DOUGLAS-CROCKFORD2 ELEPHPANT2 FACEBOOK2 FFI1 FINALLY1 FIREFOX3 GAMES1 GENERATOR1 GO1 GOOGLE1 GOOGLE-CHROME1 GOOGLE-MAPS1 HACK4 HOMEASSISTANT1 HTML2 HTML-HELP-WORKSHOP1 HTML51 HUG1 HUGO1 INFORMATION_SCHEMA1 INI1 INTERNET-EXPLORER3 IPV41 IPV61 ITERATOR2 JAVASCRIPT14 JQUERY1 LAMBDA1 LINUX1 MAGENTO7 MAGENTO22 MAP1 MINESWEEPER1 MOTIVATION1 MYSQL6 NGINX1 NODE.JS2 NOSQL1 OBSERVER3 OBSERVER-PATTERN1 OOP1 OPERA1 OPTIMIZATION1 ORACLE1 PAGESPEED1 PAIR1 PARSE_INI_FILE1 PHONEGAP2 PHP35 PHP-ELEPHANT2 PHP-FOR-ANDROID1 PHP-GTK1 PHP42 PHP53 PHP5.311 PHP5.46 PHP5.53 PHP5.61 PHP67 PHP7.41 PROGRAMMING1 REVIEW1 ROMANIAN-STEMMER2 SAFARY1 SCALAR-TYPE-HINTING1 SCHEME1 SET1 SHOPPING-CART-PRICE-RULE1 SINGLETON1 SOAP1 SPL2 SQLITE1 SSH1 STACK-TRACE1 STDERR1 STDIN1 STDOUT1 SUN1 SYMFONY2 TEST-TO-SPEECH1 TITANIUM2 TRAITS1 TTS1 UBUNTU1 UNICODE2 UTF-82 VECTOR1 WEBKIT1 WINBINDER1 WINDOWS1 WORDPRESS1 YAHOO3 YAHOO-MAPS1 YAHOO-OPEN-HACK1 YSLOW1 YUI1 ZCE6 ZCE5.31 ZEND3 ZEND-FRAMEWORK3
[A~Z][0~9]

Copyright © 2008 - 2021 CLAUDIU PERȘOIU'S BLOG. All Rights Reserved