45
action when one is emitted. The sample application in Recipe 20.11
combines PHP-GTK with
some SOAP function calls to display weather conditions around the world.
To install PHP-GTK on Unix, download the latest version of PHP-GTK from
http://gtk.php.net/download.php
and the GTK+ libraries from http://www.gtk.org/download
.
You also need libtool 1.4.2, automake 1.4, and autoconf 2.13 (available at
http://www.gnu.org/directory/
if they're not already installed on your system).
Once you've downloaded all the necessary files and installed the support libraries and tools,
unpack the PHP-GTK source distribution. In the PHP-GTK directory, run ./buildconf to create
configuration files, ./configure to create makefiles, then make to build the PHP-GTK extension.
Last, run make install to install the PHP-GTK extension in your PHP extensions directory. You
can find detailed Unix installation instructions, including common build problems, at
http://gtk.php.net/manual/en/install.unix.php
.
To install PHP-GTK on Windows, no compiling is necessary. From
http://gtk.php.net/download.php
, you can download a compiled PHP-GTK extension and
supporting libraries. Once you've downloaded and unzipped the Windows distribution, copy the
files in the php4 subdirectory to your PHP binary directory (or create one if it doesn't already
exist). Copy the files in the winnt\system32 subdirectory to your system32 directory
(C:\WINNT\SYSTEM32 for Windows NT and Windows 2000; C:\WINDOWS\SYSTEM32 for
Windows 95 and Windows 98). If you don't already have a php.ini file in place, copy the
winnt\php.ini file to your Windows directory (C:\WINNT or C:\WINDOWS). If you already have
a php.ini file in place, add these lines to the end of it:
[PHP-GTK]
php-gtk.extensions = php_gtk_libglade.dll, php_gtk_sqpane.dll
Detailed Windows installation instructions are at
http://gtk.php.net/manual/en/install.win32.php
.
On either platform, once you've installed the PHP-GTK extension, you need to use the
dl(
)
function to load it in any script in which you want to use GTK functionality. On Windows:
if (! class_exists('gtk')) {
dl('php_gtk.dll');
}
On Unix:
if (! class_exists('gtk')) {
dl('php_gtk.so');
}
If you want the same script to run unaltered on Unix or Windows, you can load the PHP-GTK
extension like this:
47
if (! class_exists('gtk')) {
dl('php_gtk.'. (((strtoupper(substr(PHP_OS,0,3))) ==
'WIN')?'dll':'so'));
}
The GTK+ toolkit is large and powerful. PHP-GTK makes it easy to create and manipulate
GTK+ objects, but designing and planning a GUI application is still a significant task. In
addition to the comprehensive PHP-GTK documentation at http://gtk.php.net/manual/
, also
take advantage of the GTK+ documentation itself at
http://developer.gnome.org/doc/API/gtk/index.html
. The C class and function names in the
GTK+ documentation map almost directly to their PHP equivalents. Also, the tutorial at
http://www.gtk.org/tutorial/
is for GTK+ 2.0 (not 1.2), but it is still a good introduction to the
concepts and practices of GTK+ application building.
Recipe 20.2 Parsing Program Arguments
20.2.1 Problem
You want to process arguments passed on the command line.
20.2.2 Solution
Look in
$_SERVER['argc']
for the number of arguments and
$_SERVER['argv']
for their values. The first argument,
$_SERVER['argv'][0]
, is the name of script that is being run:
if ($_SERVER['argc'] != 2) {
die("Wrong number of arguments: I expect only 1.");
}
$size = filesize($_SERVER['argv'][1]);
print "I am $_SERVER[argv][0] and report that the size of ";
print "$_SERVER[argv][1] is $size bytes.";
20.2.3 Discussion
In order to set options based on flags passed from the command line, loop through
$_SERVER['argv']
from
1
to
$_SERVER['argc']
:
for ($i = 1; $i < $_SERVER['argc']; $i++) {
switch ($_SERVER['argv'][$i]) {
case '-v':
// set a flag
$verbose = 1;
break;
case '-c':
64
// advance to the next argument
$i++;
// if it's set, save the value
if (isset($_SERVER['argv'][$i])) {
$config_file = $_SERVER['argv'][$i];
} else {
// quit if no filename specified
die("Must specify a filename after -c");
}
break;
case '-q':
$quiet = 1;
break;
default:
die('Unknown argument: '.$_SERVER['argv'][$i]);
break;
}
}
In this example, the
-v
and
-q
arguments are flags that set
$verbose
and
$quiet
,
but the
-c
argument is expected to be followed by a string. This string is assigned to
$config_file
.
20.2.4 See Also
Recipe 20.3
for more parsing arguments with getopt; documentation on
$_SERVER['argc']
and
$_SERVER['argv']
at
http://www.php.net/reserved.variables
.
Recipe 20.3 Parsing Program Arguments
with getopt
20.3.1 Problem
You want to parse program options that may be specified as short or long options, or they
may be grouped.
20.3.2 Solution
Use PEAR's
Console_Getopt
class. Its
getopt( )
method can parse both short-
style options such as
-a
or
-b
and long-style options such as
--alice
or
--bob
:
$o = new Console_Getopt;
// accepts -a, -b, and -c
$opts = $o->getopt($_SERVER['argv'],'abc');
55
// accepts --alice and --bob
$opts = $o->getopt($_SERVER['argv'],'',array('alice','bob'));
20.3.3 Discussion
To parse short-style options, pass
Console_Getopt::getopt( )
the array of
command-line arguments and a string specifying valid options. This example allows
-a
,
-b
,
or
-c
as arguments, alone or in groups:
$o = new Console_Getopt;
$opts = $o->getopt($_SERVER['argv'],'abc');
For the previous option string
abc
, these are valid sets of options to pass:
% program.php -a -b -c
% program.php -abc
% program.php -ab -c
The
getopt( )
method returns an array. The first element in the array is a list of all of
the parsed options that were specified on the command line, along with their values. The
second element is any specified command-line option that wasn't in the argument specification
passed to
getopt( )
. For example, if the previous program is run as:
% program.php -a -b sneeze
then
$opts
is:
Array
(
[0] => Array
(
[0] => Array
(
[0] => a
[1] =>
)
[1] => Array
(
[0] => b
[1] =>
)
)
[1] => Array
(
[0] => program.php
[1] => sneeze
)
)
69
Put a colon after an option in the specification string to indicate that it requires a value. Two
colons means the value is optional. So,
ab:c:
: means that
a
can't have a value,
b
must,
and
c
can take a value if specified. With this specification string, running the program as:
% program.php -a -b sneeze
makes
$opts
:
Array
(
[0] => Array
(
[0] => Array
(
[0] => a
[1] =>
)
[1] => Array
(
[0] => b
[1] => sneeze
)
)
[1] => Array
(
[0] => program.php
)
)
Because
sneeze
is now set as the value of
b
, it is no longer in the array of unparsed
options. Note that the array of unparsed options always contains the name of the program.
To parse long-style arguments, supply
getopt( )
with an array that describes your
desired arguments. Put each argument in an array element (leave off the leading
--
) and
follow it with
=
to indicate a mandatory argument or
= =
to indicate an optional argument.
This array is the third argument to
getopt( )
. The second argument (the string for
short-style arguments) can be left blank or not, depending on whether you also want to parse
short-style arguments. This example allows
debug
as an argument with no value,
name
with a mandatory value, and
size
with an optional value:
require 'Console/Getopt.php';
$o = new Console_Getopt;
$opts = $o->getopt($_SERVER['argv'],'',array('debug','name=','size=='));
These are valid ways to run this program:
% program.php --debug
% program.php --name=Susannah
71
% program.php --name Susannah
% program.php --debug --size
% program.php --size=56 --name=Susannah
% program.php --name --debug
The last example is valid (if counterproductive) because it treats
--debug
as the value of
the
name
argument and doesn't consider the
debug
argument to be set. Values can be
separated from their arguments on the command line by either a
=
or a space.
For long-style arguments,
getopt( )
includes the leading
--
in the array of parsed
arguments; for example, when run as:
% program.php --debug --name=Susannah
$opts
is set to:
Array
(
[0] => Array
(
[0] => Array
(
[0] => --debug
[1] =>
)
[1] => Array
(
[0] => --name
[1] => Susannah
)
)
[1] => Array
(
[0] => program.php
)
)
We've been using
$_SERVER['argv']
as the array of command-line arguments, which
is fine by default.
Console_Getopt
provides a method,
readPHPArgv( )
, to look
also in
$argv
and
$HTTP_SERVER_VARS['argv']
for command-line arguments.
Use it by passing its results to
getopt( )
:
require 'Console/Getopt.php';
$o = new Console_Getopt;
$opts = $o->getopt($o->readPHPArgv(),'',array('debug','name=','size=='));
Both
getopt( )
and
readPHPArgv( )
return a
Getopt_Error
object when
these encounter an error; for example, having no option specified for an option that requires
46
one.
Getopt_Error
extends the
PEAR_Error
base class, so you can use familiar
methods to handle errors:
require 'Console/Getopt.php';
$o = new Console_Getopt;
$opts = $o->getopt($o->readPHPArgv(),'',array('debug','name=','size=='));
if (PEAR::isError($opts)) {
print $opts->getMessage();
} else {
// process options
}
20.3.4 See Also
Recipe 20.2
for parsing of program options without getopt; documentation on
Console_Getopt
at http://pear.php.net/manual/en/core.console.getopt.php
.
Recipe 20.4 Reading from the Keyboard
20.4.1 Problem
You need to read in some typed user input.
20.4.2 Solution
Use
fopen( )
with the special filename php://stdin:
print "Type your message. Type '.' on a line by itself when you're
done.\n";
$fh = fopen('php://stdin','r') or die($php_errormsg);
$last_line = false; $message = '';
while (! $last_line) {
$next_line = fgets($fp,1024);
if (".\n" == $next_line) {
$last_line = true;
} else {
$message .= $next_line;
}
}
print "\nYour message is:\n$message\n";
If the Readline extension is installed, use
readline( )
:
$last_line = false; $message = '';
while (! $last_line) {
$next_line = readline();
56
if ('.' == $next_line) {
$last_line = true;
} else {
$message .= $next_line."\n";
}
}
print "\nYour message is:\n$message\n";
20.4.3 Discussion
Once you get a file handle pointing to stdin with
fopen( )
, you can use all the standard
file-reading functions to process input (
fread( )
,
fgets( )
, etc.) The solution uses
fgets( )
, which returns input a line at a time. If you use
fread( )
, the input still
needs to be newline-terminated to make
fread( )
return. For example, if you run:
$fh = fopen('php://stdin','r') or die($php_errormsg);
$msg = fread($fh,4);
print "[$msg]";
And type in
tomato
and then a newline, the output is
[toma]
. The
fread( )
grabs
only four characters from stdin, as directed, but still needs the newline as a signal to return
from waiting for keyboard input.
The Readline extension provides an interface to the GNU Readline library. The
readline(
)
function returns a line at a time, without the ending newline. Readline allows Emacs and vi-
style line editing by users. You can also use it to keep a history of previously entered
commands:
$command_count = 1;
while (true) {
$line = readline("[$command_count]--> ");
readline_add_history($line);
if (is_readable($line)) {
print "$line is a readable file.\n";
}
$command_count++;
}
This example displays a prompt with an incrementing count before each line. Since each line is
added to the readline history with
readline_add_history( )
, pressing the up
and down arrows at a prompt scrolls through the previously entered lines.
20.4.4 See Also
53
Documentation on
fopen( )
at http://www.php.net/fopen
,
fgets( )
at
http://www.php.net/fgets
,
fread( )
at http://www.php.net/fread
, and the Readline
extension at http://www.php.net/readline
; the Readline library at
http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html
.
Recipe 20.5 Reading Passwords
20.5.1 Problem
You need to read a string from the command line without it being echoed as it's typed; for
example, when entering passwords.
20.5.2 Solution
On Unix systems, use /bin/stty to toggle echoing of typed characters:
// turn off echo
`/bin/stty -echo`;
// read password
$password = readline();
// turn echo back on
`/bin/stty echo`;
On Windows, use
w32api_register_function( )
to import
_getch( )
from msvcrt.dll:
// load the w32api extension and register _getch()
dl('php_w32api.dll');
w32api_register_function('msvcrt.dll','_getch','int');
while(true) {
// get a character from the keyboard
$c = chr(_getch());
if ( "\r" == $c || "\n" == $c ) {
// if it's a newline, break out of the loop, we've got our password
break;
} elseif ("\x08" == $c) {
/* if it's a backspace, delete the previous char from $password */
$password = substr_replace($password,'',-1,1);
} elseif ("\x03" == $c) {
// if it's Control-C, clear $password and break out of the loop
$password = NULL;
break;
} else {
// otherwise, add the character to the password
$password .= $c;
}
}
54
20.5.3 Discussion
On Unix, you use /bin/stty to control the terminal characteristics so that typed characters
aren't echoed to the screen while you read a password. Windows doesn't have /bin/stty, so
you use the W32api extension to get access
_getch( )
in the Microsoft C runtime library,
msvcrt.dll. The
_getch( )
function reads a character without echoing it to the screen. It
returns the ASCII code of the character read, so you convert it to a character using
chr( )
. You then take action based on the character typed. If it's a newline or carriage return, you
break out of the loop because the password has been entered. If it's a backspace, you delete a
character from the end of the password. If it's a Control-C interrupt, you set the password to
NULL
and break out of the loop. If none of these things are true, the character is
concatenated to
$password
. When you exit the loop,
$password
holds the entered
password.
The following code displays
Login
: and
Password
: prompts, and compares the entered
password to the corresponding encrypted password stored in /etc/passwd. This requires that
the system not use shadow passwords.
print "Login: ";
$fh = fopen('php://stdin','r') or die($php_errormsg);
$username = rtrim(fgets($fh,64)) or die($php_errormsg);
preg_match('/^[a-zA-Z0-9]+$/',$username)
or die("Invalid username: only letters and numbers allowed");
print 'Password: ';
`/bin/stty -echo`;
$password = rtrim(fgets($fh,64)) or die($php_errormsg);
`/bin/stty echo`;
print "\n";
// nothing more to read from the keyboard
fclose($fh);
// find corresponding line in /etc/passwd
$fh = fopen('/etc/passwd','r') or die($php_errormsg);
$found_user = 0;
while (! ($found_user || feof($fh))) {
$passwd_line = fgets($fh,256);
if (preg_match("/^$username:/",$passwd_line)) {
$found_user = 1;
}
}
fclose($fh);
$found_user or die ("Can't find user \"$username\"");
// parse the correct line from /etc/passwd
$passwd_parts = split(':',$passwd_line);
Documents you may be interested
Documents you may be interested