PHP5: Protocols & Wrappers

Posted on March 1, 2011

PHP has provided various built-in wrappers and protocols for a while, but PHP5 adds a few extras.

Wrappers allow you to operate on resources as if they were regular local files. So, you can use functions like fopen(), copy(), and filesize() on these resources and PHP performs the necessary operations transparently.

Existing Wrappers

For example, you could always open a local file in PHP like this:

$fp1 = fopen('myfile.dat', 'r'); // relative path
$fp2 = fopen('/path/to/myfile.data', 'r'); // absolute path

PHP5 allows you to also use the file:// prefix to mimic other protocols:

$fp1 = fopen('file://myfile.dat', 'r'); // relative path
$fp2 = fopen('file:///path/to/myfile.data', 'r'); // absolute path

PHP (since 4) also supports file operations using the http://, https://, ftp://, and ftps:// protocols. You can use these to modify remote files (if allow_url_fopen is enabled).

PHP4+ also provides wrappers for pseudofiles php://stdin, php://stdout, php://stderr, php://input, and php://output. These are not used as much because they are at a lower level than what is typically required, but they can be useful in certain situations.

You can also transparently read and write the contents of Zip and Bzip2 files, using compress.zlib:// and compress.bzip2:// respectively.

PHP Wrappers

A new wrapper in PHP5 is php://filter, a meta-wrapper that allows you to filter the resource when you open it. The filters are included after the first “/”; you can specify “read=” or “write=” to apply the filter to only one stream, otherwise it applies to both reading and writing. You then include the resource you would normally use (without the filter) using “/resource=”. Here are some examples:

// This will output the contents of www.example.com entirely in uppercase.
readfile("php://filter/read=string.toupper/resource=http://www.example.com");

// This will do the same as above but will also ROT13 encode it.
// (Use pipe character to separate filters.)
readfile("php://filter/read=string.toupper|string.rot13/resource=http://www.example.com");

// This will filter the string "Hello World" through the rot13 filter,
//  then write to example.txt in the current directory.
file_put_contents("php://filter/write=string.rot13/resource=example.txt","Hello World");

The manual says: “This is useful with all-in-one file functions such as readfile(), file(), and file_get_contents() where there is otherwise no opportunity to apply a filter to the stream prior the contents being read.” I imagine this also uses less memory than storing a block of data and manipulating it there.

Another new wrapper is php://memory, which stores the data in memory. I’m not sure if PHP’s memory_limit applies to this footprint or not, but I would imagine so.

The new php://temp wrapper acts like php://memory if storage required is below a certain limit (default 2 MB). If the needed space exceeds the limit, then the data is stored in a temporary file instead. You can include a “/maxmemory:” parameter to specify the size limit:

$fiveMBs = 5 * 1024 * 1024;
$fp = fopen("php://temp/maxmemory:$fiveMBs", 'r+');

Data Stream Wrapper

You may be familiar with the data stream syntax because modern browsers support them for inline images. You can use the same syntax (and any type of file) for reading a string of data:

// Prints "I love PHP".
echo file_get_contents('data://text/plain;base64,SSBsb3ZlIFBIUAo=');

If you aren’t reading in binary data, you don’t have to encode it using Base64, but you do need to urlencode() it. You can also leave out the double slashes, e.g. “data:text/plain”, to match the official syntax standard.

Glob Wrapper

The glob:// wrapper is sort of an extension of the glob() function. Like the function, it includes all files matching a specific pattern. The glob wrapper automatically handles the opening of the files though. Since it can match multiple files, I presume it can only be used in a multiple-file context, such as with an iterator:

// Loop over all *.php files in ext/spl/examples/ directory
//   and print the filename and its size.
$it = new DirectoryIterator("glob://ext/spl/examples/*.php");
foreach($it as $f)
{
  printf("%s: %.1FKn", $f->getFilename(), $f->getSize()/1024);
}

PHP Archive Wrapper

Finally, PHP5 has a new wrapper for working with PHP archives, designated by a phar:// prefix. PHP archives are specific to PHP, so you probably haven’t heard of them. They warrant their own extension and manual pages, but they basically collect files into an archive, specifically used as a way to package a PHP application into a single file.

More

Those are the wrappers that are built-in to PHP5. You can add more, including support for the SSH protocol, RAR archives, audio streams, and pseudo-terminals, if you install the necessary extensions. You can even write your own.

The individual documentation on each wrapper has details on which operations are available and other wrapper-specifics. (For example, the ftp(s) wrapper doesn’t allow simultaneous reading and writing.)

Leave a Reply

  1.  

    |