Claudiu Persoiu

Blog-ul lui Claudiu Persoiu


Archive for 26 February 2011

PHP CLI Input/Output from keyboard, pipe or arguments

without comments

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:

#!/usr/bin/php
<?php
// initializing the input stream
$input = fopen('php://stdin', 'r');

// welcome message
echo 'Type "exit" and then enter to exit' . PHP_EOL;

// reading the stream input
while($line = fgets($input, 1024)) {
 // exit condition with line terminator
 if($line == 'exit' . PHP_EOL) {
    echo 'bye bye' . PHP_EOL;
    break;
 }
 // displaying the input from the keyboard
 echo 'You say: ' . $line . PHP_EOL;
}

// close stream
fclose($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:

chmod +x testStream.php

Then the file can be executed in Linux directly with:

$./testStream.php

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

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

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:

#!/usr/bin/php
<?php
// initializing the input stream
$input = fopen('php://stdin', 'r');

// initializing the output stream
$output = fopen('php://stdout', 'w');

// welcome message
fwrite($output, 'Type "exit" and then enter to exit' . PHP_EOL);
// reading the steam input
while($line = fgets($input, 1024)) {
 // exit condition with line terminator
 if($line == 'exit' . PHP_EOL) {
    fwrite($output, 'bye bye' . PHP_EOL);
    break;
 }
 // displaying the input from the keyboard
 fwrite($output, 'You say: ' . $line . PHP_EOL);
}

// close input stream
fclose($input);

// close output stream
fclose($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):

#!/usr/bin/php
<?php
// initializing the input stream
$input = fopen('php://stdin', 'r');

// initializing the output stream
$output = fopen('php://stdout', 'w');

// initializing the error stream
$err = fopen('php://stderr', 'w');

// welcome message
fwrite($output, 'Type "exit" and then enter to exit' . PHP_EOL);

// reading the steam input
while($line = fgets($input, 1024)) {
 // exit condition with line terminator
 if($line == 'exit' . PHP_EOL) {
    fwrite($output, 'bye bye' . PHP_EOL);
    break;
 }

 if(strlen($line) > 5) {
    fwrite($err, 'WARNING! Input greater then 5 characters: ' . $line);
    continue;
 }

 // displaying the input from the keyboard
 fwrite($output, 'Ai scris: ' . $line . PHP_EOL);
}

// close input stream
fclose($input);

// close output stream
fclose($output);

// close error stream
fclose($err);

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:

$./testStream 2>>testStream.log

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:

valid_addres@yahoo.com
another_valid@yahoo.co.uk
invalid@y.c
good@gmail.com
invalid addres@hotmail.com
foo

The name of the script will be emailTest.php:

#!/usr/bin/php
<?php
// initializing the input stream
$input = fopen('php://stdin', 'r');

// initializing error stream
$err = fopen('php://stderr', 'w');

// unlike the previous cases, here is tested for the end of the file
// because the input is not coming from keyboard
while(!feof($input)) {
 // the value is trimmed to remove line terminators
 $line = trim(fgets($input, 1024));

 // test email address
 if(filter_var($line, FILTER_VALIDATE_EMAIL)) {
    // direct output, equivalent to php://stdout stream
    echo $line . PHP_EOL;
 } else {
    // invalid addresses are redirected to the php://stderr stream
    // to be intercepted later
    fputs($err, $line . PHP_EOL);
 }
}

// close input stream
fclose($input);

// close error stream
fclose($err);

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

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

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:

#!/usr/bin/php
<?php

// the count stars at 1 to eliminate the name of the script
for ($i = 1; $i < count($argv); $i++) {
  // initializing the input stream
  $input = fopen($argv[$i], 'r');

  // initializing error stream
  $err = fopen('php://stderr', 'w');

  if(!$input) {
   continue;
  }

  // unlike the previous cases, here is tested for the end of the file
  // because the input is not coming from keyboard
  while(!feof($input)) {
   // the value is trimmed to remove line terminators
   $line = trim(fgets($input, 1024));

   // test email address
   if(filter_var($line, FILTER_VALIDATE_EMAIL)) {
     // direct output, equivalent to php://stdout stream
     echo $line . PHP_EOL;
   } else {
     // invalid addresses are redirected to the php://stderr stream
     // to be intercepted later
     fputs($err, $line . PHP_EOL);
   }
  }

  // close input stream
  fclose($input);

  // close error stream
  fclose($err);
}

Now just run the script with arguments:

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

Written by Claudiu Persoiu

26 February 2011 at 2:35 PM

Posted in PHP

Tagged with , , , ,

100+ PHP ZCE certified developers in Romania

with 4 comments

In 2008 when I had my first certification exam there were 22 Zend Certified Engineers in Romania, I was number 23.

With time looks like more people took the exam, and this week the number of 100 Zend Certified Engineers was exceeded!

After a search of PHP ZCE, full of joy, I find that the 100th certified web developer in Romania is actually my colleague and friend Emanuel Croitoru,  whom I’ve tortured for weeks on end with: “don’t worry, is easy”.

When the time came to really study the manual it didn’t look that simple. 🙂

But after all, the determination to make this step is just another reason that a ZCE is trying to become a good web developer!

Written by Claudiu Persoiu

25 February 2011 at 10:38 PM

Posted in PHP

Tagged with , , ,

Is official, there are no more IPv4 addresses!

without comments

Since I’ve first learned about IPs, I’ve wandered when will the possible number of addresses will run out. Now is official, there are no more IPv4 addresses!

ICANN (Internet Corporation for Assigned Names and Numbers) has officially announced on February 3 that the las IPv4 addresses have been allocated. Off course they haven’t been allocated directly to the users, but they will be used by ISPs.

But what will happen if there are no more IP addresses? Well, as this has become obvious some ware in the evolutionary process of the Internet IPv6 was created. What is the difference? Well, using IPv4 there are about 4 billion addresses, with IPv6 there are 3.4×1038, in fact I don’t even know how to pronounce a number that big, but it will be enough for a very long time.

Fortunately, a lot of operating systems already have support for IPv6, and if they don’t, they will start having very soon.

Written by Claudiu Persoiu

7 February 2011 at 8:26 PM

Posted in Diverse

Tagged with ,

No SQL Expert

without comments

No SQL Expert

Written by Claudiu Persoiu

6 February 2011 at 11:16 AM

Posted in Diverse,MySQL

Tagged with