iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 20
1
Modern Web

成為 Modern PHPer系列 第 20

Day 20:Stream Filter 的使用

  • 分享至 

  • xImage
  •  

前言

關於 Stream 也到第三篇文章了,倒也不是因為這個 Feature 很重要,只是因為這個主題所涵蓋的範圍太廣了,只能花這麼多篇幅來敘述。

我們已經在前兩天的文章中瞭解到:Stream 是一個操作串流的特性,無論該串流是來自於檔案、網路服務還是其它任何資訊,PHP 僅是把這些操作抽象化成為一個概念。

介紹

Filter 中文譯為「過濾器」,偍我通常不會對其進行翻譯,而會以 Stream Filter 這樣的名稱去稱呼它。

根據官方文件的定義,Stream Filter 是針對最後一塊可被讀取/寫入的 Steam 進行操作的功能。例如,我們可以利用 string.touppper 將字串轉為大寫:

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

在 PHP 中已經提供許多預設 Filter 可供使用,可以利用 stream_get_filters() 查閱目前可以使用的 Filter。另外,官方文件也有提供列表可供查照。

使用

使用 Stream Filter 非常容易,只需要呼叫 stream_filter_append() 函式即可。

另外也可以在 PHP Stream 上直接使用 filter:php://filter/string.toupper/resource={檔案名稱}

進階設計

自定義 Stream Filter

除了使用預設的 Stream Filter 之外,PHP 也允許我們自定義 Stream Filter。

以下範例改寫自 PHP 官方文件

<?php
class StrToupper extends php_user_filter
{
    public function filter($in, $out, &$consumed, $closing): int
    {
        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::class);

$output = fopen('php://output', 'w');
stream_filter_append($output, 'strtoupper');
fwrite($output, 'this is a test.'); // THIS IS A TEST.

Stream Filter 與 LFI 的安全風險

LFI,全名 Locale File Inclusion。

在 PHP 中,LFI 的發生通常與不正確的引入檔案有關,通常會牽涉到 includerequire 兩個關鍵字。

舉例而言,以下程式存在 LFI 的安全風險

<?php

include file_exists($_GET['page']) ? $_GET['page'] : 'index.php';

此時,若我輸入 /?page=../../../../etc/passwd(視目前檔案位置而定,可能需要增減 ../ 的數量),就可以取得 /etc/passwd 的內容。

同時,因為 Stream 也可以被 include,所以我也可以輸入 /?page=php://filter/convert.base64-encode/resource=index,如此以來便可以取得一串 base64 encoded 字串,這個字串解析後就是 index.php 的原始碼。

註:這個我在 PTT PHP 版的 https://www.ptt.cc/bbs/PHP/M.1527504207.A.92A.html 一文中的第二個問題有提到,算是剛好對 Stream Filter 做一個補充。

後記

1999 年 9 月 21 日,當時我五歲。20 年後的今天我能夠在這裡寫文,必須感謝當時人們的無私奉獻與付出。


上一篇
Day 19:自定義 Stream
下一篇
Day 21:Callable 類型
系列文
成為 Modern PHPer30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言