こんにちは!今回は、PHPの標準関数であるsession_get_cookie_params()について詳しく解説していきます。セッションクッキーの設定を取得できる、セキュリティ確認とデバッグに重要な関数です!
session_get_cookie_params関数とは?
session_get_cookie_params()関数は、現在のセッションクッキーパラメータを取得する関数です。
セッションIDを保存するクッキーの有効期限、パス、ドメイン、セキュア設定、HttpOnly設定などを確認できます。セキュリティ監査や設定の検証に使用されます!
基本的な構文
session_get_cookie_params(): array
- 引数: なし
- 戻り値: クッキーパラメータを含む配列
返される配列の構造
// 返される配列の内容(PHP 7.3.0以降)
$params = session_get_cookie_params();
// 配列の構造
[
'lifetime' => int, // クッキーの有効期限(秒)、0=ブラウザ終了まで
'path' => string, // クッキーが有効なパス
'domain' => string, // クッキーが有効なドメイン
'secure' => bool, // HTTPS接続でのみ送信(true/false)
'httponly' => bool, // JavaScriptからアクセス不可(true/false)
'samesite' => string // SameSite属性('Lax', 'Strict', 'None', '')PHP 7.3.0以降
]
// 各パラメータの詳細
echo "Lifetime: {$params['lifetime']}秒\n";
echo "Path: {$params['path']}\n";
echo "Domain: {$params['domain']}\n";
echo "Secure: " . ($params['secure'] ? 'Yes' : 'No') . "\n";
echo "HttpOnly: " . ($params['httponly'] ? 'Yes' : 'No') . "\n";
echo "SameSite: {$params['samesite']}\n"; // PHP 7.3.0以降
重要な注意点
// PHP 7.3.0未満ではsameSiteキーは含まれない
if (PHP_VERSION_ID >= 70300) {
$params = session_get_cookie_params();
echo $params['samesite']; // OK
} else {
$params = session_get_cookie_params();
// sameSiteキーは存在しない
}
// session_start()の前後どちらでも使用可能
$params1 = session_get_cookie_params(); // session_start()前
session_start();
$params2 = session_get_cookie_params(); // session_start()後
// 両方とも同じ値
// 設定を確認するだけ(変更はしない)
$params = session_get_cookie_params();
// パラメータを変更したい場合はsession_set_cookie_params()を使用
// デフォルト値
// lifetime: 0(ブラウザ終了まで)
// path: '/'
// domain: ''(現在のホスト)
// secure: false
// httponly: false
// samesite: ''(PHP 7.3.0以降)
session_set_cookie_params()との関係
// 設定を変更
session_set_cookie_params([
'lifetime' => 3600,
'path' => '/app',
'domain' => 'example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]);
// 変更された設定を確認
$params = session_get_cookie_params();
echo "Lifetime: {$params['lifetime']}\n"; // 3600
echo "Path: {$params['path']}\n"; // /app
echo "Domain: {$params['domain']}\n"; // example.com
echo "Secure: {$params['secure']}\n"; // 1 (true)
echo "HttpOnly: {$params['httponly']}\n"; // 1 (true)
echo "SameSite: {$params['samesite']}\n"; // Strict
基本的な使用例
デフォルトパラメータの確認
// デフォルト設定を確認
$params = session_get_cookie_params();
echo "=== セッションクッキーパラメータ ===\n";
echo "Lifetime: {$params['lifetime']}秒\n";
echo "Path: {$params['path']}\n";
echo "Domain: {$params['domain']}\n";
echo "Secure: " . ($params['secure'] ? 'Yes' : 'No') . "\n";
echo "HttpOnly: " . ($params['httponly'] ? 'Yes' : 'No') . "\n";
if (isset($params['samesite'])) {
echo "SameSite: {$params['samesite']}\n";
}
パラメータの詳細表示
$params = session_get_cookie_params();
echo "=== 詳細情報 ===\n";
// Lifetime
if ($params['lifetime'] === 0) {
echo "有効期限: ブラウザ終了まで\n";
} else {
echo "有効期限: {$params['lifetime']}秒 (" .
round($params['lifetime'] / 3600, 2) . "時間)\n";
}
// Path
echo "有効パス: {$params['path']}\n";
echo " → このパス以下のページでクッキーが送信されます\n";
// Domain
if (empty($params['domain'])) {
echo "有効ドメイン: 現在のホストのみ\n";
} else {
echo "有効ドメイン: {$params['domain']}\n";
echo " → サブドメインを含む場合があります\n";
}
// Secure
if ($params['secure']) {
echo "セキュア: HTTPS接続でのみ送信\n";
} else {
echo "セキュア: HTTPでも送信(非推奨)\n";
}
// HttpOnly
if ($params['httponly']) {
echo "HttpOnly: JavaScriptからアクセス不可(推奨)\n";
} else {
echo "HttpOnly: JavaScriptからアクセス可能(XSSリスク)\n";
}
// SameSite
if (isset($params['samesite'])) {
switch ($params['samesite']) {
case 'Strict':
echo "SameSite: Strict(最も厳格、CSRF完全防止)\n";
break;
case 'Lax':
echo "SameSite: Lax(バランス型、推奨)\n";
break;
case 'None':
echo "SameSite: None(制限なし、Secure必須)\n";
break;
default:
echo "SameSite: 未設定\n";
}
}
設定前後の比較
// 変更前
echo "=== 変更前 ===\n";
$before = session_get_cookie_params();
print_r($before);
// 設定を変更
session_set_cookie_params([
'lifetime' => 7200,
'path' => '/secure',
'domain' => '.example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]);
// 変更後
echo "\n=== 変更後 ===\n";
$after = session_get_cookie_params();
print_r($after);
// 差分を表示
echo "\n=== 変更点 ===\n";
foreach ($after as $key => $value) {
if ($before[$key] !== $value) {
echo "{$key}: {$before[$key]} → {$value}\n";
}
}
セキュリティチェック
$params = session_get_cookie_params();
echo "=== セキュリティチェック ===\n";
$issues = [];
// Secureチェック
if (!$params['secure']) {
$issues[] = "WARNING: Secure属性が無効です(HTTPS推奨)";
}
// HttpOnlyチェック
if (!$params['httponly']) {
$issues[] = "WARNING: HttpOnly属性が無効です(XSS対策必須)";
}
// SameSiteチェック
if (isset($params['samesite'])) {
if (empty($params['samesite'])) {
$issues[] = "WARNING: SameSite属性が未設定です(CSRF対策推奨)";
} elseif ($params['samesite'] === 'None' && !$params['secure']) {
$issues[] = "ERROR: SameSite=NoneにはSecure属性が必須です";
}
}
if (empty($issues)) {
echo "✓ セキュリティ設定は適切です\n";
} else {
foreach ($issues as $issue) {
echo "✗ {$issue}\n";
}
}
実践的な使用例
例1: クッキーパラメータ検査システム
class CookieParamsInspector {
private $params;
/**
* インスペクターを初期化
*/
public function __construct() {
$this->params = session_get_cookie_params();
}
/**
* 完全な検査レポートを生成
*/
public function inspect() {
return [
'parameters' => $this->params,
'security_score' => $this->calculateSecurityScore(),
'security_issues' => $this->findSecurityIssues(),
'recommendations' => $this->getRecommendations(),
'compatibility' => $this->checkCompatibility(),
'summary' => $this->generateSummary()
];
}
/**
* セキュリティスコアを計算(0-100)
*/
public function calculateSecurityScore() {
$score = 0;
$maxScore = 100;
// Secure属性(30点)
if ($this->params['secure']) {
$score += 30;
}
// HttpOnly属性(30点)
if ($this->params['httponly']) {
$score += 30;
}
// SameSite属性(25点)
if (isset($this->params['samesite'])) {
if ($this->params['samesite'] === 'Strict') {
$score += 25;
} elseif ($this->params['samesite'] === 'Lax') {
$score += 20;
} elseif ($this->params['samesite'] === 'None' && $this->params['secure']) {
$score += 10;
}
}
// Lifetime設定(15点)
if ($this->params['lifetime'] > 0 && $this->params['lifetime'] <= 86400) {
$score += 15; // 適切な有効期限
} elseif ($this->params['lifetime'] === 0) {
$score += 10; // ブラウザ終了まで
} elseif ($this->params['lifetime'] <= 604800) {
$score += 5; // 1週間以内
}
return [
'score' => $score,
'max_score' => $maxScore,
'percentage' => round(($score / $maxScore) * 100, 2),
'grade' => $this->getSecurityGrade($score)
];
}
/**
* セキュリティグレードを取得
*/
private function getSecurityGrade($score) {
if ($score >= 90) return 'A';
if ($score >= 75) return 'B';
if ($score >= 60) return 'C';
if ($score >= 40) return 'D';
return 'F';
}
/**
* セキュリティ問題を検出
*/
public function findSecurityIssues() {
$issues = [];
// Secure属性チェック
if (!$this->params['secure']) {
$issues[] = [
'severity' => 'high',
'type' => 'secure_disabled',
'message' => 'Secure属性が無効です。HTTPS環境では必須です。',
'impact' => 'Man-in-the-Middle攻撃のリスク'
];
}
// HttpOnly属性チェック
if (!$this->params['httponly']) {
$issues[] = [
'severity' => 'high',
'type' => 'httponly_disabled',
'message' => 'HttpOnly属性が無効です。',
'impact' => 'XSS攻撃によるセッションハイジャックのリスク'
];
}
// SameSite属性チェック
if (isset($this->params['samesite'])) {
if (empty($this->params['samesite'])) {
$issues[] = [
'severity' => 'medium',
'type' => 'samesite_missing',
'message' => 'SameSite属性が未設定です。',
'impact' => 'CSRF攻撃のリスク'
];
} elseif ($this->params['samesite'] === 'None' && !$this->params['secure']) {
$issues[] = [
'severity' => 'critical',
'type' => 'samesite_none_insecure',
'message' => 'SameSite=NoneにはSecure属性が必須です。',
'impact' => 'クッキーが正しく機能しません'
];
}
}
// Lifetime チェック
if ($this->params['lifetime'] > 2592000) { // 30日以上
$issues[] = [
'severity' => 'low',
'type' => 'long_lifetime',
'message' => 'クッキーの有効期限が長すぎます(' .
round($this->params['lifetime'] / 86400) . '日)。',
'impact' => 'セキュリティリスクの増加'
];
}
// Domain チェック
if (!empty($this->params['domain']) && strpos($this->params['domain'], '.') === 0) {
$issues[] = [
'severity' => 'info',
'type' => 'wildcard_domain',
'message' => 'ワイルドカードドメインが使用されています({$this->params['domain']})。',
'impact' => 'すべてのサブドメインでクッキーが共有されます'
];
}
return $issues;
}
/**
* 推奨事項を取得
*/
public function getRecommendations() {
$recommendations = [];
if (!$this->params['secure']) {
$recommendations[] = [
'priority' => 'high',
'action' => 'Secure属性を有効化',
'code' => "session_set_cookie_params(['secure' => true, ...]);"
];
}
if (!$this->params['httponly']) {
$recommendations[] = [
'priority' => 'high',
'action' => 'HttpOnly属性を有効化',
'code' => "session_set_cookie_params(['httponly' => true, ...]);"
];
}
if (isset($this->params['samesite']) && empty($this->params['samesite'])) {
$recommendations[] = [
'priority' => 'medium',
'action' => 'SameSite属性を設定(Lax推奨)',
'code' => "session_set_cookie_params(['samesite' => 'Lax', ...]);"
];
}
if ($this->params['lifetime'] === 0) {
$recommendations[] = [
'priority' => 'low',
'action' => '明示的な有効期限を設定',
'code' => "session_set_cookie_params(['lifetime' => 3600, ...]);"
];
}
return $recommendations;
}
/**
* 互換性チェック
*/
public function checkCompatibility() {
$compatibility = [
'php_version' => PHP_VERSION,
'samesite_support' => PHP_VERSION_ID >= 70300,
'issues' => []
];
// SameSite対応チェック
if (PHP_VERSION_ID < 70300 && isset($this->params['samesite'])) {
$compatibility['issues'][] = 'PHP 7.3.0未満ではSameSite属性が正しく機能しない可能性があります';
}
// Secure + SameSite=None チェック
if (isset($this->params['samesite']) &&
$this->params['samesite'] === 'None' &&
!$this->params['secure']) {
$compatibility['issues'][] = 'SameSite=NoneにはSecure=trueが必須です';
}
return $compatibility;
}
/**
* サマリーを生成
*/
public function generateSummary() {
$score = $this->calculateSecurityScore();
$issues = $this->findSecurityIssues();
$criticalCount = count(array_filter($issues, function($i) {
return $i['severity'] === 'critical';
}));
$highCount = count(array_filter($issues, function($i) {
return $i['severity'] === 'high';
}));
return [
'security_grade' => $score['grade'],
'security_percentage' => $score['percentage'],
'total_issues' => count($issues),
'critical_issues' => $criticalCount,
'high_issues' => $highCount,
'status' => $criticalCount > 0 ? 'critical' :
($highCount > 0 ? 'warning' : 'ok')
];
}
/**
* レポートを表示
*/
public function displayReport() {
$report = $this->inspect();
echo "=== Cookie Parameters Inspection Report ===\n\n";
// サマリー
echo "Security Grade: {$report['summary']['security_grade']} ";
echo "({$report['summary']['security_percentage']}%)\n";
echo "Status: " . strtoupper($report['summary']['status']) . "\n";
echo "Total Issues: {$report['summary']['total_issues']}\n\n";
// パラメータ
echo "Current Parameters:\n";
foreach ($report['parameters'] as $key => $value) {
$displayValue = is_bool($value) ? ($value ? 'true' : 'false') : $value;
echo " {$key}: {$displayValue}\n";
}
echo "\n";
// 問題点
if (!empty($report['security_issues'])) {
echo "Security Issues:\n";
foreach ($report['security_issues'] as $issue) {
echo " [{$issue['severity']}] {$issue['message']}\n";
echo " Impact: {$issue['impact']}\n";
}
echo "\n";
}
// 推奨事項
if (!empty($report['recommendations'])) {
echo "Recommendations:\n";
foreach ($report['recommendations'] as $rec) {
echo " [{$rec['priority']}] {$rec['action']}\n";
echo " {$rec['code']}\n";
}
}
}
}
// 使用例
echo "=== クッキーパラメータ検査 ===\n";
$inspector = new CookieParamsInspector();
// レポート表示
$inspector->displayReport();
// 詳細な検査結果
$report = $inspector->inspect();
echo "\n=== セキュリティスコア詳細 ===\n";
echo "スコア: {$report['security_score']['score']}/{$report['security_score']['max_score']}\n";
echo "グレード: {$report['security_score']['grade']}\n";
例2: セキュリティ監査ツール
class SessionSecurityAuditor {
private $auditResults = [];
/**
* 完全なセキュリティ監査を実行
*/
public function audit() {
$this->auditResults = [];
// 各項目を監査
$this->auditCookieParams();
$this->auditSessionConfig();
$this->auditSecurityHeaders();
$this->auditBestPractices();
return $this->generateAuditReport();
}
/**
* クッキーパラメータを監査
*/
private function auditCookieParams() {
$params = session_get_cookie_params();
$findings = [];
// Secure属性の監査
$findings[] = [
'category' => 'Cookie Security',
'check' => 'Secure Attribute',
'status' => $params['secure'] ? 'pass' : 'fail',
'value' => $params['secure'] ? 'Enabled' : 'Disabled',
'recommendation' => $params['secure'] ?
'Good' : 'Enable Secure attribute for HTTPS',
'severity' => $params['secure'] ? 'none' : 'high'
];
// HttpOnly属性の監査
$findings[] = [
'category' => 'Cookie Security',
'check' => 'HttpOnly Attribute',
'status' => $params['httponly'] ? 'pass' : 'fail',
'value' => $params['httponly'] ? 'Enabled' : 'Disabled',
'recommendation' => $params['httponly'] ?
'Good' : 'Enable HttpOnly to prevent XSS',
'severity' => $params['httponly'] ? 'none' : 'high'
];
// SameSite属性の監査
if (isset($params['samesite'])) {
$sameSiteOk = in_array($params['samesite'], ['Strict', 'Lax']);
$findings[] = [
'category' => 'Cookie Security',
'check' => 'SameSite Attribute',
'status' => $sameSiteOk ? 'pass' : 'warning',
'value' => $params['samesite'] ?: 'Not set',
'recommendation' => $sameSiteOk ?
'Good' : 'Set SameSite to Lax or Strict',
'severity' => $sameSiteOk ? 'none' : 'medium'
];
}
// Lifetime の監査
$lifetimeOk = $params['lifetime'] > 0 && $params['lifetime'] <= 86400;
$findings[] = [
'category' => 'Cookie Security',
'check' => 'Cookie Lifetime',
'status' => $lifetimeOk ? 'pass' : 'info',
'value' => $params['lifetime'] === 0 ?
'Browser session' : $params['lifetime'] . ' seconds',
'recommendation' => $lifetimeOk ?
'Appropriate' : 'Consider setting explicit lifetime',
'severity' => 'low'
];
$this->auditResults['cookie_params'] = $findings;
}
/**
* セッション設定を監査
*/
private function auditSessionConfig() {
$findings = [];
// session.use_strict_mode
$strictMode = ini_get('session.use_strict_mode');
$findings[] = [
'category' => 'Session Configuration',
'check' => 'Strict Mode',
'status' => $strictMode ? 'pass' : 'fail',
'value' => $strictMode ? 'Enabled' : 'Disabled',
'recommendation' => $strictMode ?
'Good' : 'Enable session.use_strict_mode',
'severity' => $strictMode ? 'none' : 'high'
];
// session.use_only_cookies
$onlyCookies = ini_get('session.use_only_cookies');
$findings[] = [
'category' => 'Session Configuration',
'check' => 'Use Only Cookies',
'status' => $onlyCookies ? 'pass' : 'fail',
'value' => $onlyCookies ? 'Enabled' : 'Disabled',
'recommendation' => $onlyCookies ?
'Good' : 'Enable session.use_only_cookies',
'severity' => $onlyCookies ? 'none' : 'critical'
];
// session.cookie_httponly
$cookieHttpOnly = ini_get('session.cookie_httponly');
$findings[] = [
'category' => 'Session Configuration',
'check' => 'Cookie HttpOnly (ini)',
'status' => $cookieHttpOnly ? 'pass' : 'fail',
'value' => $cookieHttpOnly ? 'Enabled' : 'Disabled',
'recommendation' => $cookieHttpOnly ?
'Good' : 'Enable session.cookie_httponly',
'severity' => $cookieHttpOnly ? 'none' : 'high'
];
// session.cookie_secure
$cookieSecure = ini_get('session.cookie_secure');
$findings[] = [
'category' => 'Session Configuration',
'check' => 'Cookie Secure (ini)',
'status' => $cookieSecure ? 'pass' : 'warning',
'value' => $cookieSecure ? 'Enabled' : 'Disabled',
'recommendation' => $cookieSecure ?
'Good' : 'Enable session.cookie_secure for HTTPS',
'severity' => $cookieSecure ? 'none' : 'high'
];
$this->auditResults['session_config'] = $findings;
}
/**
* セキュリティヘッダーを監査
*/
private function auditSecurityHeaders() {
$findings = [];
// この実装例では実際のヘッダー送信はしないため、
// 推奨事項のみを記録
$findings[] = [
'category' => 'Security Headers',
'check' => 'X-Frame-Options',
'status' => 'info',
'value' => 'Not checked',
'recommendation' => 'Set X-Frame-Options: DENY or SAMEORIGIN',
'severity' => 'medium'
];
$findings[] = [
'category' => 'Security Headers',
'check' => 'X-Content-Type-Options',
'status' => 'info',
'value' => 'Not checked',
'recommendation' => 'Set X-Content-Type-Options: nosniff',
'severity' => 'low'
];
$findings[] = [
'category' => 'Security Headers',
'check' => 'Strict-Transport-Security',
'status' => 'info',
'value' => 'Not checked',
'recommendation' => 'Set HSTS header for HTTPS',
'severity' => 'medium'
];
$this->auditResults['security_headers'] = $findings;
}
/**
* ベストプラクティスを監査
*/
private function auditBestPractices() {
$findings = [];
$params = session_get_cookie_params();
// セキュアな設定の組み合わせ
$hasSecureCombo = $params['secure'] &&
$params['httponly'] &&
isset($params['samesite']) &&
!empty($params['samesite']);
$findings[] = [
'category' => 'Best Practices',
'check' => 'Secure Cookie Combination',
'status' => $hasSecureCombo ? 'pass' : 'fail',
'value' => $hasSecureCombo ?
'All security attributes enabled' :
'Missing security attributes',
'recommendation' => $hasSecureCombo ?
'Excellent' :
'Enable Secure, HttpOnly, and SameSite together',
'severity' => $hasSecureCombo ? 'none' : 'high'
];
// Domain設定の適切性
$appropriateDomain = empty($params['domain']) ||
!str_starts_with($params['domain'], '.');
$findings[] = [
'category' => 'Best Practices',
'check' => 'Domain Scope',
'status' => $appropriateDomain ? 'pass' : 'warning',
'value' => empty($params['domain']) ?
'Current host only' : $params['domain'],
'recommendation' => $appropriateDomain ?
'Appropriate' :
'Be cautious with wildcard domains',
'severity' => 'low'
];
$this->auditResults['best_practices'] = $findings;
}
/**
* 監査レポートを生成
*/
private function generateAuditReport() {
$allFindings = [];
foreach ($this->auditResults as $category => $findings) {
$allFindings = array_merge($allFindings, $findings);
}
// 統計を計算
$stats = [
'total_checks' => count($allFindings),
'passed' => 0,
'failed' => 0,
'warnings' => 0,
'info' => 0,
'critical' => 0,
'high' => 0,
'medium' => 0,
'low' => 0
];
foreach ($allFindings as $finding) {
// ステータス
switch ($finding['status']) {
case 'pass':
$stats['passed']++;
break;
case 'fail':
$stats['failed']++;
break;
case 'warning':
$stats['warnings']++;
break;
case 'info':
$stats['info']++;
break;
}
// 深刻度
switch ($finding['severity']) {
case 'critical':
$stats['critical']++;
break;
case 'high':
$stats['high']++;
break;
case 'medium':
$stats['medium']++;
break;
case 'low':
$stats['low']++;
break;
}
}
// 総合評価
$overallScore = 100;
$overallScore -= $stats['critical'] * 30;
$overallScore -= $stats['high'] * 20;
$overallScore -= $stats['medium'] * 10;
$overallScore -= $stats['low'] * 5;
$overallScore = max(0, $overallScore);
return [
'findings' => $this->auditResults,
'statistics' => $stats,
'overall_score' => $overallScore,
'overall_grade' => $this->calculateGrade($overallScore),
'timestamp' => time()
];
}
/**
* グレードを計算
*/
private function calculateGrade($score) {
if ($score >= 90) return 'A';
if ($score >= 80) return 'B';
if ($score >= 70) return 'C';
if ($score >= 60) return 'D';
return 'F';
}
/**
* レポートを表示
*/
public function displayReport() {
$report = $this->audit();
echo "=== Session Security Audit Report ===\n\n";
echo "Overall Score: {$report['overall_score']}/100 (Grade: {$report['overall_grade']})\n";
echo "Timestamp: " . date('Y-m-d H:i:s', $report['timestamp']) . "\n\n";
echo "Summary:\n";
echo " Total Checks: {$report['statistics']['total_checks']}\n";
echo " Passed: {$report['statistics']['passed']}\n";
echo " Failed: {$report['statistics']['failed']}\n";
echo " Warnings: {$report['statistics']['warnings']}\n";
echo " Critical Issues: {$report['statistics']['critical']}\n";
echo " High Issues: {$report['statistics']['high']}\n\n";
foreach ($report['findings'] as $category => $findings) {
echo strtoupper(str_replace('_', ' ', $category)) . ":\n";
foreach ($findings as $finding) {
$status = strtoupper($finding['status']);
echo " [{$status}] {$finding['check']}\n";
echo " Value: {$finding['value']}\n";
echo " Recommendation: {$finding['recommendation']}\n";
if ($finding['severity'] !== 'none') {
echo " Severity: {$finding['severity']}\n";
}
}
echo "\n";
}
}
/**
* JSON形式でエクスポート
*/
public function exportJson() {
$report = $this->audit();
return json_encode($report, JSON_PRETTY_PRINT);
}
}
// 使用例
echo "=== セキュリティ監査ツール ===\n";
$auditor = new SessionSecurityAuditor();
// レポート表示
$auditor->displayReport();
// JSON エクスポート
echo "\n=== JSON Export ===\n";
$json = $auditor->exportJson();
echo substr($json, 0, 500) . "...\n";
例3: クッキー設定管理システム
class CookieParamsManager {
private $profiles = [];
/**
* マネージャーを初期化
*/
public function __construct() {
$this->initializeProfiles();
}
/**
* デフォルトプロファイルを初期化
*/
private function initializeProfiles() {
// 開発環境プロファイル
$this->profiles['development'] = [
'lifetime' => 0,
'path' => '/',
'domain' => '',
'secure' => false,
'httponly' => true,
'samesite' => 'Lax'
];
// 本番環境プロファイル
$this->profiles['production'] = [
'lifetime' => 7200, // 2時間
'path' => '/',
'domain' => '',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
];
// API用プロファイル
$this->profiles['api'] = [
'lifetime' => 3600, // 1時間
'path' => '/api',
'domain' => '',
'secure' => true,
'httponly' => true,
'samesite' => 'None' // クロスドメインAPI用
];
// 管理画面プロファイル
$this->profiles['admin'] = [
'lifetime' => 1800, // 30分
'path' => '/admin',
'domain' => '',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
];
}
/**
* プロファイルを適用
*/
public function applyProfile($profileName) {
if (!isset($this->profiles[$profileName])) {
throw new Exception("Profile not found: {$profileName}");
}
$before = session_get_cookie_params();
$profile = $this->profiles[$profileName];
session_set_cookie_params($profile);
$after = session_get_cookie_params();
return [
'profile' => $profileName,
'before' => $before,
'after' => $after,
'applied' => $profile
];
}
/**
* カスタムプロファイルを作成
*/
public function createProfile($name, $params) {
// バリデーション
$this->validateParams($params);
$this->profiles[$name] = $params;
return [
'name' => $name,
'params' => $params,
'created' => true
];
}
/**
* パラメータをバリデート
*/
private function validateParams($params) {
$required = ['lifetime', 'path', 'domain', 'secure', 'httponly'];
foreach ($required as $key) {
if (!array_key_exists($key, $params)) {
throw new Exception("Missing required parameter: {$key}");
}
}
// 型チェック
if (!is_int($params['lifetime']) || $params['lifetime'] < 0) {
throw new Exception("Invalid lifetime: must be non-negative integer");
}
if (!is_string($params['path'])) {
throw new Exception("Invalid path: must be string");
}
if (!is_bool($params['secure'])) {
throw new Exception("Invalid secure: must be boolean");
}
if (!is_bool($params['httponly'])) {
throw new Exception("Invalid httponly: must be boolean");
}
// SameSite値チェック
if (isset($params['samesite'])) {
$validSameSite = ['', 'Lax', 'Strict', 'None'];
if (!in_array($params['samesite'], $validSameSite)) {
throw new Exception("Invalid samesite: must be one of " . implode(', ', $validSameSite));
}
}
// セキュリティチェック
if (isset($params['samesite']) &&
$params['samesite'] === 'None' &&
!$params['secure']) {
throw new Exception("SameSite=None requires Secure=true");
}
}
/**
* プロファイル一覧を取得
*/
public function listProfiles() {
$list = [];
foreach ($this->profiles as $name => $params) {
$list[$name] = [
'name' => $name,
'params' => $params,
'security_level' => $this->assessSecurityLevel($params)
];
}
return $list;
}
/**
* セキュリティレベルを評価
*/
private function assessSecurityLevel($params) {
$score = 0;
if ($params['secure']) $score += 30;
if ($params['httponly']) $score += 30;
if (isset($params['samesite']) && $params['samesite'] === 'Strict') $score += 25;
elseif (isset($params['samesite']) && $params['samesite'] === 'Lax') $score += 15;
if ($params['lifetime'] > 0 && $params['lifetime'] <= 3600) $score += 15;
if ($score >= 85) return 'high';
if ($score >= 60) return 'medium';
return 'low';
}
/**
* 現在の設定を取得
*/
public function getCurrentSettings() {
$params = session_get_cookie_params();
return [
'params' => $params,
'security_level' => $this->assessSecurityLevel($params),
'profile_match' => $this->findMatchingProfile($params)
];
}
/**
* マッチするプロファイルを検索
*/
private function findMatchingProfile($params) {
foreach ($this->profiles as $name => $profile) {
if ($this->paramsMatch($params, $profile)) {
return $name;
}
}
return null;
}
/**
* パラメータが一致するかチェック
*/
private function paramsMatch($params1, $params2) {
$keys = ['lifetime', 'path', 'domain', 'secure', 'httponly'];
foreach ($keys as $key) {
if ($params1[$key] !== $params2[$key]) {
return false;
}
}
// SameSite は optional
if (isset($params1['samesite']) && isset($params2['samesite'])) {
if ($params1['samesite'] !== $params2['samesite']) {
return false;
}
}
return true;
}
/**
* プロファイル比較
*/
public function compareProfiles($profile1, $profile2) {
if (!isset($this->profiles[$profile1]) || !isset($this->profiles[$profile2])) {
throw new Exception("One or both profiles not found");
}
$p1 = $this->profiles[$profile1];
$p2 = $this->profiles[$profile2];
$differences = [];
$allKeys = array_unique(array_merge(array_keys($p1), array_keys($p2)));
foreach ($allKeys as $key) {
$val1 = $p1[$key] ?? null;
$val2 = $p2[$key] ?? null;
if ($val1 !== $val2) {
$differences[$key] = [
$profile1 => $val1,
$profile2 => $val2
];
}
}
return [
'profile1' => $profile1,
'profile2' => $profile2,
'differences' => $differences,
'identical' => empty($differences)
];
}
/**
* 環境に応じた推奨プロファイルを取得
*/
public function getRecommendedProfile($environment = 'production', $isHttps = true) {
if ($environment === 'development') {
return 'development';
}
if (!$isHttps) {
// HTTPSでない場合は警告
return [
'recommended' => 'development',
'warning' => 'HTTPS is not available. Secure cookies cannot be used.'
];
}
return 'production';
}
}
// 使用例
echo "=== クッキー設定管理システム ===\n";
$manager = new CookieParamsManager();
// プロファイル一覧
echo "利用可能なプロファイル:\n";
foreach ($manager->listProfiles() as $name => $info) {
echo " {$name}: セキュリティレベル={$info['security_level']}\n";
}
// 現在の設定
echo "\n現在の設定:\n";
$current = $manager->getCurrentSettings();
echo " セキュリティレベル: {$current['security_level']}\n";
echo " マッチするプロファイル: " . ($current['profile_match'] ?? 'なし') . "\n";
// プロファイル適用
echo "\n本番環境プロファイルを適用:\n";
$result = $manager->applyProfile('production');
echo " 適用完了\n";
echo " Secure: " . ($result['after']['secure'] ? 'Yes' : 'No') . "\n";
echo " HttpOnly: " . ($result['after']['httponly'] ? 'Yes' : 'No') . "\n";
echo " SameSite: {$result['after']['samesite']}\n";
// プロファイル比較
echo "\n開発環境 vs 本番環境:\n";
$comparison = $manager->compareProfiles('development', 'production');
foreach ($comparison['differences'] as $key => $values) {
echo " {$key}:\n";
foreach ($values as $profile => $value) {
$displayValue = is_bool($value) ? ($value ? 'true' : 'false') : $value;
echo " {$profile}: {$displayValue}\n";
}
}
// カスタムプロファイル作成
echo "\nカスタムプロファイル作成:\n";
$custom = $manager->createProfile('custom_strict', [
'lifetime' => 900, // 15分
'path' => '/secure',
'domain' => '',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]);
echo " {$custom['name']} を作成しました\n";
例4: クッキーパラメータ変更履歴トラッカー
class CookieParamsHistoryTracker {
private $historyFile;
private $history = [];
/**
* トラッカーを初期化
*/
public function __construct($historyFile = '/tmp/cookie_params_history.json') {
$this->historyFile = $historyFile;
$this->loadHistory();
}
/**
* 履歴を読み込み
*/
private function loadHistory() {
if (file_exists($this->historyFile)) {
$this->history = json_decode(file_get_contents($this->historyFile), true) ?? [];
}
}
/**
* 履歴を保存
*/
private function saveHistory() {
file_put_contents($this->historyFile, json_encode($this->history, JSON_PRETTY_PRINT));
}
/**
* 現在のパラメータを記録
*/
public function snapshot($label = null) {
$params = session_get_cookie_params();
$snapshot = [
'timestamp' => time(),
'label' => $label,
'params' => $params,
'php_version' => PHP_VERSION,
'session_started' => session_status() === PHP_SESSION_ACTIVE
];
$this->history[] = $snapshot;
$this->saveHistory();
return $snapshot;
}
/**
* 履歴を取得
*/
public function getHistory($limit = null) {
$history = $this->history;
if ($limit !== null) {
$history = array_slice($history, -$limit);
}
return $history;
}
/**
* 変更を検出
*/
public function detectChanges() {
if (count($this->history) < 2) {
return [
'has_changes' => false,
'message' => 'Insufficient history for comparison'
];
}
$latest = end($this->history);
$previous = $this->history[count($this->history) - 2];
$changes = [];
foreach ($latest['params'] as $key => $value) {
if (!isset($previous['params'][$key]) || $previous['params'][$key] !== $value) {
$changes[$key] = [
'old' => $previous['params'][$key] ?? null,
'new' => $value,
'timestamp' => $latest['timestamp']
];
}
}
return [
'has_changes' => !empty($changes),
'changes' => $changes,
'previous_snapshot' => $previous,
'latest_snapshot' => $latest
];
}
/**
* 特定期間の変更履歴を分析
*/
public function analyzeChanges($startTime = null, $endTime = null) {
$startTime = $startTime ?? 0;
$endTime = $endTime ?? time();
$periodHistory = array_filter($this->history, function($snapshot) use ($startTime, $endTime) {
return $snapshot['timestamp'] >= $startTime && $snapshot['timestamp'] <= $endTime;
});
if (count($periodHistory) < 2) {
return ['error' => 'Insufficient data in specified period'];
}
$allChanges = [];
$previousSnapshot = null;
foreach ($periodHistory as $snapshot) {
if ($previousSnapshot !== null) {
foreach ($snapshot['params'] as $key => $value) {
if (!isset($previousSnapshot['params'][$key]) ||
$previousSnapshot['params'][$key] !== $value) {
if (!isset($allChanges[$key])) {
$allChanges[$key] = [];
}
$allChanges[$key][] = [
'timestamp' => $snapshot['timestamp'],
'old' => $previousSnapshot['params'][$key] ?? null,
'new' => $value,
'label' => $snapshot['label']
];
}
}
}
$previousSnapshot = $snapshot;
}
return [
'period_start' => date('Y-m-d H:i:s', $startTime),
'period_end' => date('Y-m-d H:i:s', $endTime),
'total_snapshots' => count($periodHistory),
'parameters_changed' => array_keys($allChanges),
'change_count' => array_sum(array_map('count', $allChanges)),
'changes' => $allChanges
];
}
/**
* パラメータごとの変更頻度を取得
*/
public function getChangeFrequency() {
$frequency = [];
for ($i = 1; $i < count($this->history); $i++) {
$previous = $this->history[$i - 1];
$current = $this->history[$i];
foreach ($current['params'] as $key => $value) {
if (!isset($previous['params'][$key]) || $previous['params'][$key] !== $value) {
if (!isset($frequency[$key])) {
$frequency[$key] = 0;
}
$frequency[$key]++;
}
}
}
arsort($frequency);
return $frequency;
}
/**
* ロールバック(特定のスナップショットに戻す)
*/
public function rollback($index) {
if (!isset($this->history[$index])) {
throw new Exception("Snapshot not found at index: {$index}");
}
$snapshot = $this->history[$index];
$params = $snapshot['params'];
session_set_cookie_params($params);
// 新しいスナップショットを作成
$this->snapshot("Rolled back to index {$index}");
return [
'rolled_back_to' => $index,
'timestamp' => $snapshot['timestamp'],
'label' => $snapshot['label'],
'params' => $params
];
}
/**
* レポートを生成
*/
public function generateReport() {
$report = "=== Cookie Parameters History Report ===\n\n";
$report .= "Total Snapshots: " . count($this->history) . "\n";
if (!empty($this->history)) {
$first = reset($this->history);
$last = end($this->history);
$report .= "First Snapshot: " . date('Y-m-d H:i:s', $first['timestamp']) . "\n";
$report .= "Latest Snapshot: " . date('Y-m-d H:i:s', $last['timestamp']) . "\n\n";
// 変更頻度
$frequency = $this->getChangeFrequency();
if (!empty($frequency)) {
$report .= "Change Frequency:\n";
foreach ($frequency as $param => $count) {
$report .= " {$param}: {$count} changes\n";
}
$report .= "\n";
}
// 最新の変更
$changes = $this->detectChanges();
if ($changes['has_changes']) {
$report .= "Latest Changes:\n";
foreach ($changes['changes'] as $param => $change) {
$oldVal = is_bool($change['old']) ? ($change['old'] ? 'true' : 'false') : $change['old'];
$newVal = is_bool($change['new']) ? ($change['new'] ? 'true' : 'false') : $change['new'];
$report .= " {$param}: {$oldVal} → {$newVal}\n";
}
} else {
$report .= "No recent changes detected\n";
}
}
return $report;
}
/**
* タイムラインを表示
*/
public function displayTimeline($limit = 10) {
$history = array_slice($this->history, -$limit);
echo "=== Cookie Parameters Timeline ===\n\n";
foreach ($history as $index => $snapshot) {
echo "[" . date('Y-m-d H:i:s', $snapshot['timestamp']) . "]";
if ($snapshot['label']) {
echo " {$snapshot['label']}";
}
echo "\n";
foreach ($snapshot['params'] as $key => $value) {
$displayValue = is_bool($value) ? ($value ? 'true' : 'false') : $value;
echo " {$key}: {$displayValue}\n";
}
echo "\n";
}
}
}
// 使用例
echo "=== クッキーパラメータ変更履歴 ===\n";
$tracker = new CookieParamsHistoryTracker('/tmp/cookie_history_test.json');
// 初期スナップショット
$tracker->snapshot('Initial state');
echo "初期状態を記録\n";
// パラメータ変更
session_set_cookie_params([
'lifetime' => 3600,
'path' => '/',
'domain' => '',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
]);
$tracker->snapshot('Enabled security features');
echo "セキュリティ機能を有効化\n";
// さらに変更
session_set_cookie_params([
'lifetime' => 7200,
'path' => '/',
'domain' => '',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]);
$tracker->snapshot('Increased lifetime and stricter SameSite');
echo "有効期限を延長、SameSiteを厳格化\n";
// タイムライン表示
echo "\n";
$tracker->displayTimeline(5);
// 変更検出
echo "=== 最新の変更 ===\n";
$changes = $tracker->detectChanges();
if ($changes['has_changes']) {
foreach ($changes['changes'] as $param => $change) {
$oldVal = is_bool($change['old']) ? ($change['old'] ? 'true' : 'false') : ($change['old'] ?? 'null');
$newVal = is_bool($change['new']) ? ($change['new'] ? 'true' : 'false') : $change['new'];
echo "{$param}: {$oldVal} → {$newVal}\n";
}
}
// レポート生成
echo "\n";
echo $tracker->generateReport();
// 変更頻度
echo "\n=== 変更頻度 ===\n";
$frequency = $tracker->getChangeFrequency();
foreach ($frequency as $param => $count) {
echo "{$param}: {$count}回\n";
}
例5: 環境別設定検証システム
class EnvironmentConfigValidator {
private $environments = [];
/**
* 環境を登録
*/
public function registerEnvironment($name, $expectedParams) {
$this->environments[$name] = $expectedParams;
}
/**
* デフォルト環境を設定
*/
public function setupDefaultEnvironments() {
// ローカル開発環境
$this->registerEnvironment('local', [
'secure' => false,
'httponly' => true,
'samesite' => 'Lax',
'lifetime' => 0
]);
// ステージング環境
$this->registerEnvironment('staging', [
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
'lifetime' => 3600
]);
// 本番環境
$this->registerEnvironment('production', [
'secure' => true,
'httponly' => true,
'samesite' => 'Strict',
'lifetime' => 7200
]);
}
/**
* 現在の環境を検証
*/
public function validate($environmentName) {
if (!isset($this->environments[$environmentName])) {
throw new Exception("Environment not registered: {$environmentName}");
}
$expected = $this->environments[$environmentName];
$actual = session_get_cookie_params();
$mismatches = [];
$matches = [];
foreach ($expected as $key => $expectedValue) {
if (!isset($actual[$key])) {
$mismatches[$key] = [
'expected' => $expectedValue,
'actual' => null,
'severity' => 'error'
];
} elseif ($actual[$key] !== $expectedValue) {
$mismatches[$key] = [
'expected' => $expectedValue,
'actual' => $actual[$key],
'severity' => $this->getSeverity($key, $expectedValue, $actual[$key])
];
} else {
$matches[$key] = $expectedValue;
}
}
return [
'environment' => $environmentName,
'valid' => empty($mismatches),
'matches' => $matches,
'mismatches' => $mismatches,
'match_count' => count($matches),
'mismatch_count' => count($mismatches)
];
}
/**
* 不一致の深刻度を判定
*/
private function getSeverity($key, $expected, $actual) {
// セキュリティ関連は重大
if (in_array($key, ['secure', 'httponly', 'samesite'])) {
// 期待値がセキュアだが実際がそうでない場合
if (($key === 'secure' || $key === 'httponly') && $expected && !$actual) {
return 'critical';
}
if ($key === 'samesite' && $expected === 'Strict' && $actual !== 'Strict') {
return 'high';
}
return 'medium';
}
// その他は低
return 'low';
}
/**
* すべての環境を検証
*/
public function validateAll() {
$results = [];
foreach (array_keys($this->environments) as $envName) {
$results[$envName] = $this->validate($envName);
}
return $results;
}
/**
* 環境を推測
*/
public function detectEnvironment() {
$actual = session_get_cookie_params();
$scores = [];
foreach ($this->environments as $envName => $expected) {
$score = 0;
$total = count($expected);
foreach ($expected as $key => $value) {
if (isset($actual[$key]) && $actual[$key] === $value) {
$score++;
}
}
$scores[$envName] = [
'score' => $score,
'total' => $total,
'percentage' => round(($score / $total) * 100, 2)
];
}
// 最高スコアの環境を取得
uasort($scores, function($a, $b) {
return $b['score'] - $a['score'];
});
$bestMatch = key($scores);
return [
'detected_environment' => $bestMatch,
'confidence' => $scores[$bestMatch]['percentage'],
'all_scores' => $scores
];
}
/**
* 修正提案を生成
*/
public function suggestFix($environmentName) {
$validation = $this->validate($environmentName);
if ($validation['valid']) {
return [
'needs_fix' => false,
'message' => 'Configuration is correct for this environment'
];
}
$fixes = [];
foreach ($validation['mismatches'] as $key => $mismatch) {
$fixes[] = [
'parameter' => $key,
'current_value' => $mismatch['actual'],
'expected_value' => $mismatch['expected'],
'severity' => $mismatch['severity'],
'fix_code' => $this->generateFixCode($key, $mismatch['expected'])
];
}
// 全体の修正コードを生成
$allParams = session_get_cookie_params();
foreach ($validation['mismatches'] as $key => $mismatch) {
$allParams[$key] = $mismatch['expected'];
}
return [
'needs_fix' => true,
'environment' => $environmentName,
'fixes' => $fixes,
'complete_fix_code' => $this->generateCompleteFixCode($allParams)
];
}
/**
* 修正コードを生成
*/
private function generateFixCode($key, $value) {
$valueStr = is_bool($value) ? ($value ? 'true' : 'false') :
(is_string($value) ? "'{$value}'" : $value);
return "session_set_cookie_params(['{$key}' => {$valueStr}, ...]);";
}
/**
* 完全な修正コードを生成
*/
private function generateCompleteFixCode($params) {
$lines = ["session_set_cookie_params(["];
foreach ($params as $key => $value) {
$valueStr = is_bool($value) ? ($value ? 'true' : 'false') :
(is_string($value) ? "'{$value}'" : $value);
$lines[] = " '{$key}' => {$valueStr},";
}
$lines[] = "]);";
return implode("\n", $lines);
}
/**
* 検証レポートを表示
*/
public function displayValidationReport($environmentName) {
$validation = $this->validate($environmentName);
echo "=== Environment Validation Report ===\n";
echo "Environment: {$environmentName}\n";
echo "Status: " . ($validation['valid'] ? 'VALID' : 'INVALID') . "\n";
echo "Matches: {$validation['match_count']}\n";
echo "Mismatches: {$validation['mismatch_count']}\n\n";
if (!empty($validation['matches'])) {
echo "Correct Parameters:\n";
foreach ($validation['matches'] as $key => $value) {
$displayValue = is_bool($value) ? ($value ? 'true' : 'false') : $value;
echo " ✓ {$key}: {$displayValue}\n";
}
echo "\n";
}
if (!empty($validation['mismatches'])) {
echo "Incorrect Parameters:\n";
foreach ($validation['mismatches'] as $key => $mismatch) {
$expectedVal = is_bool($mismatch['expected']) ?
($mismatch['expected'] ? 'true' : 'false') : $mismatch['expected'];
$actualVal = is_bool($mismatch['actual']) ?
($mismatch['actual'] ? 'true' : 'false') : ($mismatch['actual'] ?? 'null');
echo " ✗ {$key}: expected {$expectedVal}, got {$actualVal} ";
echo "[{$mismatch['severity']}]\n";
}
echo "\n";
// 修正提案
$fix = $this->suggestFix($environmentName);
if ($fix['needs_fix']) {
echo "Suggested Fix:\n";
echo $fix['complete_fix_code'] . "\n";
}
}
}
}
// 使用例
echo "=== 環境別設定検証 ===\n";
$validator = new EnvironmentConfigValidator();
$validator->setupDefaultEnvironments();
// 本番環境用の設定を適用
session_set_cookie_params([
'lifetime' => 7200,
'path' => '/',
'domain' => '',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]);
// 本番環境として検証
echo "\n";
$validator->displayValidationReport('production');
// 環境を推測
echo "\n=== 環境検出 ===\n";
$detected = $validator->detectEnvironment();
echo "検出された環境: {$detected['detected_environment']}\n";
echo "確信度: {$detected['confidence']}%\n\n";
// すべての環境のスコア
echo "全環境のマッチング:\n";
foreach ($detected['all_scores'] as $env => $score) {
echo " {$env}: {$score['score']}/{$score['total']} ({$score['percentage']}%)\n";
}
// 間違った設定でテスト
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'domain' => '',
'secure' => false, // 本番環境には不適切
'httponly' => true,
'samesite' => 'Lax' // 本番環境には不適切
]);
echo "\n";
$validator->displayValidationReport('production');
例6: リアルタイムモニタリングシステム
class CookieParamsMonitor {
private $alertThresholds = [];
private $listeners = [];
/**
* モニターを初期化
*/
public function __construct() {
$this->setDefaultThresholds();
}
/**
* デフォルトのしきい値を設定
*/
private function setDefaultThresholds() {
$this->alertThresholds = [
'secure' => ['expected' => true, 'alert_if_different' => true],
'httponly' => ['expected' => true, 'alert_if_different' => true],
'samesite' => ['expected' => 'Strict', 'alert_if_different' => false],
'lifetime' => ['max' => 86400, 'alert_if_exceeded' => true]
];
}
/**
* しきい値を設定
*/
public function setThreshold($param, $threshold) {
$this->alertThresholds[$param] = $threshold;
}
/**
* リスナーを追加
*/
public function addListener($callback) {
$this->listeners[] = $callback;
}
/**
* モニタリングを実行
*/
public function monitor() {
$params = session_get_cookie_params();
$alerts = [];
foreach ($this->alertThresholds as $param => $threshold) {
if (!isset($params[$param])) {
continue;
}
$alert = $this->checkThreshold($param, $params[$param], $threshold);
if ($alert !== null) {
$alerts[] = $alert;
$this->notifyListeners($alert);
}
}
return [
'timestamp' => time(),
'params' => $params,
'alerts' => $alerts,
'alert_count' => count($alerts)
];
}
/**
* しきい値をチェック
*/
private function checkThreshold($param, $value, $threshold) {
// 期待値チェック
if (isset($threshold['expected']) && isset($threshold['alert_if_different'])) {
if ($value !== $threshold['expected'] && $threshold['alert_if_different']) {
return [
'type' => 'value_mismatch',
'param' => $param,
'expected' => $threshold['expected'],
'actual' => $value,
'severity' => 'warning',
'message' => "{$param} is {$value}, expected {$threshold['expected']}"
];
}
}
// 最大値チェック
if (isset($threshold['max']) && isset($threshold['alert_if_exceeded'])) {
if ($value > $threshold['max'] && $threshold['alert_if_exceeded']) {
return [
'type' => 'threshold_exceeded',
'param' => $param,
'max' => $threshold['max'],
'actual' => $value,
'severity' => 'info',
'message' => "{$param} ({$value}) exceeds maximum ({$threshold['max']})"
];
}
}
return null;
}
/**
* リスナーに通知
*/
private function notifyListeners($alert) {
foreach ($this->listeners as $listener) {
call_user_func($listener, $alert);
}
}
/**
* 継続的モニタリング
*/
public function continuousMonitor($duration = 60, $interval = 5) {
$endTime = time() + $duration;
$results = [];
echo "Starting continuous monitoring for {$duration} seconds...\n\n";
while (time() < $endTime) {
$result = $this->monitor();
$results[] = $result;
echo "[" . date('H:i:s') . "] ";
if ($result['alert_count'] > 0) {
echo "ALERTS: {$result['alert_count']}\n";
foreach ($result['alerts'] as $alert) {
echo " [{$alert['severity']}] {$alert['message']}\n";
}
} else {
echo "OK - No alerts\n";
}
sleep($interval);
}
return [
'total_checks' => count($results),
'total_alerts' => array_sum(array_column($results, 'alert_count')),
'results' => $results
];
}
/**
* ヘルスチェック
*/
public function healthCheck() {
$params = session_get_cookie_params();
$score = 0;
$maxScore = 100;
$issues = [];
// Secure(30点)
if ($params['secure']) {
$score += 30;
} else {
$issues[] = 'Secure attribute is disabled';
}
// HttpOnly(30点)
if ($params['httponly']) {
$score += 30;
} else {
$issues[] = 'HttpOnly attribute is disabled';
}
// SameSite(25点)
if (isset($params['samesite']) && in_array($params['samesite'], ['Strict', 'Lax'])) {
$score += 25;
} else {
$issues[] = 'SameSite attribute is not properly set';
}
// Lifetime(15点)
if ($params['lifetime'] > 0 && $params['lifetime'] <= 86400) {
$score += 15;
} else {
$issues[] = 'Lifetime is not optimal';
}
$health = 'critical';
if ($score >= 85) {
$health = 'excellent';
} elseif ($score >= 70) {
$health = 'good';
} elseif ($score >= 50) {
$health = 'fair';
}
return [
'health' => $health,
'score' => $score,
'max_score' => $maxScore,
'percentage' => round(($score / $maxScore) * 100, 2),
'issues' => $issues,
'params' => $params
];
}
/**
* ダッシュボードを表示
*/
public function displayDashboard() {
$health = $this->healthCheck();
$monitoring = $this->monitor();
echo "=== Cookie Parameters Dashboard ===\n\n";
echo "Health Status: " . strtoupper($health['health']) . "\n";
echo "Score: {$health['score']}/{$health['max_score']} ({$health['percentage']}%)\n\n";
echo "Current Parameters:\n";
foreach ($health['params'] as $key => $value) {
$displayValue = is_bool($value) ? ($value ? 'true' : 'false') : $value;
echo " {$key}: {$displayValue}\n";
}
echo "\n";
if (!empty($health['issues'])) {
echo "Issues:\n";
foreach ($health['issues'] as $issue) {
echo " ⚠ {$issue}\n";
}
echo "\n";
}
if ($monitoring['alert_count'] > 0) {
echo "Active Alerts:\n";
foreach ($monitoring['alerts'] as $alert) {
echo " [{$alert['severity']}] {$alert['message']}\n";
}
} else {
echo "✓ No active alerts\n";
}
}
}
// 使用例
echo "=== リアルタイムモニタリング ===\n";
$monitor = new CookieParamsMonitor();
// リスナーを追加
$monitor->addListener(function($alert) {
error_log("Cookie Alert: [{$alert['severity']}] {$alert['message']}");
});
// カスタムしきい値を設定
$monitor->setThreshold('lifetime', [
'max' => 3600,
'alert_if_exceeded' => true
]);
// ダッシュボード表示
$monitor->displayDashboard();
// モニタリング実行
echo "\n=== モニタリング結果 ===\n";
$result = $monitor->monitor();
echo "アラート数: {$result['alert_count']}\n";
foreach ($result['alerts'] as $alert) {
echo " {$alert['message']}\n";
}
// ヘルスチェック
echo "\n=== ヘルスチェック ===\n";
$health = $monitor->healthCheck();
echo "健全性: {$health['health']}\n";
echo "スコア: {$health['percentage']}%\n";
// 継続的モニタリング(コメントアウト)
// echo "\n=== 継続的モニタリング ===\n";
// $continuous = $monitor->continuousMonitor(30, 5);
// echo "総チェック数: {$continuous['total_checks']}\n";
// echo "総アラート数: {$continuous['total_alerts']}\n";
セキュリティベストプラクティス
// 推奨されるセキュアな設定
// 本番環境(HTTPS必須)
session_set_cookie_params([
'lifetime' => 7200, // 2時間
'path' => '/',
'domain' => '',
'secure' => true, // HTTPS必須
'httponly' => true, // JavaScript無効
'samesite' => 'Strict' // CSRF防止
]);
// 設定を確認
$params = session_get_cookie_params();
// セキュリティチェック
$isSecure = $params['secure'] &&
$params['httponly'] &&
isset($params['samesite']) &&
$params['samesite'] === 'Strict';
if (!$isSecure) {
trigger_error('Insecure cookie configuration', E_USER_WARNING);
}
パラメータの意味と推奨値
// 各パラメータの詳細
// lifetime(有効期限)
// 0 = ブラウザ終了まで(推奨:セキュリティ重視)
// 3600 = 1時間(推奨:一般的なアプリ)
// 7200 = 2時間(推奨:通常の業務アプリ)
// 86400 = 24時間(長期セッション)
// path(有効パス)
// '/' = サイト全体(デフォルト、推奨)
// '/admin' = 管理画面のみ
// '/api' = API専用
// domain(有効ドメイン)
// '' = 現在のホストのみ(推奨)
// '.example.com' = サブドメイン含む(注意が必要)
// secure(HTTPS限定)
// true = HTTPS接続でのみ送信(本番環境推奨)
// false = HTTPでも送信(開発環境のみ)
// httponly(JavaScript無効)
// true = JavaScriptからアクセス不可(強く推奨)
// false = JavaScriptからアクセス可能(XSSリスク)
// samesite(CSRF対策)
// 'Strict' = 最も厳格(推奨:高セキュリティ)
// 'Lax' = バランス型(推奨:一般的)
// 'None' = 制限なし(Secure必須、特殊用途のみ)
// '' = 未設定(非推奨)
まとめ
session_get_cookie_params()関数の特徴をまとめると:
できること:
- セッションクッキーパラメータの取得
- セキュリティ設定の確認
- 現在の設定の監査
- 設定の検証とデバッグ
返される配列の構造:
[
'lifetime' => int, // 有効期限(秒)
'path' => string, // 有効パス
'domain' => string, // 有効ドメイン
'secure' => bool, // HTTPS限定
'httponly' => bool, // JavaScript無効
'samesite' => string // CSRF対策(PHP 7.3.0以降)
]
重要なセキュリティパラメータ:
- secure: HTTPS接続でのみ送信(本番環境必須)
- httponly: JavaScriptからアクセス不可(XSS対策)
- samesite: CSRF攻撃防止(Strict/Lax推奨)
推奨される使用場面:
- セキュリティ監査
- 環境別設定の検証
- 設定の確認とデバッグ
- コンプライアンスチェック
- 設定変更の履歴管理
session_set_cookie_params()との組み合わせ:
// 設定を変更
session_set_cookie_params([
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]);
// 変更を確認
$params = session_get_cookie_params();
var_dump($params);
ベストプラクティス:
// 1. 設定前の確認
$before = session_get_cookie_params();
// 2. セキュアな設定を適用
session_set_cookie_params([
'lifetime' => 7200,
'path' => '/',
'domain' => '',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]);
// 3. 設定後の検証
$after = session_get_cookie_params();
assert($after['secure'] === true);
assert($after['httponly'] === true);
assert($after['samesite'] === 'Strict');
// 4. セキュリティチェック
function validateCookieParams() {
$params = session_get_cookie_params();
$issues = [];
if (!$params['secure']) {
$issues[] = 'Secure attribute is disabled';
}
if (!$params['httponly']) {
$issues[] = 'HttpOnly attribute is disabled';
}
if (!isset($params['samesite']) || empty($params['samesite'])) {
$issues[] = 'SameSite attribute is not set';
}
return empty($issues);
}
if (!validateCookieParams()) {
trigger_error('Insecure cookie configuration detected', E_USER_WARNING);
}
環境別推奨設定:
// 開発環境
$dev = [
'lifetime' => 0,
'secure' => false, // HTTPでも動作
'httponly' => true,
'samesite' => 'Lax'
];
// ステージング環境
$staging = [
'lifetime' => 3600,
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
];
// 本番環境
$production = [
'lifetime' => 7200,
'secure' => true, // 必須
'httponly' => true, // 必須
'samesite' => 'Strict' // 推奨
];
関連関数:
session_set_cookie_params(): クッキーパラメータを設定session_name(): セッション名を取得/設定session_id(): セッションIDを取得/設定ini_get(): PHP設定を取得
PHP設定との関係:
// session_get_cookie_params()の値は以下のPHP設定に対応
ini_get('session.cookie_lifetime'); // lifetime
ini_get('session.cookie_path'); // path
ini_get('session.cookie_domain'); // domain
ini_get('session.cookie_secure'); // secure
ini_get('session.cookie_httponly'); // httponly
ini_get('session.cookie_samesite'); // samesite (PHP 7.3.0以降)
session_get_cookie_params()は、セッションクッキーの設定を確認するための重要な関数です。セキュリティ監査、設定検証、デバッグに活用して、安全なセッション管理を実現しましょう!
