最近在看《Modern PHP》,发现以前没有用过流过滤器,学习记录一下。
桶:总所周知(好吧,我才知道),PHP流会把数据分成按次序排列的桶,一个桶中城防的数据流量是固定的(如4096字节)。流过滤器一次能接受一个或多个桶。一定时间内过滤器接收到的桶叫做桶队列。
PS:每个桶对象都有两个公开属性:data
和datalen
.分别是桶内容和内容长度。
<?php
/**
* 脏词过滤器
* 1.自定义过滤器必须扩展内置的php_user_filter类
* 2.实现filter()方法
* 3.在stream_filter_register()函数注册自己的过滤器
*/
class DirtyWordsFilter extends php_user_filter
{
/**
* 该方法内实现过滤
* @param resource $in 流来的桶队列
* @param resource $out 流走的桶队列
* @param int &$consumed 处理的字节数
* @param bool $closing 是否是最后一个桶队列
*/
public function filter($in, $out, &$consumed, $closing)
{
$words = array('grime', 'grease', 'dirt', 'fuck');//脏词,可配置到文件中。
$wordData = array();
foreach ($words as $word) {
$replacement = array_fill(0, mb_strlen($word), '*');
$wordData[$word] = implode('', $replacement);//将脏词跟和谐符号(*)以键值对存放
}
$bad = array_keys($wordData);
$good = array_values($wordData);
/**
* (PHP 5)
* stream_bucket_make_writeable — Return a bucket object from the brigade for operating on
*
* (PHP 5, PHP 7)
* stream_bucket_append — Append bucket to brigade
*
* PSFS_PASS_ON Filter processed successfully with data available in the out bucket brigade.
*/
while ($bucket = stream_bucket_make_writeable($in)) {//迭代每个桶
$bucket->data = str_replace($bad, $good, $bucket->data);//替换
$consumed += $bucket->datalen;//增加已经处理的数据量
stream_bucket_append($out, $bucket);//将该桶对象放入流向下游的队列
}
return PSFS_PASS_ON;
}
}
stream_filter_register('dirty_words_filter', 'DirtyWordsFilter');//注册流过滤器
//测试环节
$handle = fopen('data.txt', 'rb');
stream_filter_append($handle, 'dirty_words_filter');
while (feof($handle) !== true) {
echo fgets($handle);
}
fclose($handle);
//data.txt: 'Hi, you grime,haha grease dirt, this is a fuck'
//输出:'Hi, you *****,haha ****** ****, this is a ****'