views:

178

answers:

2

Is there a way to attach a stream filter to echo so that any data that is echoed goes through the stream filter? My idea is to write an output escaping filter to protect against XSS.

I found this bug report http://bugs.php.net/bug.php?id=30583 but it is from 2004 and I didn't know if this is now possible or not.

class strtoupper_filter extends php_user_filter 
{
  function filter($in, $out, &$consumed, $closing)
  {
   while ($bucket = stream_bucket_make_writeable($in)) {
     $bucket->data = strtoupper($bucket->data);
     $consumed += $bucket->datalen;
     stream_bucket_append($out, $bucket);
   }
   return PSFS_PASS_ON;
  }
}
stream_filter_register("strtoupper", "strtoupper_filter");

$fp = fopen("php://output", "w");
stream_filter_append($fp, "strtoupper");

echo "echo: testing 123<br>";
print("print: testing 123<br>");
fwrite($fp, "fwrite: testing 123<br>");
A: 

You can use output buffering for any filter job.

<?php
function my_filter($data) {
    return strtoupper($data);
}
ob_start('my_filter', 1); // Chunk size of 1 is same as 4096
echo 'test';
ob_end_flush(); // Or end of script

Any complexer example is possible.

eisberg
Good idea except that would filter everything. If I have a PHP script that includes PHP code and HTML I would only want the stuff that PHP outputs to go through the filter and not have the HTML code filtered.
ejunker
Do you mean data outside of any <?php ?> tag when you say HTML? If not just filter your filter ;) with preg_match.
eisberg
+1  A: 

You could always just make a special 'echo' function of your own that contains the filter. Then replace all of the echo's in your code with your custom function.

<?php
function filtered_echo($data) {
    // filter $data here
    echo $data;
}
?>
NULL