[PHP]session_cache_limiter関数を完全解説!セッションのキャッシュリミッターを設定する方法

PHP

こんにちは!今回は、PHPの標準関数であるsession_cache_limiter()について詳しく解説していきます。セッションページのキャッシュ制御方法を設定できる、セキュリティとパフォーマンスに重要な関数です!

session_cache_limiter関数とは?

session_cache_limiter()関数は、現在のセッションで使用するキャッシュリミッターを取得または設定する関数です。

キャッシュリミッターは、ブラウザやプロキシサーバーに送信されるHTTPキャッシュ制御ヘッダーを決定します。セキュリティ、プライバシー、パフォーマンスのバランスを取るために重要な役割を果たします!

基本的な構文

session_cache_limiter(?string $value = null): string|false
  • $value: キャッシュリミッター名、省略時は現在の値を取得
  • 戻り値: 現在の設定値、失敗時はfalse

利用可能なリミッター

// nocache - キャッシュを完全に無効化(デフォルト)
session_cache_limiter('nocache');
// 送信されるヘッダー:
// Expires: Thu, 19 Nov 1981 08:52:00 GMT
// Cache-Control: no-store, no-cache, must-revalidate
// Pragma: no-cache

// private - プライベートキャッシュのみ許可
session_cache_limiter('private');
// 送信されるヘッダー:
// Expires: (現在時刻 + cache_expire)
// Cache-Control: private, max-age=...

// private_no_expire - privateと同じだがExpiresヘッダーなし
session_cache_limiter('private_no_expire');
// 送信されるヘッダー:
// Cache-Control: private, max-age=...

// public - 公開キャッシュを許可
session_cache_limiter('public');
// 送信されるヘッダー:
// Expires: (現在時刻 + cache_expire)
// Cache-Control: public, max-age=...

// '' (空文字列) - キャッシュヘッダーを送信しない
session_cache_limiter('');
// ヘッダーを送信しない(手動制御)

重要な注意点

// session_start()の前に呼び出す必要がある
session_cache_limiter('private');  // 正しい順序
session_start();

// session_start()の後では効果なし
session_start();
session_cache_limiter('private');  // 効果なし

// デフォルト値は'nocache'
echo session_cache_limiter();  // 'nocache'

// session_cache_expire()と組み合わせて使用
session_cache_expire(30);  // 30分
session_cache_limiter('private');
session_start();

基本的な使用例

現在の値を取得

// デフォルト値を確認
$limiter = session_cache_limiter();
echo "現在のキャッシュリミッター: {$limiter}\n";
// 出力: 現在のキャッシュリミッター: nocache

リミッターを設定

// privateに設定
$old_limiter = session_cache_limiter('private');
echo "以前の値: {$old_limiter}\n";
echo "新しい値: " . session_cache_limiter() . "\n";

session_start();

キャッシュを完全に無効化

// セキュアなページ用設定
session_cache_limiter('nocache');
session_cache_expire(0);
session_start();

// これにより、ページは決してキャッシュされない

公開コンテンツの設定

// 公開ページ用設定
session_cache_limiter('public');
session_cache_expire(1440);  // 24時間
session_start();

// プロキシやCDNでもキャッシュ可能

手動でヘッダー制御

// PHPの自動ヘッダーを無効化
session_cache_limiter('');
session_start();

// 手動でヘッダーを設定
header('Cache-Control: no-cache, must-revalidate');
header('Expires: 0');

実践的な使用例

例1: セキュリティレベル別キャッシュ管理

class SecurityBasedCacheManager {
    /**
     * セキュリティレベルに応じた設定
     */
    public static function configure($securityLevel) {
        switch ($securityLevel) {
            case 'maximum':
                // 最高セキュリティ - キャッシュ完全無効
                session_cache_limiter('nocache');
                session_cache_expire(0);
                return self::getSettings('Maximum Security');
                
            case 'high':
                // 高セキュリティ - プライベートキャッシュのみ、短時間
                session_cache_limiter('private_no_expire');
                session_cache_expire(15);
                return self::getSettings('High Security');
                
            case 'medium':
                // 中セキュリティ - プライベートキャッシュ、標準時間
                session_cache_limiter('private');
                session_cache_expire(30);
                return self::getSettings('Medium Security');
                
            case 'low':
                // 低セキュリティ - 公開キャッシュ可
                session_cache_limiter('public');
                session_cache_expire(180);
                return self::getSettings('Low Security');
                
            case 'custom':
                // カスタム - ヘッダーを手動制御
                session_cache_limiter('');
                session_cache_expire(0);
                return self::getSettings('Custom Control');
                
            default:
                // デフォルト - nocache
                session_cache_limiter('nocache');
                session_cache_expire(180);
                return self::getSettings('Default');
        }
    }
    
    /**
     * 現在の設定を取得
     */
    private static function getSettings($level) {
        return [
            'security_level' => $level,
            'cache_limiter' => session_cache_limiter(),
            'cache_expire' => session_cache_expire(),
            'headers_preview' => self::getHeadersPreview()
        ];
    }
    
    /**
     * 送信されるヘッダーのプレビュー
     */
    private static function getHeadersPreview() {
        $limiter = session_cache_limiter();
        $expire = session_cache_expire() * 60;  // 秒に変換
        
        $headers = [];
        
        switch ($limiter) {
            case 'nocache':
                $headers = [
                    'Expires' => 'Thu, 19 Nov 1981 08:52:00 GMT',
                    'Cache-Control' => 'no-store, no-cache, must-revalidate',
                    'Pragma' => 'no-cache'
                ];
                break;
                
            case 'private':
                $headers = [
                    'Expires' => gmdate('D, d M Y H:i:s', time() + $expire) . ' GMT',
                    'Cache-Control' => "private, max-age={$expire}"
                ];
                break;
                
            case 'private_no_expire':
                $headers = [
                    'Cache-Control' => "private, max-age={$expire}"
                ];
                break;
                
            case 'public':
                $headers = [
                    'Expires' => gmdate('D, d M Y H:i:s', time() + $expire) . ' GMT',
                    'Cache-Control' => "public, max-age={$expire}"
                ];
                break;
                
            case '':
                $headers = ['Note' => 'No automatic headers sent'];
                break;
        }
        
        return $headers;
    }
    
    /**
     * 推奨設定を取得
     */
    public static function getRecommendation($pageType) {
        $recommendations = [
            'login' => 'maximum',
            'admin' => 'maximum',
            'user_profile' => 'high',
            'dashboard' => 'medium',
            'blog' => 'low',
            'static_content' => 'low',
            'api' => 'custom'
        ];
        
        $level = $recommendations[$pageType] ?? 'medium';
        
        return [
            'page_type' => $pageType,
            'recommended_level' => $level,
            'reason' => self::getRecommendationReason($pageType, $level)
        ];
    }
    
    /**
     * 推奨理由を取得
     */
    private static function getRecommendationReason($pageType, $level) {
        $reasons = [
            'login' => '認証情報を含むため最高セキュリティが必要',
            'admin' => '管理画面のため最高セキュリティが必要',
            'user_profile' => '個人情報を含むため高セキュリティが必要',
            'dashboard' => 'ユーザー固有データのため中セキュリティが適切',
            'blog' => '公開コンテンツのため低セキュリティで十分',
            'static_content' => '静的コンテンツのためキャッシュ推奨',
            'api' => 'APIは手動でヘッダー制御が望ましい'
        ];
        
        return $reasons[$pageType] ?? 'ページタイプに応じた標準設定';
    }
}

// 使用例
echo "=== セキュリティレベル別設定 ===\n";

// 各セキュリティレベルをテスト
$levels = ['maximum', 'high', 'medium', 'low', 'custom'];

foreach ($levels as $level) {
    echo "\n{$level}:\n";
    $settings = SecurityBasedCacheManager::configure($level);
    echo "  レベル: {$settings['security_level']}\n";
    echo "  リミッター: {$settings['cache_limiter']}\n";
    echo "  有効期限: {$settings['cache_expire']}分\n";
    echo "  ヘッダー:\n";
    foreach ($settings['headers_preview'] as $name => $value) {
        echo "    {$name}: {$value}\n";
    }
}

// ページタイプ別の推奨設定
echo "\n=== ページタイプ別推奨設定 ===\n";
$pageTypes = ['login', 'admin', 'user_profile', 'blog', 'api'];

foreach ($pageTypes as $pageType) {
    $recommendation = SecurityBasedCacheManager::getRecommendation($pageType);
    echo "\n{$recommendation['page_type']}:\n";
    echo "  推奨レベル: {$recommendation['recommended_level']}\n";
    echo "  理由: {$recommendation['reason']}\n";
}

例2: ページタイプ別リミッター設定

class PageTypeConfigurator {
    private $configurations = [];
    
    /**
     * 設定を初期化
     */
    public function __construct() {
        $this->configurations = [
            'authentication' => [
                'limiter' => 'nocache',
                'expire' => 0,
                'description' => 'ログイン/認証ページ',
                'reason' => 'セキュリティのため絶対にキャッシュしない'
            ],
            'user_data' => [
                'limiter' => 'private_no_expire',
                'expire' => 30,
                'description' => 'ユーザーデータページ',
                'reason' => 'プライベートキャッシュのみ、短時間'
            ],
            'dashboard' => [
                'limiter' => 'private',
                'expire' => 60,
                'description' => 'ダッシュボード',
                'reason' => 'ユーザー固有だが更新頻度は低い'
            ],
            'public_content' => [
                'limiter' => 'public',
                'expire' => 1440,
                'description' => '公開コンテンツ',
                'reason' => 'CDNやプロキシでのキャッシュを許可'
            ],
            'static_page' => [
                'limiter' => 'public',
                'expire' => 10080,  // 7日
                'description' => '静的ページ',
                'reason' => 'ほとんど変更されないため長時間キャッシュ'
            ],
            'api_endpoint' => [
                'limiter' => '',
                'expire' => 0,
                'description' => 'APIエンドポイント',
                'reason' => 'カスタムヘッダーで制御'
            ]
        ];
    }
    
    /**
     * ページタイプに応じて設定
     */
    public function configureForPage($pageType) {
        if (!isset($this->configurations[$pageType])) {
            throw new Exception("Unknown page type: {$pageType}");
        }
        
        $config = $this->configurations[$pageType];
        
        session_cache_limiter($config['limiter']);
        session_cache_expire($config['expire']);
        
        return [
            'page_type' => $pageType,
            'description' => $config['description'],
            'reason' => $config['reason'],
            'limiter' => session_cache_limiter(),
            'expire' => session_cache_expire()
        ];
    }
    
    /**
     * すべての設定を一覧表示
     */
    public function listConfigurations() {
        $list = [];
        
        foreach ($this->configurations as $type => $config) {
            $list[] = [
                'type' => $type,
                'description' => $config['description'],
                'limiter' => $config['limiter'],
                'expire' => $config['expire'],
                'reason' => $config['reason']
            ];
        }
        
        return $list;
    }
    
    /**
     * URLパスからページタイプを判定
     */
    public function detectPageType($path) {
        $patterns = [
            '/^\/login/' => 'authentication',
            '/^\/register/' => 'authentication',
            '/^\/logout/' => 'authentication',
            '/^\/user\//' => 'user_data',
            '/^\/profile/' => 'user_data',
            '/^\/dashboard/' => 'dashboard',
            '/^\/admin/' => 'dashboard',
            '/^\/api\//' => 'api_endpoint',
            '/^\/blog\//' => 'public_content',
            '/^\/about/' => 'static_page',
            '/^\/contact/' => 'static_page'
        ];
        
        foreach ($patterns as $pattern => $type) {
            if (preg_match($pattern, $path)) {
                return $type;
            }
        }
        
        return 'public_content';  // デフォルト
    }
    
    /**
     * 自動設定(URLから判定)
     */
    public function autoConfigureFromUrl($url) {
        $parsedUrl = parse_url($url);
        $path = $parsedUrl['path'] ?? '/';
        
        $pageType = $this->detectPageType($path);
        return $this->configureForPage($pageType);
    }
}

// 使用例
echo "=== ページタイプ別設定 ===\n";

$configurator = new PageTypeConfigurator();

// すべての設定を表示
echo "利用可能な設定:\n";
foreach ($configurator->listConfigurations() as $config) {
    echo "\n{$config['type']}:\n";
    echo "  説明: {$config['description']}\n";
    echo "  リミッター: {$config['limiter']}\n";
    echo "  有効期限: {$config['expire']}分\n";
    echo "  理由: {$config['reason']}\n";
}

// URL から自動設定
echo "\n=== URLからの自動設定 ===\n";
$urls = [
    'https://example.com/login',
    'https://example.com/user/profile',
    'https://example.com/blog/article',
    'https://example.com/api/data'
];

foreach ($urls as $url) {
    $result = $configurator->autoConfigureFromUrl($url);
    echo "\n{$url}:\n";
    echo "  ページタイプ: {$result['page_type']}\n";
    echo "  リミッター: {$result['limiter']}\n";
    echo "  有効期限: {$result['expire']}分\n";
}

例3: 認証状態に応じた動的制御

class AuthenticationAwareCacheControl {
    /**
     * 認証状態に応じて設定
     */
    public function configureByAuthState($isAuthenticated, $userRole = 'guest') {
        if (!$isAuthenticated) {
            // 未認証 - 公開キャッシュ可
            session_cache_limiter('public');
            session_cache_expire(180);
            $state = 'unauthenticated';
            
        } else {
            // 認証済み - ロールに応じて設定
            switch ($userRole) {
                case 'admin':
                    // 管理者 - キャッシュなし
                    session_cache_limiter('nocache');
                    session_cache_expire(0);
                    $state = 'admin';
                    break;
                    
                case 'premium':
                    // プレミアムユーザー - 短時間プライベートキャッシュ
                    session_cache_limiter('private_no_expire');
                    session_cache_expire(15);
                    $state = 'premium_user';
                    break;
                    
                case 'user':
                default:
                    // 一般ユーザー - プライベートキャッシュ
                    session_cache_limiter('private');
                    session_cache_expire(30);
                    $state = 'regular_user';
            }
        }
        
        return [
            'state' => $state,
            'authenticated' => $isAuthenticated,
            'role' => $userRole,
            'limiter' => session_cache_limiter(),
            'expire' => session_cache_expire()
        ];
    }
    
    /**
     * セッションベースで設定
     */
    public function configureFromSession() {
        session_start();
        
        $isAuthenticated = $_SESSION['authenticated'] ?? false;
        $userRole = $_SESSION['role'] ?? 'guest';
        
        // セッションを閉じて再設定
        session_write_close();
        
        // 新しい設定で再開
        $config = $this->configureByAuthState($isAuthenticated, $userRole);
        session_start();
        
        return $config;
    }
    
    /**
     * 認証後の設定変更
     */
    public function onLoginSuccess($userRole) {
        // 現在のセッションを終了
        if (session_status() === PHP_SESSION_ACTIVE) {
            session_write_close();
        }
        
        // 新しい設定を適用
        $config = $this->configureByAuthState(true, $userRole);
        
        // セッションを再開
        session_start();
        $_SESSION['authenticated'] = true;
        $_SESSION['role'] = $userRole;
        
        return $config;
    }
    
    /**
     * ログアウト時の設定変更
     */
    public function onLogout() {
        if (session_status() === PHP_SESSION_ACTIVE) {
            session_write_close();
        }
        
        // 未認証設定に戻す
        $config = $this->configureByAuthState(false);
        
        session_start();
        $_SESSION = [];
        
        return $config;
    }
    
    /**
     * 権限昇格時の設定変更
     */
    public function onRoleChange($newRole) {
        session_start();
        
        $isAuthenticated = $_SESSION['authenticated'] ?? false;
        
        if (!$isAuthenticated) {
            return ['error' => 'Not authenticated'];
        }
        
        // セッションを閉じて再設定
        session_write_close();
        
        $config = $this->configureByAuthState(true, $newRole);
        
        session_start();
        $_SESSION['role'] = $newRole;
        
        return $config;
    }
}

// 使用例
echo "=== 認証状態に応じた制御 ===\n";

$cacheControl = new AuthenticationAwareCacheControl();

// 未認証状態
echo "未認証状態:\n";
$config = $cacheControl->configureByAuthState(false);
echo "  状態: {$config['state']}\n";
echo "  リミッター: {$config['limiter']}\n";
echo "  有効期限: {$config['expire']}分\n";

// 一般ユーザーとしてログイン
echo "\n一般ユーザーログイン:\n";
$config = $cacheControl->onLoginSuccess('user');
echo "  状態: {$config['state']}\n";
echo "  リミッター: {$config['limiter']}\n";
echo "  有効期限: {$config['expire']}分\n";

// 管理者に権限変更
echo "\n管理者に昇格:\n";
$config = $cacheControl->onRoleChange('admin');
echo "  状態: {$config['state']}\n";
echo "  リミッター: {$config['limiter']}\n";
echo "  有効期限: {$config['expire']}分\n";

// ログアウト
echo "\nログアウト:\n";
$config = $cacheControl->onLogout();
echo "  状態: {$config['state']}\n";
echo "  リミッター: {$config['limiter']}\n";
echo "  有効期限: {$config['expire']}分\n";

例4: APIレスポンスヘッダー管理

class ApiHeaderManager {
    /**
     * APIエンドポイント用のヘッダー設定
     */
    public function configureForApi($endpoint, $cacheStrategy = 'no-cache') {
        // PHPの自動ヘッダーを無効化
        session_cache_limiter('');
        session_start();
        
        // カスタムヘッダーを設定
        switch ($cacheStrategy) {
            case 'cacheable':
                $this->setCacheableHeaders($endpoint);
                break;
                
            case 'conditional':
                $this->setConditionalHeaders($endpoint);
                break;
                
            case 'no-cache':
            default:
                $this->setNoCacheHeaders();
        }
        
        return [
            'endpoint' => $endpoint,
            'strategy' => $cacheStrategy,
            'headers' => $this->getSetHeaders()
        ];
    }
    
    /**
     * キャッシュ可能なヘッダー
     */
    private function setCacheableHeaders($endpoint) {
        $maxAge = $this->getMaxAgeForEndpoint($endpoint);
        
        header("Cache-Control: public, max-age={$maxAge}");
        header("Expires: " . gmdate('D, d M Y H:i:s', time() + $maxAge) . ' GMT');
        header("ETag: " . md5($endpoint . time()));
    }
    
    /**
     * 条件付きキャッシュヘッダー
     */
    private function setConditionalHeaders($endpoint) {
        $etag = md5($endpoint . filemtime(__FILE__));
        $lastModified = gmdate('D, d M Y H:i:s', filemtime(__FILE__)) . ' GMT';
        
        header("Cache-Control: private, must-revalidate");
        header("ETag: \"{$etag}\"");
        header("Last-Modified: {$lastModified}");
        
        // If-None-Matchヘッダーをチェック
        if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && 
            trim($_SERVER['HTTP_IF_NONE_MATCH'], '"') === $etag) {
            header('HTTP/1.1 304 Not Modified');
            exit;
        }
    }
    
    /**
     * キャッシュなしヘッダー
     */
    private function setNoCacheHeaders() {
        header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
        header("Cache-Control: post-check=0, pre-check=0", false);
        header("Pragma: no-cache");
        header("Expires: 0");
    }
    
    /**
     * エンドポイントごとの最大キャッシュ時間
     */
    private function getMaxAgeForEndpoint($endpoint) {
        $maxAges = [
            '/api/static' => 86400,      // 24時間
            '/api/content' => 3600,      // 1時間
            '/api/data' => 300,          // 5分
            '/api/realtime' => 0         // キャッシュなし
        ];
        
        foreach ($maxAges as $pattern => $maxAge) {
            if (strpos($endpoint, $pattern) === 0) {
                return $maxAge;
            }
        }
        
        return 60;  // デフォルト: 1分
    }
    
    /**
     * 設定されたヘッダーを取得(デバッグ用)
     */
    private function getSetHeaders() {
        if (function_exists('headers_list')) {
            return headers_list();
        }
        return ['Note' => 'headers_list() not available'];
    }
    
    /**
     * CORS対応ヘッダーを追加
     */
    public function addCorsHeaders($allowedOrigins = ['*']) {
        if (in_array('*', $allowedOrigins)) {
            header("Access-Control-Allow-Origin: *");
        } else {
            $origin = $_SERVER['HTTP_ORIGIN'] ?? '';
            if (in_array($origin, $allowedOrigins)) {
                header("Access-Control-Allow-Origin: {$origin}");
            }
        }
        
        header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
        header("Access-Control-Allow-Headers: Content-Type, Authorization");
        header("Access-Control-Max-Age: 86400");
    }
    
    /**
     * レート制限ヘッダーを追加
     */
    public function addRateLimitHeaders($limit, $remaining, $reset) {
        header("X-RateLimit-Limit: {$limit}");
        header("X-RateLimit-Remaining: {$remaining}");
        header("X-RateLimit-Reset: {$reset}");
    }
}

// 使用例
echo "=== APIヘッダー管理 ===\n";

$apiManager = new ApiHeaderManager();

// 異なる戦略でAPIを設定
$strategies = ['cacheable', 'conditional', 'no-cache'];

foreach ($strategies as $strategy) {
    echo "\n{$strategy} 戦略:\n";
    $result = $apiManager->configureForApi('/api/data', $strategy);
    echo "  エンドポイント: {$result['endpoint']}\n";
    echo "  戦略: {$result['strategy']}\n";
    
    // セッションをリセット
    if (session_status() === PHP_SESSION_ACTIVE) {
        session_write_close();
    }
}

// CORS とレート制限を含む完全な設定
echo "\n=== 完全なAPI設定 ===\n";
session_cache_limiter('');
session_start();
$apiManager->setNoCacheHeaders();
$apiManager->addCorsHeaders(['https://example.com']);
$apiManager->addRateLimitHeaders(100, 95, time() + 3600);
echo "APIヘッダー設定完了\n";

例5: CDN連携システム

class CdnCacheIntegration {
    private $cdnEnabled;
    private $cdnProvider;
    
    /**
     * CDN連携を初期化
     */
    public function __construct($cdnEnabled = false, $cdnProvider = 'cloudflare') {
        $this->cdnEnabled = $cdnEnabled;
        $this->cdnProvider = $cdnProvider;
    }
    
    /**
     * CDN対応のキャッシュ設定
     */
    public function configureCdnCache($contentType, $ttl = 3600) {
        if ($this->cdnEnabled) {
            // CDN用の設定
            session_cache_limiter('public');
            session_cache_expire((int)($ttl / 60));  // 分に変換
            session_start();
            
            // CDN固有のヘッダーを追加
            $this->addCdnHeaders($contentType, $ttl);
            
        } else {
            // CDNなしの標準設定
            session_cache_limiter('private');
            session_cache_expire(30);
            session_start();
        }
        
        return [
            'cdn_enabled' => $this->cdnEnabled,
            'content_type' => $contentType,
            'ttl' => $ttl,
            'limiter' => session_cache_limiter(),
            'expire' => session_cache_expire()
        ];
    }
    
    /**
     * CDN固有のヘッダーを追加
     */
    private function addCdnHeaders($contentType, $ttl) {
        switch ($this->cdnProvider) {
            case 'cloudflare':
                // Cloudflare固有のヘッダー
                header("CF-Cache-Status: DYNAMIC");
                header("Cache-Control: public, max-age={$ttl}, s-maxage={$ttl}");
                break;
                
            case 'fastly':
                // Fastly固有のヘッダー
                header("Surrogate-Control: max-age={$ttl}");
                header("Cache-Control: public, max-age={$ttl}");
                break;
                
            case 'akamai':
                // Akamai固有のヘッダー
                header("Edge-Control: max-age={$ttl}");
                header("Cache-Control: public, max-age={$ttl}");
                break;
                
            default:
                // 一般的なCDNヘッダー
                header("Cache-Control: public, max-age={$ttl}");
        }
        
        // Vary ヘッダーを追加
        header("Vary: Accept-Encoding");
    }
    
    /**
     * キャッシュパージ用のヘッダー
     */
    public function setCachePurgeHeaders() {
        session_cache_limiter('');
        session_start();
        
        header("Cache-Control: no-cache, no-store, must-revalidate");
        header("Pragma: no-cache");
        header("Expires: 0");
        
        // CDN固有のパージヘッダー
        if ($this->cdnEnabled) {
            switch ($this->cdnProvider) {
                case 'cloudflare':
                    header("CF-Cache-Status: BYPASS");
                    break;
                    
                case 'fastly':
                    header("Fastly-Force-Shield: 1");
                    break;
            }
        }
        
        return ['purge_headers_set' => true];
    }
    
    /**
     * コンテンツタイプ別のTTL
     */
    public function getTtlForContentType($contentType) {
        $ttls = [
            'image' => 86400,       // 24時間
            'css' => 604800,        // 7日
            'js' => 604800,         // 7日
            'html' => 3600,         // 1時間
            'api' => 300,           // 5分
            'dynamic' => 60         // 1分
        ];
        
        return $ttls[$contentType] ?? 3600;
    }
    
    /**
     * 条件付きCDNキャッシュ
     */
    public function configureConditional($conditions) {
        if ($conditions['user_authenticated']) {
            // 認証ユーザー - プライベートキャッシュ
            session_cache_limiter('private');
            session_cache_expire(15);
            $cacheType = 'private';
            
        } elseif ($conditions['content_personalized']) {
            // パーソナライズコンテンツ - Varyヘッダーで制御
            session_cache_limiter('public');
            session_cache_expire(30);
            header("Vary: Cookie");
            $cacheType = 'personalized';
            
        } else {
            // 公開コンテンツ - CDNキャッシュ
            $ttl = $this->getTtlForContentType($conditions['content_type']);
            $this->configureCdnCache($conditions['content_type'], $ttl);
            $cacheType = 'public_cdn';
        }
        
        return [
            'cache_type' => $cacheType,
            'conditions' => $conditions
        ];
    }
}

// 使用例
echo "=== CDN連携システム ===\n";

// CDN有効
$cdn = new CdnCacheIntegration(true, 'cloudflare');

echo "CDN有効時の設定:\n";
$contentTypes = ['image', 'css', 'html', 'api'];

foreach ($contentTypes as $type) {
    $ttl = $cdn->getTtlForContentType($type);
    $config = $cdn->configureCdnCache($type, $ttl);
    echo "\n{$type}:\n";
    echo "  TTL: {$config['ttl']}秒\n";
    echo "  リミッター: {$config['limiter']}\n";
    
    session_write_close();
}

// 条件付きキャッシュ
echo "\n=== 条件付きキャッシュ ===\n";

$conditions = [
    ['user_authenticated' => false, 'content_personalized' => false, 'content_type' => 'html'],
    ['user_authenticated' => true, 'content_personalized' => false, 'content_type' => 'html'],
    ['user_authenticated' => false, 'content_personalized' => true, 'content_type' => 'html']
];

foreach ($conditions as $condition) {
    $result = $cdn->configureConditional($condition);
    echo "\nキャッシュタイプ: {$result['cache_type']}\n";
    echo "  認証: " . ($condition['user_authenticated'] ? 'Yes' : 'No') . "\n";
    echo "  パーソナライズ: " . ($condition['content_personalized'] ? 'Yes' : 'No') . "\n";
    
    session_write_close();
}

例6: キャッシュ戦略マネージャー

class CacheStrategyManager {
    private $strategies = [];
    private $currentStrategy;
    
    /**
     * キャッシュ戦略を初期化
     */
    public function __construct() {
        $this->strategies = [
            'aggressive' => [
                'limiter' => 'public',
                'expire' => 10080,  // 7日
                'description' => '積極的キャッシュ - 静的コンテンツ向け',
                'use_cases' => ['画像', 'CSS', 'JS', '変更頻度が低いページ']
            ],
            'moderate' => [
                'limiter' => 'public',
                'expire' => 1440,  // 24時間
                'description' => '中程度キャッシュ - 一般コンテンツ向け',
                'use_cases' => ['ブログ記事', 'ニュース', '商品ページ']
            ],
            'conservative' => [
                'limiter' => 'private',
                'expire' => 60,  // 1時間
                'description' => '控えめキャッシュ - ユーザー固有コンテンツ向け',
                'use_cases' => ['ダッシュボード', 'マイページ']
            ],
            'minimal' => [
                'limiter' => 'private_no_expire',
                'expire' => 15,  // 15分
                'description' => '最小キャッシュ - 頻繁に更新されるコンテンツ向け',
                'use_cases' => ['検索結果', 'フィード']
            ],
            'none' => [
                'limiter' => 'nocache',
                'expire' => 0,
                'description' => 'キャッシュなし - セキュアページ向け',
                'use_cases' => ['ログイン', '支払い', '個人情報']
            ]
        ];
    }
    
    /**
     * 戦略を適用
     */
    public function applyStrategy($strategyName) {
        if (!isset($this->strategies[$strategyName])) {
            throw new Exception("Unknown strategy: {$strategyName}");
        }
        
        $strategy = $this->strategies[$strategyName];
        
        session_cache_limiter($strategy['limiter']);
        session_cache_expire($strategy['expire']);
        
        $this->currentStrategy = $strategyName;
        
        return [
            'strategy' => $strategyName,
            'description' => $strategy['description'],
            'limiter' => session_cache_limiter(),
            'expire' => session_cache_expire(),
            'use_cases' => $strategy['use_cases']
        ];
    }
    
    /**
     * コンテンツに基づいて戦略を選択
     */
    public function selectStrategy($contentMetadata) {
        $score = 0;
        
        // 更新頻度スコア
        if ($contentMetadata['update_frequency'] === 'never') {
            $score += 4;
        } elseif ($contentMetadata['update_frequency'] === 'rarely') {
            $score += 3;
        } elseif ($contentMetadata['update_frequency'] === 'sometimes') {
            $score += 2;
        } elseif ($contentMetadata['update_frequency'] === 'often') {
            $score += 1;
        } else {
            $score += 0;
        }
        
        // パーソナライゼーションスコア
        if (!$contentMetadata['personalized']) {
            $score += 2;
        }
        
        // セキュリティスコア
        if ($contentMetadata['sensitive']) {
            return $this->applyStrategy('none');
        }
        
        // スコアに基づいて戦略を選択
        if ($score >= 5) {
            return $this->applyStrategy('aggressive');
        } elseif ($score >= 4) {
            return $this->applyStrategy('moderate');
        } elseif ($score >= 2) {
            return $this->applyStrategy('conservative');
        } else {
            return $this->applyStrategy('minimal');
        }
    }
    
    /**
     * 戦略一覧を取得
     */
    public function listStrategies() {
        $list = [];
        
        foreach ($this->strategies as $name => $strategy) {
            $list[] = [
                'name' => $name,
                'description' => $strategy['description'],
                'limiter' => $strategy['limiter'],
                'expire' => $strategy['expire'],
                'use_cases' => $strategy['use_cases']
            ];
        }
        
        return $list;
    }
    
    /**
     * 戦略の比較
     */
    public function compareStrategies($strategy1, $strategy2) {
        if (!isset($this->strategies[$strategy1]) || !isset($this->strategies[$strategy2])) {
            throw new Exception("One or both strategies not found");
        }
        
        return [
            $strategy1 => $this->strategies[$strategy1],
            $strategy2 => $this->strategies[$strategy2],
            'recommendation' => $this->getComparisonRecommendation($strategy1, $strategy2)
        ];
    }
    
    /**
     * 比較に基づく推奨
     */
    private function getComparisonRecommendation($strategy1, $strategy2) {
        $expire1 = $this->strategies[$strategy1]['expire'];
        $expire2 = $this->strategies[$strategy2]['expire'];
        
        if ($expire1 > $expire2) {
            return "{$strategy1}の方がキャッシュ時間が長く、パフォーマンスが向上しますが、コンテンツの鮮度は低下します";
        } else {
            return "{$strategy2}の方がキャッシュ時間が長く、パフォーマンスが向上しますが、コンテンツの鮮度は低下します";
        }
    }
}

// 使用例
echo "=== キャッシュ戦略マネージャー ===\n";

$manager = new CacheStrategyManager();

// すべての戦略を表示
echo "利用可能な戦略:\n";
foreach ($manager->listStrategies() as $strategy) {
    echo "\n{$strategy['name']}:\n";
    echo "  説明: {$strategy['description']}\n";
    echo "  リミッター: {$strategy['limiter']}\n";
    echo "  有効期限: {$strategy['expire']}分\n";
    echo "  ユースケース: " . implode(', ', $strategy['use_cases']) . "\n";
}

// コンテンツメタデータに基づいて自動選択
echo "\n=== 自動戦略選択 ===\n";

$contentTypes = [
    [
        'name' => 'ブログ記事',
        'update_frequency' => 'rarely',
        'personalized' => false,
        'sensitive' => false
    ],
    [
        'name' => 'ユーザーダッシュボード',
        'update_frequency' => 'often',
        'personalized' => true,
        'sensitive' => false
    ],
    [
        'name' => 'ログインページ',
        'update_frequency' => 'sometimes',
        'personalized' => false,
        'sensitive' => true
    ]
];

foreach ($contentTypes as $content) {
    $result = $manager->selectStrategy($content);
    echo "\n{$content['name']}:\n";
    echo "  選択された戦略: {$result['strategy']}\n";
    echo "  説明: {$result['description']}\n";
    echo "  有効期限: {$result['expire']}分\n";
    
    session_write_close();
}

HTTPヘッダーの詳細

// 各リミッターが送信するヘッダーの詳細

// nocache
session_cache_limiter('nocache');
session_start();
// Expires: Thu, 19 Nov 1981 08:52:00 GMT
// Cache-Control: no-store, no-cache, must-revalidate
// Pragma: no-cache

// private
session_cache_limiter('private');
session_cache_expire(30);  // 30分
session_start();
// Expires: (現在時刻 + 30分)
// Cache-Control: private, max-age=1800

// private_no_expire
session_cache_limiter('private_no_expire');
session_cache_expire(30);
session_start();
// Cache-Control: private, max-age=1800
// (Expiresヘッダーなし)

// public
session_cache_limiter('public');
session_cache_expire(60);
session_start();
// Expires: (現在時刻 + 60分)
// Cache-Control: public, max-age=3600

// '' (空文字列)
session_cache_limiter('');
session_start();
// キャッシュ関連のヘッダーを送信しない

まとめ

session_cache_limiter()関数の特徴をまとめると:

できること:

  • セッションページのキャッシュリミッター設定
  • HTTPキャッシュヘッダーの制御
  • ブラウザ・プロキシのキャッシュ動作制御

利用可能なリミッター:

  • nocache: キャッシュ完全無効(デフォルト)
  • private: プライベートキャッシュのみ
  • private_no_expire: privateだがExpiresなし
  • public: 公開キャッシュ許可
  • '': 自動ヘッダー無効(手動制御)

推奨される使用場面:

  • 認証ページ(nocache)
  • ユーザーデータ(private)
  • 公開コンテンツ(public)
  • APIエンドポイント(”で手動制御)
  • CDN連携(public)

重要な注意点:

  • session_start()の前に呼び出す
  • session_cache_expire()と組み合わせて使用
  • セキュリティとパフォーマンスのトレードオフ
  • HTTPヘッダーに直接影響

セキュリティ考慮:

// 機密情報を含むページ
session_cache_limiter('nocache');
session_cache_expire(0);

// ユーザー固有データ
session_cache_limiter('private');
session_cache_expire(30);

// 公開データ(CDN可)
session_cache_limiter('public');
session_cache_expire(1440);

ベストプラクティス:

// 1. ページタイプに応じた設定
if ($pageType === 'login') {
    session_cache_limiter('nocache');
} elseif ($pageType === 'public') {
    session_cache_limiter('public');
} else {
    session_cache_limiter('private');
}

// 2. session_start()の前に設定
session_cache_limiter('private');
session_cache_expire(30);
session_start();

// 3. APIでは手動制御
session_cache_limiter('');
session_start();
header('Cache-Control: no-cache');

関連関数:

  • session_cache_expire(): キャッシュ有効期限設定
  • session_start(): セッション開始
  • header(): HTTPヘッダー送信
  • headers_sent(): ヘッダー送信済みか確認

session_cache_limiter()は、セッションページのキャッシュ動作を細かく制御できる重要な関数です。適切に設定することで、セキュリティを保ちながらパフォーマンスを最適化できます!

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