[PHP]stream_context_set_default完全解説|デフォルトストリームコンテキストの設定・グローバル通信制御を実践サンプルで理解する

PHP

stream_context_set_defaultとは?

stream_context_set_default() は、PHPが内部で保持しているデフォルトストリームコンテキストを新しいオプションで設定(上書き)する関数です。

file_get_contents()fopen() などのストリーム関数は、コンテキストを明示的に渡さない場合にデフォルトコンテキストを暗黙的に使用します。stream_context_set_default() でこのデフォルトを設定しておくことで、スクリプト全体のすべてのストリーム関数に共通設定を一括適用できます。

PHP 5.3.0 で追加された関数です。「設定専用」の明確な意図を持ち、引数は必須です。


基本構文

stream_context_set_default(array $options): resource
引数説明
$optionsarrayデフォルトコンテキストに適用するオプションの連想配列(必須)
戻り値resource設定後のデフォルトストリームコンテキストリソース

stream_context_get_default() との使い分け

関数引数主な目的
stream_context_set_default($options)必須設定専用。意図が明確
stream_context_get_default($options)省略可取得が主目的。引数ありで上書きも可

機能的には重複しますが、「設定したい」なら set_default()、「取得したい(ついでに設定も)」なら get_default() と使い分けると、コードの読みやすさが向上します。


基本的な使い方

<?php
// デフォルトコンテキストを設定
stream_context_set_default([
    'http' => [
        'timeout'    => 10,
        'user_agent' => 'MyApp/1.0',
    ],
]);

// コンテキストを明示しなくても上記の設定が適用される
$html = file_get_contents('https://www.php.net/');
echo strlen($html) . " バイト取得\n";

// 設定内容を確認
$ctx  = stream_context_get_default();
$opts = stream_context_get_options($ctx);
echo "timeout: "    . $opts['http']['timeout']    . "\n"; // 10
echo "user_agent: " . $opts['http']['user_agent'] . "\n"; // MyApp/1.0

実践クラスサンプル

サンプル1:アプリケーション設定クラスでデフォルトコンテキストを初期化する

起動時に一度だけ呼び出すブートストラップクラスです。

<?php

class AppStreamBootstrap
{
    private static bool $initialized = false;

    public static function boot(string $appName, string $version, string $env = 'production'): void
    {
        if (self::$initialized) {
            return;
        }

        $isProduction = $env === 'production';

        stream_context_set_default([
            'http' => [
                'user_agent'      => "{$appName}/{$version}",
                'timeout'         => $isProduction ? 10 : 30,
                'follow_location' => 1,
                'max_redirects'   => 5,
                'ignore_errors'   => true,
            ],
            'ssl' => [
                'verify_peer'       => $isProduction,
                'verify_peer_name'  => $isProduction,
                'allow_self_signed' => !$isProduction,
            ],
        ]);

        self::$initialized = true;

        $env_label = $isProduction ? '本番' : '開発';
        echo "[$env_label] デフォルトコンテキストを初期化しました\n";
    }

    public static function isInitialized(): bool
    {
        return self::$initialized;
    }
}

// index.php やサービスプロバイダなど起動時に1度だけ呼ぶ
AppStreamBootstrap::boot(appName: 'ShopApp', version: '3.1', env: 'production');

// 以降すべてのストリーム関数に設定が自動適用される
$data = file_get_contents('https://jsonplaceholder.typicode.com/todos/1');
echo json_decode($data, true)['title'] . "\n";

サンプル2:環境設定ファイルからデフォルトコンテキストを構築するクラス

.env や設定配列をもとに動的にコンテキストを組み立てます。

<?php

class StreamContextConfigLoader
{
    private array $config;

    public function __construct(array $config)
    {
        $this->config = $config;
    }

    public function apply(): resource
    {
        $options = [];

        // httpラッパーの構築
        $http = $this->config['http'] ?? [];
        if (!empty($http)) {
            $httpOptions = array_filter([
                'timeout'         => $http['timeout']          ?? 15,
                'user_agent'      => $http['user_agent']        ?? 'PHP/Stream',
                'follow_location' => (int)($http['follow_location'] ?? true),
                'max_redirects'   => $http['max_redirects']     ?? 5,
                'ignore_errors'   => $http['ignore_errors']     ?? true,
                'proxy'           => $http['proxy']             ?? null,
            ], fn($v) => $v !== null);

            $options['http'] = $httpOptions;
        }

        // sslラッパーの構築
        $ssl = $this->config['ssl'] ?? [];
        if (!empty($ssl)) {
            $options['ssl'] = array_filter([
                'verify_peer'       => $ssl['verify_peer']       ?? true,
                'verify_peer_name'  => $ssl['verify_peer_name']  ?? true,
                'allow_self_signed' => $ssl['allow_self_signed'] ?? false,
                'cafile'            => $ssl['cafile']            ?? null,
            ], fn($v) => $v !== null);
        }

        return stream_context_set_default($options);
    }
}

// 使用例:設定配列から組み立て(.envや設定ファイルから読み込んだ値を想定)
$config = [
    'http' => [
        'timeout'    => 20,
        'user_agent' => 'ConfigLoader/1.0',
    ],
    'ssl' => [
        'verify_peer' => true,
    ],
];

$loader = new StreamContextConfigLoader($config);
$ctx    = $loader->apply();

$opts = stream_context_get_options($ctx);
echo "適用後 timeout: "    . $opts['http']['timeout']    . "\n";
echo "適用後 user_agent: " . $opts['http']['user_agent'] . "\n";

サンプル3:デフォルトコンテキストをリセット・スナップショット管理するクラス

設定変更前の状態を保存し、任意のタイミングで復元します。

<?php

class StreamContextSnapshot
{
    /** @var array[] */
    private array $stack = [];

    /**
     * 現在のデフォルト設定をスタックに保存してから新しい設定を適用
     */
    public function push(array $options): void
    {
        $current       = stream_context_get_default();
        $this->stack[] = stream_context_get_options($current);
        stream_context_set_default($options);
    }

    /**
     * 直前のスナップショットに戻す
     */
    public function pop(): bool
    {
        if (empty($this->stack)) {
            return false;
        }

        $previous = array_pop($this->stack);
        stream_context_set_default($previous ?: ['http' => []]);
        return true;
    }

    /**
     * すべてのスナップショットをクリアして空の状態に戻す
     */
    public function reset(): void
    {
        $this->stack = [];
        stream_context_set_default(['http' => []]);
    }

    public function depth(): int
    {
        return count($this->stack);
    }
}

// 使用例
$snapshot = new StreamContextSnapshot();

stream_context_set_default(['http' => ['timeout' => 10, 'user_agent' => 'Base/1.0']]);
echo "初期: " . stream_context_get_options(stream_context_get_default())['http']['user_agent'] . "\n";

// 設定①を積む
$snapshot->push(['http' => ['timeout' => 30, 'user_agent' => 'Layer1/1.0']]);
echo "push後: " . stream_context_get_options(stream_context_get_default())['http']['user_agent'] . "\n";

// 設定②をさらに積む
$snapshot->push(['http' => ['timeout' => 60, 'user_agent' => 'Layer2/1.0']]);
echo "push後: " . stream_context_get_options(stream_context_get_default())['http']['user_agent'] . "\n";

echo "スタック深さ: " . $snapshot->depth() . "\n";

// 1つ戻す
$snapshot->pop();
echo "pop後: " . stream_context_get_options(stream_context_get_default())['http']['user_agent'] . "\n";

// さらに1つ戻す
$snapshot->pop();
echo "pop後: " . stream_context_get_options(stream_context_get_default())['http']['user_agent'] . "\n";

サンプル4:プロキシ設定をデフォルトコンテキストへ適用するクラス

社内ネットワークやCI環境でプロキシが必要なケースに対応します。

<?php

class ProxyContextConfigurator
{
    private string  $proxyUrl;
    private ?string $noProxyPattern;

    public function __construct(string $proxyUrl, ?string $noProxyPattern = null)
    {
        $this->proxyUrl       = $proxyUrl;
        $this->noProxyPattern = $noProxyPattern;
    }

    public function enable(): void
    {
        $ctx     = stream_context_get_default();
        $current = stream_context_get_options($ctx)['http'] ?? [];

        $current['proxy']            = $this->proxyUrl;
        $current['request_fulluri']  = true;  // プロキシ経由ではフルURIが必要

        stream_context_set_default(['http' => $current]);

        echo "プロキシを設定しました: {$this->proxyUrl}\n";
    }

    public function disable(): void
    {
        $ctx     = stream_context_get_default();
        $current = stream_context_get_options($ctx)['http'] ?? [];

        unset($current['proxy'], $current['request_fulluri']);
        stream_context_set_default(['http' => $current]);

        echo "プロキシ設定を解除しました\n";
    }

    public function shouldBypass(string $url): bool
    {
        if ($this->noProxyPattern === null) {
            return false;
        }
        $host = parse_url($url, PHP_URL_HOST) ?? '';
        return fnmatch($this->noProxyPattern, $host);
    }
}

// 使用例
$proxy = new ProxyContextConfigurator(
    proxyUrl:       'tcp://proxy.example.com:8080',
    noProxyPattern: '*.internal.example.com'
);

$proxy->enable();

// プロキシ不要なURLかチェック
$urls = [
    'https://api.external.com/data',
    'https://service.internal.example.com/health',
];

foreach ($urls as $url) {
    $bypass = $proxy->shouldBypass($url);
    echo $url . ' → ' . ($bypass ? 'プロキシをバイパス' : 'プロキシ経由') . "\n";
}

$proxy->disable();

サンプル5:認証トークンをデフォルトコンテキストに付与・ローテーションするクラス

APIトークンの有効期限切れに備え、自動的にヘッダーを更新します。

<?php

class DefaultContextTokenManager
{
    private string $currentToken;
    private int    $expiresAt;

    public function __construct(string $initialToken, int $ttlSeconds = 3600)
    {
        $this->currentToken = $initialToken;
        $this->expiresAt    = time() + $ttlSeconds;
        $this->applyToken();
    }

    private function applyToken(): void
    {
        $ctx     = stream_context_get_default();
        $current = stream_context_get_options($ctx)['http'] ?? [];

        // 既存ヘッダーからAuthorizationだけ除去してから付け直す
        $lines = explode("\r\n", trim($current['header'] ?? ''));
        $lines = array_filter($lines, fn($l) => !str_starts_with($l, 'Authorization:'));
        $lines[] = "Authorization: Bearer {$this->currentToken}";

        $current['header'] = implode("\r\n", array_filter($lines)) . "\r\n";

        stream_context_set_default(['http' => $current]);
    }

    public function rotate(string $newToken, int $ttlSeconds = 3600): void
    {
        $this->currentToken = $newToken;
        $this->expiresAt    = time() + $ttlSeconds;
        $this->applyToken();
        echo "トークンをローテーションしました(有効期限: " . date('H:i:s', $this->expiresAt) . ")\n";
    }

    public function isExpired(): bool
    {
        return time() >= $this->expiresAt;
    }

    public function ensureValid(callable $tokenRefresher): void
    {
        if ($this->isExpired()) {
            $newToken = $tokenRefresher();
            $this->rotate($newToken);
        }
    }
}

// 使用例
$manager = new DefaultContextTokenManager(initialToken: 'initial-jwt-token', ttlSeconds: 1800);

// トークンが有効か確認してから通信
$manager->ensureValid(fn() => 'refreshed-jwt-token-' . time());

$ctx  = stream_context_get_default();
$opts = stream_context_get_options($ctx);
echo "現在のヘッダー:\n" . ($opts['http']['header'] ?? '(なし)');

サンプル6:テスト用スタブコンテキストをデフォルトに差し込むクラス

PHPUnitなどのテストでHTTP通信を差し替えるモック的な使い方です。

<?php

class StreamContextTestStub
{
    private static ?array $backup = null;

    /**
     * テスト用のデフォルト設定に差し替える
     */
    public static function install(array $stubOptions): void
    {
        $ctx           = stream_context_get_default();
        self::$backup  = stream_context_get_options($ctx);
        stream_context_set_default($stubOptions);
        echo "[TEST] スタブコンテキストをインストールしました\n";
    }

    /**
     * 元の設定に戻す
     */
    public static function uninstall(): void
    {
        if (self::$backup === null) {
            return;
        }
        stream_context_set_default(self::$backup);
        self::$backup = null;
        echo "[TEST] スタブコンテキストをアンインストールしました\n";
    }

    /**
     * setUp/tearDown をまとめて実行するヘルパー
     */
    public static function withStub(array $options, callable $test): void
    {
        self::install($options);
        try {
            $test();
        } finally {
            self::uninstall();
        }
    }
}

// 使用例(PHPUnitのテストメソッド相当)
StreamContextTestStub::withStub(
    options: [
        'http' => [
            'timeout'       => 1,
            'user_agent'    => 'TestRunner/1.0',
            'ignore_errors' => true,
        ],
        'ssl' => [
            'verify_peer' => false,
        ],
    ],
    test: function () {
        $ctx  = stream_context_get_default();
        $opts = stream_context_get_options($ctx);

        assert($opts['http']['timeout']    === 1,             'timeout が1であること');
        assert($opts['http']['user_agent'] === 'TestRunner/1.0', 'user_agent が正しいこと');
        assert($opts['ssl']['verify_peer'] === false,         'verify_peer が false であること');

        echo "[TEST] すべてのアサーションが通過しました\n";
    }
);

サンプル7:デフォルトコンテキストへのタイムアウト・リトライ設定を管理するクラス

ネットワーク品質に合わせてタイムアウトを動的に調整します。

<?php

class AdaptiveTimeoutConfigurator
{
    private int   $baseTimeout;
    private float $multiplier;
    private int   $attempt = 0;

    public function __construct(int $baseTimeout = 10, float $multiplier = 1.5)
    {
        $this->baseTimeout = $baseTimeout;
        $this->multiplier  = $multiplier;
    }

    public function applyForAttempt(int $attempt): int
    {
        $this->attempt = $attempt;
        $timeout       = (int)round($this->baseTimeout * ($this->multiplier ** $attempt));

        $ctx     = stream_context_get_default();
        $current = stream_context_get_options($ctx)['http'] ?? [];
        $current['timeout'] = $timeout;

        stream_context_set_default(['http' => $current]);
        echo "試行 {$attempt}: タイムアウトを {$timeout} 秒に設定\n";

        return $timeout;
    }

    public function fetch(string $url, int $maxAttempts = 3): string|false
    {
        for ($i = 0; $i < $maxAttempts; $i++) {
            $this->applyForAttempt($i);

            $result = @file_get_contents($url);
            if ($result !== false) {
                echo "試行 {$i} で取得成功\n";
                return $result;
            }

            echo "試行 {$i} 失敗。リトライします…\n";
        }

        return false;
    }
}

// 使用例
stream_context_set_default(['http' => ['user_agent' => 'AdaptiveClient/1.0']]);

$configurator = new AdaptiveTimeoutConfigurator(baseTimeout: 5, multiplier: 2.0);

// タイムアウトの変化を確認
$configurator->applyForAttempt(0); // 5秒
$configurator->applyForAttempt(1); // 10秒
$configurator->applyForAttempt(2); // 20秒

// 実際のリトライ付きフェッチ
// $body = $configurator->fetch('https://api.example.com/slow-endpoint');

関連関数との比較

関数用途
stream_context_set_default()デフォルトコンテキストを設定(引数必須)
stream_context_get_default()デフォルトコンテキストを取得(引数付きで設定も可)
stream_context_create()新規コンテキストリソースを作成
stream_context_get_options()コンテキストのオプションを取得
stream_context_set_option()既存コンテキストにオプションを追加・変更

注意点

  • stream_context_set_default()スクリプト全体に影響します。フレームワークやライブラリが内部でストリーム関数を使っている場合、意図しない影響を与える可能性があります。
  • オプションはマージではなく上書きされます。既存設定を保持したまま一部だけ変更する場合は、先に stream_context_get_options() で現在値を取得してからマージしてください(サンプル4・5参照)。
  • verify_peer: false はローカル開発環境専用です。本番環境では必ず true に設定してください。

まとめ

項目内容
関数名stream_context_set_default()
分類ストリームコンテキスト関数
PHP バージョンPHP 5.3.0以上
戻り値設定後のデフォルトストリームコンテキストリソース
主な用途スクリプト全体のストリーム通信設定を一括管理

stream_context_set_default() を使うと、アプリ起動時に一度だけ設定を適用するだけで、以降のすべてのストリーム関数呼び出しにその設定が自動的に反映されます。タイムアウト・User-Agent・SSL設定・プロキシ・認証ヘッダーなどをスクリプト全体で統一管理したい場面で非常に有効な関数です。stream_context_get_default()stream_context_get_options() と組み合わせることで、設定の保存・復元・差し替えも柔軟に実現できます。

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