首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 流上下文與通知器機制:選項、參數、通知回調完整解析

     編輯:PHP 綜合知識

流上下文 (php_stream_context) 為流操作提供額外配置與事件通知機制。本文解析上下文選項/參數架構、php_stream_context_set_option/get_option API、HTTP 包裝器實際使用範例、通知器 (php_stream_notifier) 結構與進度回調實作。

上下文結構

typedef struct _php_stream_context {
    HashTable *options;   // 二維陣列:wrapper -> option -> zval
    HashTable *params;    // 參數:通知器等
    // ...
} php_stream_context;

建立與銷毀

php_stream_context *context = php_stream_context_alloc(TSRMLS_C);
// 自動註冊為請求級資源,請求結束自動釋放

// 手動釋放 (罕見需求)
php_stream_context_free(context);

設定選項

// 內部 API
int php_stream_context_set_option(
    php_stream_context *context,
    const char *wrappername,   // 如 "http", "ftp", "ssl"
    const char *optionname,    // 如 "user_agent", "method", "header"
    zval *optionvalue          // 值 (字串/整數/陣列)
);

// 使用者空間對應
// stream_context_set_option($context, $wrapper, $option, $value);

實戰:覆寫 HTTP User-Agent

php_stream *php_varstream_get_homepage(const char *alt_user_agent TSRMLS_DC) {
    php_stream_context *context = php_stream_context_alloc(TSRMLS_C);
    
    zval tmpval;
    ZVAL_STRING(&tmpval, alt_user_agent, 0); // 0=不複製,臨時字串
    php_stream_context_set_option(context, "http", "user_agent", &tmpval);
    
    return php_stream_open_wrapper_ex(
        "https://www.php.net", "rb",
        REPORT_ERRORS | ENFORCE_SAFE_MODE,
        NULL, context
    );
}

注意:php_stream_context_set_option 內部會**複製** zval 內容,傳入的臨時 zval 可安全銷毀。

取得選項

int php_stream_context_get_option(
    php_stream_context *context,
    const char *wrappername,
    const char *optionname,
    zval ***optionvalue  // 輸出:指向 zval** 的指標
);

HTTP 包裝器讀取 User-Agent 實作簡化版

zval **ua_zval;
char *user_agent = "PHP/5.1.0"; // 預設值

if (context && 
    php_stream_context_get_option(context, "http", "user_agent", &ua_zval) == SUCCESS &&
    Z_TYPE_PP(ua_zval) == IS_STRING) {
    user_agent = Z_STRVAL_PP(ua_zval);
}

處理非字串選項 (如 max_redirects 整數)

long max_redirects = 20; // 預設
zval **tmpzval;

if (context && 
    php_stream_context_get_option(context, "http", "max_redirects", &tmpzval) == SUCCESS) {
    
    if (Z_TYPE_PP(tmpzval) == IS_LONG) {
        max_redirects = Z_LVAL_PP(tmpzval);
    } else {
        // 型別轉換:隔離複製 → 轉換 → 使用 → 銷毀
        zval copyval = **tmpzval;
        zval_copy_ctor(©val);
        convert_to_long(©val);
        max_redirects = Z_LVAL(copyval);
        zval_dtor(©val); // 釋放複製體記憶體
    }
}

上下文參數:通知器

typedef struct {
    php_stream_notification_func func;  // 回調函式
    void (*dtor)(php_stream_notifier *notifier); // 通知器銷毀器
    void *ptr;                          // 使用者自訂資料
    int mask;                           // 事件遮罩
    size_t progress, progress_max;      // 進度追蹤
} php_stream_notifier;

事件遮罩常數

常數觸發時機
PHP_STREAM_NOTIFIER_CONNECT連線建立
PHP_STREAM_NOTIFIER_AUTH_REQUIRED需要認證
PHP_STREAM_NOTIFIER_AUTH_RESULT認證結果
PHP_STREAM_NOTIFIER_MIME_TYPE_ISMIME 型別確定
PHP_STREAM_NOTIFIER_PROGRESS傳輸進度更新
PHP_STREAM_NOTIFIER_COMPLETED傳輸完成
PHP_STREAM_NOTIFIER_FAILURE傳輸失敗
PHP_STREAM_NOTIFIER_REDIRECTED重導向發生

設定通知器範例

void my_notification_func(php_stream_context *context,
    int notify_code, int severity,
    char *xmsg, int xcode,
    size_t bytes_sofar, size_t bytes_max,
    void *ptr TSRMLS_DC) {
    
    switch (notify_code) {
        case PHP_STREAM_NOTIFIER_PROGRESS:
            php_printf("Progress: %zu / %zu\n", bytes_sofar, bytes_max);
            break;
        case PHP_STREAM_NOTIFIER_COMPLETED:
            php_printf("Download completed!\n");
            break;
        case PHP_STREAM_NOTIFIER_FAILURE:
            php_printf("Download failed: %s\n", xmsg);
            break;
    }
}

// 在 context 中安裝通知器
php_stream_context *context = php_stream_context_alloc(TSRMLS_C);
php_stream_notifier *notifier = emalloc(sizeof(php_stream_notifier));
notifier->func = my_notification_func;
notifier->mask = PHP_STREAM_NOTIFIER_PROGRESS | PHP_STREAM_NOTIFIER_COMPLETED | PHP_STREAM_NOTIFIER_FAILURE;
context->params = emalloc(sizeof(HashTable));
zend_hash_init(context->params, 0, NULL, NULL, 0);
zend_hash_add(context->params, "notification", sizeof("notification"), ¬ifier, sizeof(notifier), NULL);

常用 HTTP 選項速查

選項型別說明
methodStringGET/POST/PUT/DELETE 等
headerString/Array額外請求標頭
user_agentStringUser-Agent 標頭
contentStringPOST/PUT 請求體
max_redirectsInteger最大重導向次數
timeoutFloat連線/讀取逾時 (秒)
follow_locationBoolean是否自動追蹤重導向
ignore_errorsBoolean非 2xx 狀態碼不視為錯誤
proxyString代理伺服器 URL
sslArraySSL 選項 (verify_peer, cafile, local_cert 等)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved