8.3 Wrapper Details

The following sections show how to read from and write to different locations using PHP 5's bundled wrappers. You've already seen how to process files stored on your server's hard drive. Now you use the http and ftp wrappers to access remote files using HTTP and FTP.

The http and ftp wrappers require the allow_url_fopen configuration directive set to On. This is the default setting, but allow_url_fopen may be turned off on some systems because it allows crackers to more easily exploit insecurely written code.

Specifically, when allow_url_fopen is on, include $file will even include remote files. If a cracker is somehow able to set $file to a value of her own, she can make your web server execute any PHP code she wants just by posting it on a web site and setting $file to that URL.

Another wrapper you'll learn how to use is the php wrapper for standard in, out, and error. This wrapper is particularly useful for people using PHP on the command line or with web services.

The final set of wrappers are the compression wrappers. These wrappers are similar to the file wrapper, except that they let you read and write data that is compressed using gzip and bzip2.

8.3.1 HTTP and HTTPS

While file_get_contents( ) and file_put_contents( ) may seem to work only for local files, they're actually valid for any stream that enables them. Since PHP comes with an http stream, this means you can retrieve files using HTTP.

For example, you can fetch index.php from www.example.com:

$index = file_get_contents('http://www.example.com/index.php');

This tells PHP to use the http wrapper to retrieve the target www.example.com/index.php. The wrapper knows it should make an HTTP GET request of the web server located at www.example.com.

You can also pass along a username and password to be used as HTTP Basic Authentication credentials, like this:

$index = file_get_contents('http://rasmus:FbNAPw@www.example.com/index.php');

The username comes immediately after the double slashes and is separated from the password by a colon. After the password, place an @.

Modify the HTTP request by passing a stream context to file_get_contents( ). A stream context is a way to tweak the default behavior associated with a wrapper. For example, the http wrapper allows you to modify the HTTP method from GET to POST or add HTTP headers such as cookies.

Here's how to add a cookie to your request using streams and file_get_contents( ):

$options = array(

    'http' => array(

        'header' => "Cookie: username=rasmus\r\n"



$context = stream_context_create($options);

$index = file_get_contents('http://www.example.com/index.php', 

                           false, $context);

The stream_context_create( ) function takes an array of options and returns a context resource. Use the wrapper name as the array key. In this example it's http. These elements hold another array that specifies the wrapper options.

Each wrapper has its own set of options that vary depending upon what's appropriate for the wrapper. The http wrapper has a header option where you can enter data to be added to the HTTP header of your request.

The text Cookie: username=rasmus\r\n sets a cookie named username to the value rasmus. Every HTTP header needs to begin with a header name (Cookie), followed by a colon and a space, the header value, and then \r\n.

Pass the context as the third parameter to file_get_contents( ) and set the second parameter to false. The second parameter controls whether file_get_contents( ) should search the include_path, an option that makes no sense for the http wrapper.

Now when the web server on www.example.com processes the request, it will pass along your cookie.

Compiling PHP with the --with-openssl option enables an https wrapper. Its behavior is identical to the http wrapper, except that it uses SSL.

Table 8-1 has a list of all http and popular https context options.

Table 8-1. http and https wrapper context options




Requires https?


Allow self-signed SSL certificates; value must be true or false




Path to certificate authority file used to authenticate remote peers; used when verify_peer is true




HTTP header, such as Cookie and Content-length




HTTP method, such as GET and POST




Proxy server URL




Send requests as full instead of relative URLs (necessary for some broken proxy servers); value must be true or false




Verify SSL certificate; value must be true or false




HTTP User-agent header, overridden by header option

Value in user_agent configuration directive


Additional SSL context options are located at http://www.php.net/transports.

Since HTTP does not distinguish between getting and putting information on a protocol level, you cannot use file_put_contents( ) with the http wrapper. However, you can make an HTTP POST or PUT using http_get_contents( ). Here's an example of an HTTP POST request:

$post_variables = array('usernamed' => 'rasmus');

$content = http_build_query($post_variables);

$content_length = strlen($content);

$options = array(


        'method'  => 'POST',

        'header'  =>

              "Content-type: application/x-www-form-urlencoded\r\n" . 

              "Content-length: $content_length\r\n",

        'content' => $content



$context = stream_context_create($options);

$index = file_get_contents('http://www.example.com/index.php', false, $context);

This code makes an HTTP POST request and sends along form data that sets the username variable equal to rasmus.

The new PHP 5 function http_build_query( ) then iterates through all the elements in the $post_variables array and encodes with urlencode( ) to ensure they're valid inside an HTTP request. Variables are then joined with their values using an equals sign (=) and then linked all together using ampersand (&).

This conversion is similar to what's done for an HTTP GET request. One difference between GET and POST, however, is that you must calculate your data's content length and pass that along as an HTTP header. This is done using strlen( ).

Now you have all the data necessary to create the stream context. The method is set to POST; the header is has two lines, a Content-type and a Content-length; and the content is set to $content, your encoded data. All HTTP POST forms must set a Content-type of application/x-www-form-urlencoded so the web server will know how to interpret the data.

This causes the $_POST array of index.php to contain your form data. Calling print_r($_POST) for this request gives you:



    [username] => rasmus


There's one value, username, and it's set to rasmus.

One benefit of using streams over an extension like cURL is that you're guaranteed that the http wrapper is always available. Since cURL requires an external library, it's not enabled on all copies of PHP.

8.3.2 FTP and FTPS

The ftp wrapper allows you to speak to FTP servers. This wrapper behaves similarly to the http wrapper:

$index = file_get_contents(


This logs into ftp.example.com as user rasmus and retrieves the index.html file in the /www/www.example.com/ directory.

If a username or password is not provided, PHP attempts to log in as user anonymous.

You can save a file to an FTP server using file_put_contents( ). This command saves $index to the server:


index.html', $index);

By default, if a file already exists on the FTP server, PHP will not overwrite it. Set the overwrite context option to change this behavior, like so:

$options = array(

    'ftp' => array(

        'overwrite' => true



$context = stream_context_create($options);



    $index, false, $context);

If the ftp overwrite option is set to true, the stream won't issue an error when there's a file at the location where you're saving the stream. Failing to do this causes file_put_contents( ) to return NULL and issue a warning:

PHP Warning:


failed to open stream: Cannot overwrite files in current mode

FTP server reports 213 3

As with the http wrapper, there's an ftps wrapper that is an SSL version of ftp.

8.3.3 PHP Input and Output

The php wrapper is particularly useful for people using PHP on the command line or with web services because it allows you to access any information sent to PHP from another program, regardless of format.

Normally, you can rely on the superglobal variables to contain all the data passed to PHP. HTTP GET and POST variables are in $_GET and $_POST, cookies are in $_COOKIES, and file uploads are in $_FILES. However, this happens only because this information is specially structured to be parsed into variables. When PHP is sent data in other formats, such as a SOAP packet that's structured as XML, the superglobal variables are not helpful at all. Similarly, when you use PHP to write a command-line tool, you communicate with the user through standard input instead of the superglobals.

The php wrapper is also handy for sending data from PHP. This wrapper makes it easy to send output to multiple locations in a consistent fashion. You can write to both standard out and standard error or control whether your data goes to the screen, a file, or both. Standard input, output, and error

When you use PHP on the command line, it reads and writes information to and from three different locations. These places are known as standard input, standard output, and standard error.

Standard input is all the data sent to PHP, and standard output is the data coming from PHP. Standard input and output are typically abbreviated as stdin and stdout. These are the names used by the php filter.

This command makes the shell pass the contents of input.txt to the PHP script wordwrap.php on standard input and stores PHP's standard output in output.txt:

$ php wordwrap.php < input.txt > output.txt

Inside your script, however, you don't know about input.txt and output.txt. You only know that you're to process data from php://stdin and print the results to php://stdout. This allows you to create a generalized script that works in conjunction with other command-line tools.

To read from standard input, do this:

$stdin = file_get_contents('php://stdin');

To write to standard output, do this:

file_put_contents('php://stdout', $data);

This simple script rewraps text to 10 characters:

$stdin = file_get_contents('php://stdin');

$data = wordwrap($stdin, 10);

file_put_contents('php://stdout', $data);

When input.txt contains:

Hello! My name is Rasmus Lerdorf.

the file output.txt ends up as:

Hello! My

name is



Standard error is similar to standard output, but it's a special channel for error messages. It's often shortened as stderr, so to write to standard error, do this:

file_put_contents('php://stderr', $errors);

Standard error is used when you're storing standard output to a file and want to see warning messages on the console. Think of standard error as error_log( ) for the command line. For instance, whenever standard input is empty, Example 8-1 reports a warning using standard error.

Example 8-1. Wrapping standard input
$stdin = file_get_contents('php://stdin');

if (empty($stdin)) {

    file_put_contents('php://stderr', "wordwrap.php received no data.\n");

    $data = '';

} else {

    $data = wordwrap($stdin, 10);


file_put_contents('php://stdout', $data);

Now if you process blank.txt, a file without any data, you're given the following warning:

% php wordwrap.php < blank.txt > output.txt

wordwrap.php received no data.

You're not allowed to write to standard input, nor can you read from standard output or standard error?these streams work in only one direction. Writing to standard input won't write any bytes, which leads to an (inaccurate) warning message from PHP:

PHP Warning:  file_put_contents( ): Only 0 of 1 bytes written, possibly out of free 

disk space.

Reading from standard output or error won't generate an error, but these streams never return any data, so there's really no point.

Also, PHP has its own set of output buffering functions that let you capture printed data. Writing to standard output circumvents these buffers, so be sure you really want standard output before you use this target.

To ensure you send data to the current PHP output buffer, use the output target instead. More details on output appear in the next section. General input and output

While standard input and output are perfect for command-line tools, most people use PHP in combination with a web server to process requests. In these cases, you should use another set of streams instead.

The php://input stream contains data sent in using HTTP POST. This is identical to what's stored in the $HTTP_RAW_POST_DATA variable, but it's always available, regardless of the setting of the always_populate_raw_post_data configuration directive. Using php://input is also more efficient than $HTTP_RAW_POST_DATA.

This filter is most commonly used for processing SOAP requests. For example, this simple SOAP server code for a Weather_Server service:

require 'SOAP/Server.php';

// Your Web Service class

require 'WebServices/Weather_Server.php';

$server = new SOAP_Server;

$server->addObjectMap(new Weather_Server,



The complement to php://input is php://output. This stream is similar to standard output, but it respects your PHP output buffering settings. Therefore, unless you explicitly want standard out, you should use php://output as a stream alternative to print. This holds true even if you ultimately send the results to standard output. For example:

$ob = ob_start( );                       // Start buffering of output

print '1';                              // Captured by buffer

file_put_contents('php://stdout', '2'); // Direct to standard out

file_put_contents('php://output', '3'); // Captured by buffer

ob_implicit_flush($ob);                 // Flush buffer contents


This snippet creates a PHP output buffer and then prints 1, 2, and 3. Since the output of print and file_put_contents('php://output') are captured by the buffer, they appear after the number 2. This happens even though ob_implicit_flush( ) sends data to standard out when used on the command line, because writing directly to php://stdout bypasses the buffering scheme.

The php://output filter is also useful when you want to write a generic function that sends data to either the screen or a file:

function log_error($stream, $message) {

    $time = strftime('%c'); // default time reprentation

    fwrite($stream, "Error occured at time: $time\n");

    fwrite($stream, $message);


$screen = fopen('php://output', 'w+');

log_error($screen, "Cannot connect to database.");


The log_error( ) function prints the current time and logs the error. In this case, it's sent through the standard output buffer, but you could also send the message to a file. All you need to do is open a different stream and pass that into log_error( ). Without php://output, you would need two separate pieces of code to handle both cases. Filtered input and output

There's one final php wrapper, php://filter. This isn't so much a wrapper as a way to use filters with stream functions that don't let you attach a filter before reading data.

Normally, you need to tell PHP that you want to filter a stream after you open the stream but before you read from or write to it. However, some functions?for example, file_get_contents( )?both open and read in the file in one step. Therefore, you're unable to attach the filter to the stream.

The php://filter wrapper is a way around this problem. The exact details of its use are explained in Section 8.5.3, later in this chapter.

8.3.4 Compression

The compression wrappers allow you to automatically compress and decompress files on the hard drive. The compress.zlib filter handles gzip, and the compress.bzip2 filter handles bzip2.

To use the compress.zlib wrapper, you must configure PHP with the --with-zlib flag, whereas compress.bzip2 needs the --with-bzip2 flag. While the primary applications of these libraries are to the zlib and bzip2 extensions, you also automatically get the wrappers.

Use them just like the file wrapper:

$log = file_get_contents('compress.zlib:///var/log/access.log.gz');

This uncompresses /var/log/access.log.gz and returns it to $log.

Or you can use the compress.bzip2 wrapper:

$log = file_get_contents('compress.zlib:///var/log/access.log.bz2');

Both wrappers also allow you to write files:

file_put_contents('compress.zlib:///pub/php/php-5.0.0.gz', $php);

The compression wrappers work only on local files; you cannot combine them with the http wrapper to open compressed files via HTTP.