php8.5
Home/ Manual/ appendices/ List of Available Filters

List of Available Filters

The following is a list of a few built-in stream filters for use with stream_filter_append. Your version of PHP may have more filters (or fewer) than those listed here.

The following is a list of a few built-in stream filters for use with stream_filter_append(). Your version of PHP may have more filters (or fewer) than those listed here.

It is worth noting a slight asymmetry between stream_filter_append() and stream_filter_prepend(). Every PHP stream contains a small read buffer where it stores blocks of data retrieved from the filesystem or other resource in order to process data in the most efficient manner. As soon as data is pulled from the resource into the stream's internal buffer, it is immediately processed through any attached filters whether the PHP application is actually ready for the data or not. If data is sitting in the read buffer when a filter is appended, this data will be immediately processed through that filter making the fact that it was sitting in the buffer seem transparent. However, if data is sitting in the read buffer when a filter is prepended, this data will NOT be processed through that filter. It will instead wait until the next block of data is retrieved from the resource.

For a list of filters installed in your version of PHP use stream_get_filters().

String Filters

Each of these filters does precisely what their name implies and correspond to the behavior of a built-in php string handling function. For more information on a given filter, refer to the manual page for the corresponding function.

string.rot13

Use of this filter is equivalent to processing all stream data through the str_rot13() function.

string.rot13

php
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'string.rot13');
fwrite($fp, "This is a test.\n");
/* Outputs:  Guvf vf n grfg.   */
?>

string.toupper

Use of this filter is equivalent to processing all stream data through the strtoupper() function.

string.toupper

php
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'string.toupper');
fwrite($fp, "This is a test.\n");
/* Outputs:  THIS IS A TEST.   */
?>

string.tolower

Use of this filter is equivalent to processing all stream data through the strtolower() function.

string.tolower

php
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'string.tolower');
fwrite($fp, "This is a test.\n");
/* Outputs:  this is a test.   */
?>

string.strip_tags

Use of this filter is equivalent to processing all stream data through the strip_tags() function. It accepts parameters in one of two forms: Either as a string containing a list of tags similar to the second parameter of the strip_tags() function, or as an array of tag names.

Feature-7-3-0

string.strip_tags

php
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE, "<b><i><u>");
fwrite($fp, "<b>bolded text</b> enlarged to a <h1>level 1 heading</h1>\n");
fclose($fp);
/* Outputs:  bolded text enlarged to a level 1 heading   */

$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE, array('b','i','u'));
fwrite($fp, "<b>bolded text</b> enlarged to a <h1>level 1 heading</h1>\n");
fclose($fp);
/* Outputs:  bolded text enlarged to a level 1 heading   */
?>

Conversion Filters

Like the string.* filters, the convert.* filters perform actions similar to their names. For more information on a given filter, refer to the manual page for the corresponding function.

convert.base64-encode and convert.base64-decode

Use of these filters are equivalent to processing all stream data through the base64_encode() and base64_decode() functions respectively. convert.base64-encode supports parameters given as an associative array. If line-length is given, the base64 output will be split into chunks of line-length characters each. If line-break-chars is given, each chunk will be delimited by the characters given. These parameters give the same effect as using base64_encode() with chunk_split().

convert.base64-encode & convert.base64-decode

php
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'convert.base64-encode');
fwrite($fp, "This is a test.\n");
fclose($fp);
/* Outputs:  VGhpcyBpcyBhIHRlc3QuCg==  */

$param = array('line-length' => 8, 'line-break-chars' => "\r\n");
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'convert.base64-encode', STREAM_FILTER_WRITE, $param);
fwrite($fp, "This is a test.\n");
fclose($fp);
/* Outputs:  VGhpcyBp
          :  cyBhIHRl
          :  c3QuCg==  */

$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'convert.base64-decode');
fwrite($fp, "VGhpcyBpcyBhIHRlc3QuCg==");
fclose($fp);
/* Outputs:  This is a test.  */
?>

convert.quoted-printable-encode and convert.quoted-printable-decode

Use of the decode version of this filter is equivalent to processing all stream data through the quoted_printable_decode() function. There is no function equivalent to convert.quoted-printable-encode. convert.quoted-printable-encode supports parameters given as an associative array. In addition to the parameters supported by convert.base64-encode, convert.quoted-printable-encode also supports boolean arguments binary and force-encode-first. convert.base64-decode only supports the line-break-chars parameter as a type-hint for stripping from the encoded payload.

convert.quoted-printable-encode & convert.quoted-printable-decode

php
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'convert.quoted-printable-encode');
fwrite($fp, "This is a test.\n");
/* Outputs:  =This is a test.=0A  */
?>

convert.iconv.*

The convert.iconv.* filters are available, if iconv support is enabled, and their use is equivalent to processing all stream data with iconv(). These filters do not support parameters, but instead expect the input and output encodings to be given as part of the filter name, i.e. either as convert.iconv.<input-encoding>.<output-encoding> or convert.iconv.<input-encoding>/<output-encoding> (both notations are semantically equivalent).

convert.iconv.*

php
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'convert.iconv.utf-16le.utf-8');
fwrite($fp, "T\0h\0i\0s\0 \0i\0s\0 \0a\0 \0t\0e\0s\0t\0.\0\n\0");
fclose($fp);
/* Outputs: This is a test. */
?>

Compression Filters

While the Compression Wrappers provide a way of creating gzip and bz2 compatible files on the local filesystem, they do not provide a means for generalized compression over network streams, nor do they provide a means to begin with a non-compressed stream and transition to a compressed one. For this, a compression filter may be applied to any stream resource at any time.

Note

Compression filters do not generate headers and trailers used by command line utilities such as gzip. They only compress and decompress the payload portions of compressed data streams.

zlib.deflate and zlib.inflate

zlib.deflate (compression) and zlib.inflate (decompression) are implementations of the compression methods described in RFC 1951. The deflate filter takes up to three parameters passed as an associative array. level describes the compression strength to use (1-9). Higher numbers will generally yield smaller payloads at the cost of additional processing time. Two special compression levels also exist: 0 (for no compression at all), and -1 (zlib internal default -- currently 6). window is the base-2 log of the compression loopback window size. Higher values (up to 15 -- 32768 bytes) yield better compression at a cost of memory, while lower values (down to 9 -- 512 bytes) yield worse compression in a smaller memory footprint. Default window size is currently 15. The zlib.deflate filter implements the compression methods DEFLATE, ZLIB and GZIP depending on the value of the window parameter. The 4 lower bits of the window parameter set the size of the internal “history buffer” used, being the base-2 logarithm of its size in a range from 8 up to 15. The meaning of the others bits of the window parameter can be set as described below.

  • DEFLATE (RFC 1951) is a raw compression algorithm without header, without checksum. It is performed when the window parameter is set in the range from -9 up to -15. This compression algorithm is the base for all the formats generated by the zlib.deflate filter. The corresponding functions that operate directly on strings are gzdeflate() and gzinflate().
  • ZLIB (RFC 1950) applies the DEFLATE algorithm and adds a 2 bytes header and 4 bytes trailer containing the Adler32 checksum of the uncompressed data in big-endian byte order: ZLIB = ZLIBHEADER(2B) DEFLATE ADLER32(4B) The 2 bytes header, read as 16 bit unsigned number in big-endian order, must be multiple of 31. This format is generated when the window parameter is set in the range from 8 up to 15. The corresponding functions that operate directly on strings are gzcompress() and gzuncompress().
  • GZIP (RFC 1952) applies the DEFLATE algorithm adding an header and a trailer with the CRC32 checksum of the uncompressed data and their length, both in little-endian byte ordering: GZIP = GZIPHEADER(10B) DEFLATE CRC32(4B) LENGTH(4B) This is the format of the .gz files, with the GZIPHEADER containing in the order the GZIP signature (\x1f\x8B), the compression method (\x08), a zero flag byte, a zero modification time on 4 bytes, an extra-flags byte that depends on the compression level, and the operating system set to the current system (\x00 = FAT filesystem, \x03 = Unix, etc.). This format is generated when the window parameter is set in the range from 9+16=25 up to 15+16=31. Note that there is a limit of 4GB to the maximum length of the uncompressed data; beyond this limit, only the modulo 2^32 of the actual length is stored in the LENGTH part. The corresponding functions that operate directly on strings are gzencode() and gzdecode(); the gzopen() function allows to read and write .gz files.

With the zlib.inflate filter, only the window parameter is allowed; any other parameter (memory, level) is ignored. Be $W the base-2 log of the history buffer size, so that 2^$W bytes are allocated by the decompressor. For the ZLIB format this value must be greater or equal to the one recorded in the header, which is checked at decompression time; for the other formats it only has to be large enough for the match distances actually present in the data. The range is 9 ≤ $W ≤ 15. If unknown, $W=15 is the safer choice.

  • DEFLATE (RFC 1951): use window=-$W, with $W being a value not less than that used for compression. If unknown, set window=-15.
  • ZLIB (RFC 1950): use window=$W. The value of $W is available from the same ZLIB header, otherwise set window=15.
  • GZIP (RFC 1952): use window=$W+16. A GZIP header carries no window size, so set window=31 unless the value used for compression is known.
  • ZLIB or GZIP: use window=$W+32 for automatic header detection, so that both the formats can be recognized and decompressed; window=15+32=47 is the safer choice.

memory is a scale indicating how much work memory should be allocated. Valid values range from 1 (minimal allocation) to 9 (maximum allocation). This memory allocation affects speed only and does not impact the size of the generated payload.

Note

Because compression level is the most commonly used parameter, it may be alternatively provided as a simple integer value (rather than an array element).

zlib.* compression filters are available if zlib support is enabled.

zlib.deflate and zlib.inflate

php
<?php
$params = array('level' => 6, 'window' => 15, 'memory' => 9);

$original_text = "This is a test.\nThis is only a test.\nThis is not an important string.\n";
echo "The original text is " . strlen($original_text) . " characters long.\n";

$fp = fopen('test.deflated', 'w');
stream_filter_append($fp, 'zlib.deflate', STREAM_FILTER_WRITE, $params);
fwrite($fp, $original_text);
fclose($fp);

echo "The compressed file is " . filesize('test.deflated') . " bytes long.\n";
echo "The original text was:\n";
/* Use readfile and zlib.inflate to decompress on the fly */
readfile('php://filter/zlib.inflate/resource=test.deflated');

/* Generates output:

The original text is 70 characters long.
The compressed file is 56 bytes long.
The original text was:
This is a test.
This is only a test.
This is not an important string.

 */
?>

zlib.deflate simple

php
<?php
$original_text = "This is a test.\nThis is only a test.\nThis is not an important string.\n";
echo "The original text is " . strlen($original_text) . " characters long.\n";

$fp = fopen('test.deflated', 'w');
/* Here "6" indicates compression level 6 */
stream_filter_append($fp, 'zlib.deflate', STREAM_FILTER_WRITE, 6);
fwrite($fp, $original_text);
fclose($fp);

echo "The compressed file is " . filesize('test.deflated') . " bytes long.\n";

/* Generates output:

The original text is 70 characters long.
The compressed file is 56 bytes long.

 */
?>

bzip2.compress and bzip2.decompress

bzip2.compress and bzip2.decompress work in the same manner as the zlib filters described above. The bzip2.compress filter accepts up to two parameters given as elements of an associative array: blocks is an integer value from 1 to 9 specifying the number of 100kbyte blocks of memory to allocate for workspace. work is also an integer value ranging from 0 to 250 indicating how much effort to expend using the normal compression method before falling back on a slower, but more reliable method. Tuning this parameter effects only compression speed. Neither size of compressed output nor memory usage are changed by this setting. A work factor of 0 instructs the bzip library to use an internal default. The bzip2.decompress filter only accepts one parameter, which can be passed as either an ordinary boolean value, or as the small element of an associative array. small, when set to a true value, instructs the bzip library to perform decompression in a minimal memory footprint at the cost of speed.

bzip2.* compression filters are available if bz2 support is enabled.

bzip2.compress and bzip2.decompress

php
<?php
$param = array('blocks' => 9, 'work' => 0);

echo "The original file is " . filesize('LICENSE') . " bytes long.\n";

$fp = fopen('LICENSE.compressed', 'w');
stream_filter_append($fp, 'bzip2.compress', STREAM_FILTER_WRITE, $param);
fwrite($fp, file_get_contents('LICENSE'));
fclose($fp);

echo "The compressed file is " . filesize('LICENSE.compressed') . " bytes long.\n";

/* Generates output:

The original file is 3288 bytes long.
The compressed file is 1488 bytes long.

 */
?>

Encryption Filters

Encryption filters are especially useful for file/stream encryption.

mcrypt.* and mdecrypt.*

Feature-7-1-0

mcrypt.* and mdecrypt.* provide symmetric encryption and decryption using libmcrypt. Both sets of filters support the same algorithms available to mcrypt extension in the form of mcrypt.ciphername where ciphername is the name of the cipher as it would be passed to mcrypt_module_open(). The following five filter parameters are also available:

ParameterRequired?DefaultSample Values
modeOptionalcbccbc, cfb, ecb, nofb, ofb, stream
algorithms_dirOptionalini_get('mcrypt.algorithms_dir')Location of algorithms modules
modes_dirOptionalini_get('mcrypt.modes_dir')Location of modes modules
ivRequiredN/ATypically 8, 16, or 32 bytes of binary data. Depends on cipher
keyRequiredN/ATypically 8, 16, or 32 bytes of binary data. Depends on cipher

Encrypt/Decrypt with Blowfish

php
<?php
//$key assumed to be previously generated
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);
$fp = fopen('encrypted-file.enc', 'wb');
fwrite($fp, $iv);
$opts = array('mode'=>'cbc','iv'=>$iv, 'key'=>$key);
stream_filter_append($fp, 'mcrypt.blowfish', STREAM_FILTER_WRITE, $opts);
fwrite($fp, 'message to encrypt');
fclose($fp);

//decrypt...
$fp = fopen('encrypted-file.enc', 'rb');
$iv = fread($fp, $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC));
$opts = array('mode'=>'cbc','iv'=>$iv, 'key'=>$key);
stream_filter_append($fp, 'mdecrypt.blowfish', STREAM_FILTER_READ, $opts);
$data = rtrim(stream_get_contents($fp));//trims off null padding
fclose($fp);
echo $data;
?>

Encrypt file using AES-128 CBC with SHA256 HMAC

php
<?php
AES_CBC::encryptFile($password, "plaintext.txt", "encrypted.enc");
AES_CBC::decryptFile($password, "encrypted.enc", "decrypted.txt");

class AES_CBC
{
   protected static $KEY_SIZES = array('AES-128'=>16,'AES-192'=>24,'AES-256'=>32);
   protected static function key_size() { return self::$KEY_SIZES['AES-128']; } //default AES-128
   public static function encryptFile($password, $input_stream, $aes_filename){
      $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
      $fin = fopen($input_stream, "rb");
      $fc = fopen($aes_filename, "wb+");
      if (!empty($fin) && !empty($fc)) {
         fwrite($fc, str_repeat("_", 32) );//placeholder, SHA256 HMAC will go here later
         fwrite($fc, $hmac_salt = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM));
         fwrite($fc, $esalt = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM));
         fwrite($fc, $iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM));
         $ekey = hash_pbkdf2("sha256", $password, $esalt, $it=1000, self::key_size(), $raw=true);
         $opts = array('mode'=>'cbc', 'iv'=>$iv, 'key'=>$ekey);
         stream_filter_append($fc, 'mcrypt.rijndael-128', STREAM_FILTER_WRITE, $opts);
         $infilesize = 0;
         while (!feof($fin)) {
            $block = fread($fin, 8192);
            $infilesize+=strlen($block);
            fwrite($fc, $block);
         }
         $block_size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
         $padding = $block_size - ($infilesize % $block_size);//$padding is a number from 1-16
         fwrite($fc, str_repeat(chr($padding), $padding) );//perform PKCS7 padding
         fclose($fin);
         fclose($fc);
         $hmac_raw = self::calculate_hmac_after_32bytes($password, $hmac_salt, $aes_filename);
         $fc = fopen($aes_filename, "rb+");
         fwrite($fc, $hmac_raw);//overwrite placeholder
         fclose($fc);
      }
   }
   public static function decryptFile($password, $aes_filename, $out_stream) {
      $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
      $hmac_raw = file_get_contents($aes_filename, false, NULL,  0, 32);
      $hmac_salt = file_get_contents($aes_filename, false, NULL, 32, $iv_size);
      $hmac_calc = self::calculate_hmac_after_32bytes($password, $hmac_salt, $aes_filename);
      $fc = fopen($aes_filename, "rb");
      $fout = fopen($out_stream, 'wb');
      if (!empty($fout) && !empty($fc) && self::hash_equals($hmac_raw,$hmac_calc)) {
         fread($fc, 32+$iv_size);//skip sha256 hmac and salt
         $esalt = fread($fc, $iv_size);
         $iv    = fread($fc, $iv_size);
         $ekey = hash_pbkdf2("sha256", $password, $esalt, $it=1000, self::key_size(), $raw=true);
         $opts = array('mode'=>'cbc', 'iv'=>$iv, 'key'=>$ekey);
         stream_filter_append($fc, 'mdecrypt.rijndael-128', STREAM_FILTER_READ, $opts);
         while (!feof($fc)) {
            $block = fread($fc, 8192);
            if (feof($fc)) {
               $padding = ord($block[strlen($block) - 1]);//assume PKCS7 padding
               $block = substr($block, 0, 0-$padding);
            }
            fwrite($fout, $block);
         }
         fclose($fout);
         fclose($fc);
      }
   }
   private static function hash_equals($str1, $str2) {
      if(strlen($str1) == strlen($str2)) {
         $res = $str1 ^ $str2;
         for($ret=0,$i = strlen($res) - 1; $i >= 0; $i--) $ret |= ord($res[$i]);
         return !$ret;
      }
      return false;
   }
   private static function calculate_hmac_after_32bytes($password, $hsalt, $filename) {
      static $init=0;
      $init or $init = stream_filter_register("user-filter.skipfirst32bytes", "FileSkip32Bytes");
      $stream = 'php://filter/read=user-filter.skipfirst32bytes/resource=' . $filename;
      $hkey = hash_pbkdf2("sha256", $password, $hsalt, $iterations=1000, 24, $raw=true);
      return hash_hmac_file('sha256', $stream, $hkey, $raw=true);
   }
}
class FileSkip32Bytes extends php_user_filter
{
   private $skipped=0;
   function filter($in, $out, &$consumed, $closing)  {
      while ($bucket = stream_bucket_make_writeable($in)) {
         $outlen = $bucket->datalen;
         if ($this->skipped<32){
            $outlen = min($bucket->datalen,32-$this->skipped);
            $bucket->data = substr($bucket->data, $outlen);
            $bucket->datalen = $bucket->datalen-$outlen;
            $this->skipped+=$outlen;
         }
         $consumed += $outlen;
         stream_bucket_append($out, $bucket);
      }
      return PSFS_PASS_ON;
   }
}
class AES_128_CBC extends AES_CBC {
   protected static function key_size() { return self::$KEY_SIZES['AES-128']; }
}
class AES_192_CBC extends AES_CBC {
   protected static function key_size() { return self::$KEY_SIZES['AES-192']; }
}
class AES_256_CBC extends AES_CBC {
   protected static function key_size() { return self::$KEY_SIZES['AES-256']; }
}

Source: appendices/filters.xml · from the official PHP manual (php/doc-en)