-
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
Then the file can be executed in Linux directly with:
1$./testStream.php
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
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);
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
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
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
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
-
PHP for desktop, is it worth it?
PHP is described on Wikipedia as:
PHP: Hypertext Preprocessor is a widely used, general-purpose scripting language that was originally designed for web development to produce dynamic web pages.
Taking this into consideration, apps divide in 3 category: web, command line and desktop.
For the Web, PHP is the most popular open-source (and not only) programming language.
PHP CLI
PHP CLI (Command Line Interface) I find it very interesting, even though is not used at it’s full potential. A lot of developers prefer shell scripting or Perl with no real reason. I’ve been playing around with this tool and I liked the result.
Important frameworks like: Zend, Symfony or Cake PHP are using PHP CLI to generate projects, models, CRUD or other features that can be easily used with a command line.
In the Windows environment the command line is not exactly popular, but in Linux is almost imperative. After all what’s the point of using shell scripting when you can use a powerful language with a lot of features like PHP?
But CLI is not limited just to the command line, it is usually used for cronjobs, pipes, socket-servers etc.
PHP-GTK
When it comes to PHP and desktop usually people thing about PHP-GTK. What do I thing about the project? Is not dead, like it says on the official website, but is not exactly alive. The reason? Gtk is not exactly simple. If you come from the Linux environment probably is not that difficult, but if you usually work on the web is not exactly html… Nevertheless there is a community that keep this project alive.
Nevertheless, it allows developers to build desktop apps in PHP, compatible with a wide variety of operating systems.
But there is an issue, the resulting apps are not exactly compiled code, they must run using a PHP virtual machine. Here is the issue, how do you distribute the app? If you have a small app of only few lines of code, to distribute it with a virtual machine is a little complicated… Also the code is visible, of course there are methods to solve this issue, but there aren’t exactly simple.
This is probabily the most popular PHP platform for desktop, if you can say that about this environment.
The documentation is pretty big, it was taken from the C++ version. Is not as well polished like the PHP manual for instance, but I believe is sufficient.
Winbinder
Compared to PHP-GTK it has an disadvantage, it only works on MS Widows operating system. The advantage is that it has a much simpler API. If I had to choose a PHP platform for desktop, probably I would go for Winbinder. Unfortunately is in the same state, is not dead but is not exactly alive. It also have the support of a community, but without any particular special results.
The issue with the compiled code is found here also, and even more the issue with platform distribution is just as bad. I firmly believe that if you want to develop an app using this platform, to make it work on your computer is the easiest part, to make it work on someone else’s computer is the real issue…
The documentation is pretty small, because of the API. But simplicity is good when it comes to programming, that means you can easily build pretty interesting apps.
Compilers
There a few, and the majority of them have some issue because they use old PHP versions of even old GTK. I’ve spend many hours on Google trying to find some reals solution but with no success.
Most popular compilers:
- Bambalam – works well with CLI and Winbinder. But it has a great disadvantage: it’s only compatible with PHP 4.4.4, and I believe that says it all. Anyway I believe it was the most interesting solution, unfortunately to old (the last version was released in 2006).
- PriadoBlender – works well with PHP-GTK and CLI, but is not very stable. The last (beta) version was released in 2007, and since then nothing new was ever heard from it. Probably if that version would be updated it would help a lot the PHP-GTK project.
Conclusion
When it comes to Web, everything is great!
PHP as a command line tool is ever more popular and more tools appear each day!
In the desktop environment is a “the living dead” sensation… This projects are not dead but there not exactly alive. Of course there are other solution for PHP on desktop which I did not mention, but there are in about the same state. Probably a new approach would help, something more attractive for web developers and those passionate about this language.