[PHP]stream_context_get_options完全解説|ストリームコンテキストのオプション取得・デバッグ・活用法を実践サンプルで理解する

PHP

stream_context_get_optionsとは?

stream_context_get_options() は、ストリームコンテキストリソースに設定されているオプションを連想配列として取得する関数です。

stream_context_create()stream_context_get_default() で設定したオプション(タイムアウト・HTTPメソッド・ヘッダー・SSLオプションなど)を後から確認・検査するために使います。設定内容のデバッグ、ログ出力、テスト時のアサーション、環境ごとの設定検証など、幅広い用途で活躍します。


基本構文

stream_context_get_options(resource $context): array
引数説明
$contextresourcestream_context_create() などで作成したコンテキストリソース
戻り値arrayラッパー名をキーとするネストした連想配列

戻り値の構造

[
    'http' => [
        'method'  => 'POST',
        'timeout' => 10,
        // ...
    ],
    'ssl' => [
        'verify_peer' => true,
        // ...
    ],
]

基本的な使い方

<?php
$options = [
    'http' => [
        'method'     => 'GET',
        'timeout'    => 10,
        'user_agent' => 'MyApp/1.0',
    ],
    'ssl' => [
        'verify_peer' => true,
    ],
];

$context = stream_context_create($options);

// 設定済みオプションを取得
$retrieved = stream_context_get_options($context);

echo $retrieved['http']['method'];     // GET
echo $retrieved['http']['timeout'];    // 10
echo $retrieved['ssl']['verify_peer']; // 1 (true)

実践クラスサンプル

サンプル1:コンテキストの内容を整形して出力するデバッグクラス

開発中にコンテキストの設定内容を見やすくダンプします。

<?php

class StreamContextDebugger
{
    public static function dump(resource $context, string $label = 'Context'): void
    {
        $options = stream_context_get_options($context);

        echo "=== {$label} ===\n";

        if (empty($options)) {
            echo "  (オプションなし)\n";
            return;
        }

        foreach ($options as $wrapper => $settings) {
            echo "\n[{$wrapper}]\n";
            foreach ($settings as $key => $value) {
                $display = match (true) {
                    is_bool($value)   => $value ? 'true' : 'false',
                    is_array($value)  => json_encode($value, JSON_UNESCAPED_UNICODE),
                    is_string($value) => "\"{$value}\"",
                    default           => (string)$value,
                };
                echo "  {$key}: {$display}\n";
            }
        }

        echo "\n";
    }

    public static function dumpDefault(string $label = 'Default Context'): void
    {
        self::dump(stream_context_get_default(), $label);
    }
}

// 使用例
$ctx = stream_context_create([
    'http' => [
        'method'        => 'POST',
        'timeout'       => 30,
        'ignore_errors' => true,
        'header'        => "Content-Type: application/json\r\nAccept: application/json",
    ],
    'ssl' => [
        'verify_peer'      => true,
        'verify_peer_name' => true,
    ],
]);

StreamContextDebugger::dump($ctx, 'APIリクエストコンテキスト');

実行結果:

=== APIリクエストコンテキスト ===

[http]

method: “POST” timeout: 30 ignore_errors: true header: “Content-Type: application/json\r\nAccept: application/json”

[ssl]

verify_peer: true verify_peer_name: true


サンプル2:オプションを検証するバリデーションクラス

コンテキストに必須オプションが正しく設定されているか確認します。

<?php

class StreamContextValidator
{
    /** @var array<string, array<string, mixed>> */
    private array $rules = [];

    public function require(string $wrapper, string $key): static
    {
        $this->rules[$wrapper][$key] = ['type' => 'required'];
        return $this;
    }

    public function expect(string $wrapper, string $key, mixed $value): static
    {
        $this->rules[$wrapper][$key] = ['type' => 'equals', 'value' => $value];
        return $this;
    }

    public function validate(resource $context): array
    {
        $options = stream_context_get_options($context);
        $errors  = [];

        foreach ($this->rules as $wrapper => $keys) {
            foreach ($keys as $key => $rule) {
                $actual = $options[$wrapper][$key] ?? null;

                if ($rule['type'] === 'required' && $actual === null) {
                    $errors[] = "[{$wrapper}].{$key} は必須です";
                }

                if ($rule['type'] === 'equals' && $actual !== $rule['value']) {
                    $expected = var_export($rule['value'], true);
                    $got      = var_export($actual, true);
                    $errors[] = "[{$wrapper}].{$key}: 期待={$expected}, 実際={$got}";
                }
            }
        }

        return $errors;
    }

    public function isValid(resource $context): bool
    {
        return empty($this->validate($context));
    }
}

// 使用例
$ctx = stream_context_create([
    'http' => [
        'method'      => 'POST',
        'timeout'     => 30,
        'user_agent'  => 'MyApp/1.0',
    ],
    'ssl' => [
        'verify_peer' => true,
    ],
]);

$validator = (new StreamContextValidator())
    ->require('http', 'method')
    ->require('http', 'timeout')
    ->expect('http', 'method', 'POST')
    ->expect('ssl',  'verify_peer', true)
    ->require('http', 'user_agent');

$errors = $validator->validate($ctx);

if (empty($errors)) {
    echo "✓ コンテキスト検証OK\n";
} else {
    foreach ($errors as $error) {
        echo "✗ {$error}\n";
    }
}

サンプル3:既存コンテキストにオプションをマージして新規作成するクラス

stream_context_get_options() で現在値を取得し、部分的に上書きして新しいコンテキストを生成します。

<?php

class StreamContextMerger
{
    /**
     * 既存コンテキストのオプションに $overrides をディープマージして
     * 新しいコンテキストリソースを返す(元のコンテキストは変更しない)
     */
    public static function merge(resource $base, array $overrides): resource
    {
        $baseOptions   = stream_context_get_options($base);
        $mergedOptions = self::deepMerge($baseOptions, $overrides);
        return stream_context_create($mergedOptions);
    }

    private static function deepMerge(array $base, array $override): array
    {
        foreach ($override as $key => $value) {
            if (is_array($value) && isset($base[$key]) && is_array($base[$key])) {
                $base[$key] = self::deepMerge($base[$key], $value);
            } else {
                $base[$key] = $value;
            }
        }
        return $base;
    }

    public static function diff(resource $ctxA, resource $ctxB): array
    {
        $optA = stream_context_get_options($ctxA);
        $optB = stream_context_get_options($ctxB);
        $diff = [];

        $wrappers = array_unique(array_merge(array_keys($optA), array_keys($optB)));

        foreach ($wrappers as $wrapper) {
            $keysA = $optA[$wrapper] ?? [];
            $keysB = $optB[$wrapper] ?? [];
            $keys  = array_unique(array_merge(array_keys($keysA), array_keys($keysB)));

            foreach ($keys as $key) {
                $valA = $keysA[$key] ?? '(未設定)';
                $valB = $keysB[$key] ?? '(未設定)';
                if ($valA !== $valB) {
                    $diff["{$wrapper}.{$key}"] = ['before' => $valA, 'after' => $valB];
                }
            }
        }

        return $diff;
    }
}

// 使用例
$base = stream_context_create([
    'http' => ['method' => 'GET', 'timeout' => 10, 'user_agent' => 'Base/1.0'],
    'ssl'  => ['verify_peer' => true],
]);

// タイムアウトだけ変更した新しいコンテキストを作成
$extended = StreamContextMerger::merge($base, [
    'http' => ['timeout' => 60, 'user_agent' => 'Extended/2.0'],
]);

// 差分を確認
$diff = StreamContextMerger::diff($base, $extended);
echo "=== コンテキストの差分 ===\n";
foreach ($diff as $path => $change) {
    $before = var_export($change['before'], true);
    $after  = var_export($change['after'],  true);
    echo "  {$path}: {$before} → {$after}\n";
}

サンプル4:コンテキストをシリアライズ・復元するクラス

設定内容をJSONとして保存し、後から同一設定のコンテキストを再生成します。

<?php

class StreamContextSerializer
{
    public static function toJson(resource $context): string
    {
        $options = stream_context_get_options($context);
        return json_encode($options, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
    }

    public static function fromJson(string $json): resource
    {
        $options = json_decode($json, true, flags: JSON_THROW_ON_ERROR);
        return stream_context_create($options);
    }

    public static function saveToFile(resource $context, string $path): void
    {
        file_put_contents($path, self::toJson($context));
    }

    public static function loadFromFile(string $path): resource
    {
        if (!file_exists($path)) {
            throw new RuntimeException("設定ファイルが見つかりません: {$path}");
        }
        return self::fromJson(file_get_contents($path));
    }
}

// 使用例
$ctx = stream_context_create([
    'http' => [
        'method'      => 'POST',
        'timeout'     => 20,
        'user_agent'  => 'Serializer/1.0',
        'ignore_errors'=> true,
    ],
    'ssl' => ['verify_peer' => true],
]);

// JSON文字列として出力
$json = StreamContextSerializer::toJson($ctx);
echo "シリアライズ結果:\n{$json}\n\n";

// JSONから復元
$restored = StreamContextSerializer::fromJson($json);
$opts     = stream_context_get_options($restored);

echo "復元後のtimeout: "     . $opts['http']['timeout']    . "\n";
echo "復元後のuser_agent: "  . $opts['http']['user_agent'] . "\n";

// ファイルに保存・読み込み
// StreamContextSerializer::saveToFile($ctx, '/tmp/ctx_config.json');
// $ctxFromFile = StreamContextSerializer::loadFromFile('/tmp/ctx_config.json');

サンプル5:コンテキスト設定をログに記録するミドルウェアクラス

HTTP通信前後にコンテキスト内容をログへ出力します。

<?php

class StreamContextLogger
{
    private array $logs = [];

    public function logContext(resource $context, string $url, string $phase = 'request'): void
    {
        $options = stream_context_get_options($context);
        $http    = $options['http'] ?? [];
        $ssl     = $options['ssl']  ?? [];

        $entry = [
            'timestamp' => date('Y-m-d H:i:s'),
            'phase'     => $phase,
            'url'       => $url,
            'method'    => $http['method']     ?? 'GET',
            'timeout'   => $http['timeout']    ?? null,
            'ssl_verify'=> $ssl['verify_peer'] ?? null,
            'has_auth'  => str_contains($http['header'] ?? '', 'Authorization'),
        ];

        $this->logs[] = $entry;
        $this->printEntry($entry);
    }

    private function printEntry(array $entry): void
    {
        $auth = $entry['has_auth'] ? ' [認証あり]' : '';
        $ssl  = $entry['ssl_verify'] === null
            ? ''
            : (' SSL=' . ($entry['ssl_verify'] ? '検証あり' : '検証なし'));

        echo "[{$entry['timestamp']}] {$entry['phase']} {$entry['method']} {$entry['url']}"
           . " timeout={$entry['timeout']}{$ssl}{$auth}\n";
    }

    public function getLogs(): array
    {
        return $this->logs;
    }

    public function fetch(string $url, resource $context): string|false
    {
        $this->logContext($context, $url, 'request');
        $result = file_get_contents($url, false, $context);
        $this->logContext($context, $url, 'response');
        return $result;
    }
}

// 使用例
$ctx = stream_context_create([
    'http' => [
        'method'  => 'GET',
        'timeout' => 10,
        'header'  => "Authorization: Bearer token123\r\n",
    ],
    'ssl' => ['verify_peer' => true],
]);

$logger = new StreamContextLogger();
$body   = $logger->fetch('https://jsonplaceholder.typicode.com/todos/1', $ctx);

echo "\n取得データ:\n" . $body . "\n";

サンプル6:コンテキストを比較してセキュリティ設定を監査するクラス

本番環境に適したSSL・HTTP設定になっているか自動チェックします。

<?php

class StreamContextSecurityAuditor
{
    private array $warnings = [];

    public function audit(resource $context): array
    {
        $this->warnings = [];
        $options        = stream_context_get_options($context);

        $this->auditSsl($options['ssl']  ?? []);
        $this->auditHttp($options['http'] ?? []);

        return $this->warnings;
    }

    private function auditSsl(array $ssl): void
    {
        if (isset($ssl['verify_peer']) && $ssl['verify_peer'] === false) {
            $this->warnings[] = '[HIGH] ssl.verify_peer が false です。本番環境では必ず true にしてください。';
        }

        if (isset($ssl['verify_peer_name']) && $ssl['verify_peer_name'] === false) {
            $this->warnings[] = '[HIGH] ssl.verify_peer_name が false です。ホスト名検証が無効化されています。';
        }

        if (isset($ssl['allow_self_signed']) && $ssl['allow_self_signed'] === true) {
            $this->warnings[] = '[MEDIUM] ssl.allow_self_signed が true です。自己署名証明書が許可されています。';
        }
    }

    private function auditHttp(array $http): void
    {
        if (isset($http['timeout']) && $http['timeout'] > 60) {
            $this->warnings[] = "[LOW] http.timeout が {$http['timeout']} 秒です。長すぎる可能性があります。";
        }

        if (!isset($http['timeout'])) {
            $this->warnings[] = '[LOW] http.timeout が未設定です。デフォルト値(無制限)が適用されます。';
        }

        $header = $http['header'] ?? '';
        if (str_contains(strtolower($header), 'authorization') &&
            str_contains(strtolower($header), 'http://')) {
            $this->warnings[] = '[HIGH] HTTPでAuthorizationヘッダーを送信しています。HTTPSを使用してください。';
        }
    }

    public function printReport(resource $context): void
    {
        $warnings = $this->audit($context);
        $options  = stream_context_get_options($context);

        echo "=== セキュリティ監査レポート ===\n";
        echo "ラッパー: " . implode(', ', array_keys($options)) . "\n\n";

        if (empty($warnings)) {
            echo "✓ 問題は検出されませんでした\n";
        } else {
            foreach ($warnings as $warn) {
                echo "⚠ {$warn}\n";
            }
        }
    }
}

// 安全でない設定の例
$unsafeCtx = stream_context_create([
    'ssl'  => ['verify_peer' => false, 'allow_self_signed' => true],
    'http' => ['method' => 'GET'],  // timeout未設定
]);

$auditor = new StreamContextSecurityAuditor();
$auditor->printReport($unsafeCtx);

echo "\n";

// 安全な設定の例
$safeCtx = stream_context_create([
    'ssl'  => ['verify_peer' => true, 'verify_peer_name' => true],
    'http' => ['method' => 'GET', 'timeout' => 15],
]);

$auditor->printReport($safeCtx);

サンプル7:コンテキストの設定内容をもとに処理を分岐するルータークラス

取得したオプション内容を読んで、処理戦略を自動選択します。

<?php

class StreamContextRouter
{
    public static function dispatch(resource $context, string $url): array
    {
        $options = stream_context_get_options($context);
        $http    = $options['http'] ?? [];
        $ssl     = $options['ssl']  ?? [];

        $method     = strtoupper($http['method']      ?? 'GET');
        $hasBody    = !empty($http['content']);
        $hasAuth    = str_contains($http['header'] ?? '', 'Authorization');
        $sslVerify  = $ssl['verify_peer'] ?? true;
        $timeout    = $http['timeout']    ?? 0;

        $strategy = match (true) {
            $method === 'POST' && $hasAuth => 'authenticated_post',
            $method === 'POST'             => 'anonymous_post',
            $hasAuth                       => 'authenticated_get',
            default                        => 'anonymous_get',
        };

        echo "=== コンテキストルーティング ===\n";
        echo "URL      : {$url}\n";
        echo "メソッド : {$method}\n";
        echo "認証     : " . ($hasAuth   ? 'あり' : 'なし') . "\n";
        echo "ボディ   : " . ($hasBody   ? 'あり' : 'なし') . "\n";
        echo "SSL検証  : " . ($sslVerify ? '有効' : '無効') . "\n";
        echo "タイムアウト: {$timeout}秒\n";
        echo "選択戦略 : {$strategy}\n\n";

        return [
            'strategy' => $strategy,
            'options'  => $options,
        ];
    }
}

// GET・認証なし
$ctxGet = stream_context_create([
    'http' => ['method' => 'GET', 'timeout' => 10],
]);
StreamContextRouter::dispatch($ctxGet, 'https://api.example.com/public');

// POST・認証あり
$ctxPost = stream_context_create([
    'http' => [
        'method'  => 'POST',
        'timeout' => 20,
        'content' => '{"key":"value"}',
        'header'  => "Authorization: Bearer token\r\nContent-Type: application/json",
    ],
]);
StreamContextRouter::dispatch($ctxPost, 'https://api.example.com/private');

関連関数との比較

関数用途
stream_context_get_options()コンテキストのオプションを取得
stream_context_get_params()コンテキストのパラメータ(通知コールバックなど)を取得
stream_context_set_option()既存コンテキストにオプションを追加・変更
stream_context_create()コンテキストリソースを新規作成
stream_context_get_default()デフォルトコンテキストを取得(引数付きで上書きも可)

まとめ

項目内容
関数名stream_context_get_options()
分類ストリームコンテキスト関数
PHP バージョンPHP 4.3.0以上
戻り値ラッパー名をキーとするネストした連想配列
主な用途コンテキスト設定の取得・デバッグ・検証・マージ

stream_context_get_options() はコンテキストの「中身を読み出す」ための窓口です。単なるデバッグ用途にとどまらず、バリデーション・差分比較・シリアライズ・セキュリティ監査など、コンテキストを扱うあらゆる場面で活用できます。stream_context_create()stream_context_get_default() とセットで覚えておくと、PHP のストリーム制御をより安全・柔軟に実装できるようになります。

タイトルとURLをコピーしました