164
Chapter 10 Stream and Network Programming
n
whether the stream connection has timed out or not
n
whether the stream has blocked or not
n
whether all data has been read from the stream or not
To get stream metadata, use the
stream_get_meta_data()
function.
<?php
// Chapter 10: Stream and Network Programming
//
// Example 02: stream metdata example
// we will create a stream by opening this stream, and then we’ll
// dump the metadata out to see what’s there
echo “Metadata for file: “ . __FILE__ . “\n\n”;
$fp = fopen(__FILE__, “r”);
var_dump(stream_get_meta_data($fp));
fclose($fp);
?>
Here is the output from running the code example:
array(6) {
[“wrapper_type”]=>
string(9) “plainfile”
[“stream_type”]=>
string(5) “STDIO”
[“unread_bytes”]=>
int(0)
[“timed_out”]=>
bool(false)
[“blocked”]=>
bool(true)
[“eof”]=>
bool(false)
}
<?php
// Chapter 10: Stream and Network Programming
//
// Example 03: stream metadata example - http file wrapper
// we will create a stream by opening a connection to the PHP Project’s
// own web server, and then dump the metadata to see what we have
11 7090 ch10 7/16/04 8:46 AM Page 164
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
165
Introducing Streams
echo “Metadata from a connection to: />$fp = fopen(“ “r”);
stream_filter_append($fp, “string.rot13”);
var_dump(stream_get_meta_data($fp));
fclose($fp);
?>
Pipelines
Data in a stream flows along one of two pipelines:
n
Data sent down a stream from your PHP script to the destination file or network
server flows down the write pipeline.
n
Data retrieved from the file or network server flows up the read pipeline.
Some streams will have both pipelines, but some streams will only have a read pipeline
or a write pipeline.
What Is the Stream Transport?
At the far end of the pipeline, the furthest away from your PHP script, is the stream
transport.The stream transport is a piece of code that enables the file wrapper to talk
directly with whatever the stream is connected to.
PHP comes with a number of built-in transports:
n
STDIO
The
STDIO
transport is used to talk to normal files, special resources such as
stdin
and
stdout
, and any other types of file supported by your underlying operating
system.
n
socket
The
socket
transport is used to talk to (possibly remote) servers over the network.
PHP automatically chooses the correct transport to use with your choice of file wrapper.
What Is the Stream Context?
The stream context is a piece of data about the stream and about the data passing along
the stream. It is used to pass additional options to the file wrapper or stream transport.
You create the context using the
stream_context_create()
function, and then pass
it as a parameter to
fopen()
or
fsockopen()
.
Different file wrappers and stream transports accept different options.You can pass
options to both the file wrapper and underlying stream transport at the same time.
11 7090 ch10 7/16/04 8:46 AM Page 165
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
166
Chapter 10 Stream and Network Programming
How Do Streams Affect Me?
Most of the time, you will be using streams via
fopen()
and the file wrappers. PHP
always manages the stream for you, and you can pay it little mind under these circum-
stances.
If you have to directly interact with the stream, it will probably be to pass options
through to the file wrapper via a stream context, or to retrieve extra information from
the file wrapper via the stream’s metadata.
The other time that you will need to work more closely with the stream is if you are
writing PHP code to talk over the network to remote servers and services using net-
work protocols.
Connecting to Remote Hosts Using Sockets
When you access a normal file, all file operations ultimately are handled by your com-
puter’s operating system.The operating system creates a resource called a file handle. File
handles make it easy for the operating system to understand which file PHP is reading
from or writing to.
When you access a (possibly remote) server over the network, all the operations on
this connection are also handled by your computer’s operating system. Instead of creating
a file handle, the operating system creates a resource called a socket. File handles and
sockets are very similar, and through the PHP Streams architecture, PHP tries to keep
the differences to a minimum.
When Should I Use a Socket Instead of a File Wrapper?
Some file wrappers allow you to access (possibly remote) network servers. For example,
the
http
file wrapper allows you to retrieve pages from a web server. Unlike sockets, file
wrappers will hide the details of supporting the application-layer network protocol.
So why would you want to use a socket instead?
You must use a socket if you want to connect to a (possibly remote) network server
that there is no file wrapper for. An example would be connecting to the memcached
caching server.There is no file wrapper that supports the memcached network protocol.
You must use a socket if you want to do something that the file wrapper cannot do—
but is possible through the underlying network protocol. An example would be sending
an XML-RPC message to a (possibly remote) web server. XML-RPC involves sending
XML messages to and from the web server, using the HTTP network protocol.The
http
file wrapper only supports reading from a web server; it does allow you to write
data to the web server. But the underlying HTTP network protocol does support writ-
ing data to a web server, and you can access this network protocol by using a socket
rather than by using a file wrapper.
11 7090 ch10 7/16/04 8:46 AM Page 166
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
167
Connecting to Remote Hosts Using Sockets
What Network Transports Does PHP Support?
You can find this information in the “List of Supported Socket Transports” appendix in
the PHP Manual.
n
tcp
This transport allows you to connect to (possibly remote) network servers using
the connection-orientated Transmission Control Protocol—the TCP part of
TCP/IP.
n
udp
This transport allows you to connect to (possibly remote) network servers using
the connection-less User Datagram Protocol—part of the TCP/IP network
protocol.
n
ssl
This transport allows you to connect to (possibly remote) network servers using
Secure Sockets Layer encryption. SSL runs over TCP connections.
n
tls
This transport allows you to connect to (possibly remote) network servers using
Transport Layer Security encryption.TLS runs over TCP connections.
n
unix
This transport allows you to connect to services running on the local computer
using the connection-orientated UNIX Domain protocol.
n
udg
This transport allows you to connect to services running on the local computer
using the connection-less UNIX Domain protocol.
How Do I Open a Socket?
You can create a socket using the
fsockopen()
and
pfsockopen()
functions.You tell
PHP what type of network transport you want to use by prefixing the transport to the
name or IP address of the server you want to connect to.
<?php
// Chapter 10: Stream and Network Programming
//
// Example 06: Using fsockopen()
// we will open a connection to the PHP Project’s website, and download
// their front page
//
11 7090 ch10 7/16/04 8:46 AM Page 167
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
168
Chapter 10 Stream and Network Programming
// note that what comes back is a redirect, and not the front-page itself
// this is an example of one of the many things that the http file wrapper
// automatically (and transparently) handles for us
$fp = fsockopen (“tcp://www.php.net”, 80, $sock_errno, $sock_errmsg);
fwrite ($fp, “GET /\n”);
while (!feof($fp))
{
echo fgets($fp) . “\n”;
}
fclose($fp);
?>
Sockets created using
fsockopen()
are automatically closed by PHP when your script
ends. Sockets created using
pfsockopen()
are persistent.
Persistent Sockets
Sockets created using
pfsockopen()
remain open after your script has finished.When
your next script calls
pfsockopen()
with the same hostname and port, PHP will reuse
the socket that you opened last time—provided that the socket is still open.
PHP only persists sockets inside a single process.
n
If you are using a CGI-BIN version of PHP, the next time your script runs, the
old PHP process will have terminated.Your persistent socket will have been closed
automatically by PHP when your script finished running.
n
If you are using mod_php, or a FastCGI version of PHP (such as Zend’s
WinEnabler under IIS), there is a pool of reusable PHP engines.When your script
runs, it might run inside the same copy of the engine as last time—or it might
not. If your script runs inside a different copy of the engine, the call to
pfopensock()
will open up a new socket connection.
Remote servers (and especially by any firewalls in between) will automatically close per-
sistent sockets if the socket isn’t used for a period of time.
Timeouts When Opening a Socket
If you don’t provide the timeout parameter to
fsockopen()
, PHP uses the value of
default_socket_timeout
from the
php.ini
settings.
The timeout parameter to
fsockopen()
, and the
default_socket_timeout
setting,
only affect attempts to open the socket.This timeout is not used at all for read and write
operations.
11 7090 ch10 7/16/04 8:46 AM Page 168
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
169
Connecting to Remote Hosts Using Sockets
How Do I Use a Socket?
The PHP Streams architecture allows you to treat socket connections as you would
another type of stream.To read from a socket, you can use
fread()
and others.To write
to a socket, you can use
fwrite()
and others.
fread()
and
fwrite()
are binary safe—you can use them to read and write any type
of data that you need to.
Blocking Mode
By default, when PHP creates a new socket, it switches on blocking mode for that
stream.
When blocking mode is on, any functions that attempt to read data from the stream
will wait until there is some data available to be read—or until the socket is closed by
the remote server.
<?php
// Chapter 10: Stream and Network Programming
//
// Example 08: A blocked socket
// we will open a connection to the PHP Project’s website, and attempt
// to read from the socket without having told the webserver what we
// want it to send us.
//
// this will block, and you should use CTRL+C to abort this script when
// you get bored enough
$fp = fsockopen(“tcp://www.php.net”, 80, $sock_errno, $sock_errmsg);
echo “Attempting to read from the stream ... this will not timeout\n”;
echo “until the socket closes. You should use CTRL+C to abort this\n”;
echo “script when you’re ready\n”;
echo fgets($fp) . “\n”;
fclose($fp);
?>
You can switch blocking mode off by using
stream_set_blocking()
:
<?php
// Chapter 10: Stream and Network Programming
//
// Example 09: Switching off blocking mode
11 7090 ch10 7/16/04 8:46 AM Page 169
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
170
Chapter 10 Stream and Network Programming
// once again, we will make a connection to the PHP Project’s webserver,
// and attempt to read from the socket without having told the webserver
// what page we want it to serve
//
// the difference this time is that we will switch off blocking mode first
//
// finally, we will dump the return value from fgets(), so you can see
// what fgets() returns when trying to read from a blocked stream
$fp = fsockopen(“tcp://www.php.net”, 80, $sock_errno, $sock_errmsg);
stream_set_blocking($fp, false);
echo “Attempting to read from the stream ... this will fail and return\n”;
echo “immediately\n\n”;
$result = fgets($fp);
fclose($fp);
echo “fgets() has returned:\n”;
var_dump($result);
?>
Read/Write Timeouts
Instead of switching off blocking mode, you could use
stream_set_timeout()
to set a
timeout on read/write operations instead.
<?php
// Chapter 10: Stream and Network Programming
//
// Example 10: setting a timeout on a stream
// once again, we will make a connection to the PHP Project’s webserver,
// and attempt to read from the socket without having told the webserver
// what page we want it to serve
//
// the difference this time is that we will set a read/write timeout of
// ten seconds on the stream
//
// finally, we will dump the return value from fgets(), so you can see
// what fgets() returns when stream operations timeout
11 7090 ch10 7/16/04 8:46 AM Page 170
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
171
Connecting to Remote Hosts Using Sockets
$fp = fsockopen(“tcp://www.php.net”, 80, $sock_errno, $sock_errmsg);
stream_set_timeout($fp, 10);
echo “Attempting to read from the stream ... this will timeout in 10 secs\n\n”;
$result = fgets($fp);
fclose($fp);
echo “The fgets() has timed out, and returned:\n”;
var_dump($result);
?>
Closing a Socket
When you have finished with a socket, you should close it as soon as possible.
The computer that your PHP script is running on can only open a limited number
of sockets.The same is true for the network server at the other end of your socket.The
sooner you can close your socket, the sooner the computer’s operating system can recy-
cle the network connection for someone else to use.
Use
fclose()
to close your socket:
<?php
// Chapter 10: Stream and Network Programming
//
// Example 11: Using fclose()
// here, we create a stream using fsockopen(), and then demonstrate how
// to close it using fclose()
//
// once the stream has been closed, the file handle cannot be re-used
// without a new call to fopen() or fsockopen()
$fp = fsockopen (“tcp://www.php.net”, 80, $sock_errno, $sock_errmsg);
fclose($fp);
echo “We have opened and closed the stream. When we attempt to read from\n”;
echo “the stream, PHP will output an error on your screen.\n”;
echo fgets($fp);
?>
11 7090 ch10 7/16/04 8:46 AM Page 171
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.