Skip to content

Instantly share code, notes, and snippets.

@kazumich
Created September 1, 2025 01:40
Show Gist options
  • Select an option

  • Save kazumich/573189000988b79e966f2246335b3efb to your computer and use it in GitHub Desktop.

Select an option

Save kazumich/573189000988b79e966f2246335b3efb to your computer and use it in GitHub Desktop.
<?php
// filename: clear-cookies.php
// 目的: 実行中のドメインで送信されてきた Cookie(HttpOnly を含む)を、可能な限り失効させる UI 付きツール
// 使い方: このファイルを配置してアクセス。リストが表示され、削除ボタンで失効処理を実行します。
declare(strict_types=1);
// ------------------------------------------------------------
// 設定(必要に応じて拡張してください)
// ------------------------------------------------------------
$extraPaths = [
'/admin', '/admin/', // よくある発行パス
];
// ------------------------------------------------------------
// 共通情報
// ------------------------------------------------------------
$host = $_SERVER['HTTP_HOST'] ?? '';
$https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
$scriptDir = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? '/')), '/');
if ($scriptDir === '') $scriptDir = '/';
// 現在パスからルートまでの階層を作る(/a/b/c -> /a/b/c, /a/b, /a, /)
$pathSegments = array_values(array_filter(explode('/', $scriptDir)));
$pathCandidates = ['/'];
if (!empty($pathSegments)) {
for ($i = 1; $i <= count($pathSegments); $i++) {
$p = '/' . implode('/', array_slice($pathSegments, 0, $i));
$pathCandidates[] = $p;
$pathCandidates[] = rtrim($p, '/') . '/';
}
}
// 追加パス候補もマージ
$pathCandidates = array_values(array_unique(array_merge($pathCandidates, $extraPaths)));
// ドメイン候補(ホスト名、先頭ドット付き、親ドメインを含む)
// 例: sub.example.co.jp -> ["sub.example.co.jp", ".sub.example.co.jp", ".example.co.jp"]
$domainCandidates = [];
if ($host !== '') {
$domainCandidates[] = $host;
$domainCandidates[] = '.' . $host;
// 親ドメイン(最左ラベルを 1 つ落とす簡易版)※ PSL を見ない簡易実装
$parts = explode('.', $host);
if (count($parts) > 2) {
$parent = '.' . implode('.', array_slice($parts, 1));
$domainCandidates[] = $parent;
}
}
$domainCandidates = array_values(array_unique($domainCandidates));
// ------------------------------------------------------------
// 削除処理(POST)
// ------------------------------------------------------------
$deleted = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 受信している Cookie 名を抽出
$cookieNames = array_keys($_COOKIE ?? []);
$expires = time() - 3600; // 過去
foreach ($cookieNames as $name) {
foreach ($pathCandidates as $path) {
// ドメイン未指定(ホスト限定)
@setcookie($name, '', [
'expires' => $expires,
'path' => $path,
// domain を指定しないパターン
'secure' => $https,
'httponly' => true,
'samesite' => 'Lax',
]);
// ドメイン候補に対しても失効を試行
foreach ($domainCandidates as $domain) {
@setcookie($name, '', [
'expires' => $expires,
'path' => $path,
'domain' => $domain,
'secure' => $https,
'httponly' => true,
'samesite' => 'Lax',
]);
}
}
$deleted[] = $name;
}
// PRG パターン(再読み込みでの再 POST 防止)
$qs = http_build_query(['cleared' => 1, 'count' => count($deleted)]);
$url = strtok($_SERVER['REQUEST_URI'], '?') . '?' . $qs;
header('Location: ' . $url, true, 303);
exit;
}
// ------------------------------------------------------------
// 表示用データ
// ------------------------------------------------------------
$currentCookies = $_COOKIE ?? [];
$hasCookies = !empty($currentCookies);
// HTML 出力開始
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Cookie clear tool</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<meta name="robots" content="noindex,nofollow,noarchive" />
</head>
<body class="bg-gray-50 text-gray-900">
<div class="max-w-5xl mx-auto px-4 py-10">
<header class="mb-8">
<h1 class="text-2xl font-bold"><?= htmlspecialchars($host, ENT_QUOTES, 'UTF-8') ?> の Cookie 管理</h1>
<p class="text-sm text-gray-600 mt-2">
HTTPS: <span class="font-mono"><?= $https ? 'true' : 'false' ?></span>
</p>
</header>
<?php if (isset($_GET['cleared'])): ?>
<div class="mb-6 rounded-lg border border-green-200 bg-green-50 p-4">
<p class="font-medium text-green-800">Cookie の削除処理を実行しました。</p>
<p class="text-green-800 text-sm mt-1">必要に応じてページを再読み込みし、最新の状態を確認してください。</p>
</div>
<?php endif; ?>
<section class="mb-8">
<div class="flex items-center justify-between mb-3">
<h2 class="text-xl font-semibold">現在の Cookie 状況</h2>
<span class="text-sm text-gray-600">検出数: <span class="font-medium"><?= count($currentCookies) ?></span></span>
</div>
<?php if ($hasCookies): ?>
<div class="overflow-x-auto rounded-lg border border-gray-200 bg-white">
<table class="min-w-full text-sm">
<thead class="bg-gray-50">
<tr>
<th class="px-4 py-2 text-left font-medium text-gray-600">Name</th>
<th class="px-4 py-2 text-left font-medium text-gray-600">Value (冒頭のみ表示)</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
<?php foreach ($currentCookies as $name => $value): ?>
<tr>
<td class="px-4 py-2 font-mono text-gray-800"><?= htmlspecialchars((string)$name, ENT_QUOTES, 'UTF-8') ?></td>
<td class="px-4 py-2 font-mono text-gray-700">
<?php
$v = (string)$value;
$short = mb_strimwidth($v, 0, 80, '…', 'UTF-8');
echo htmlspecialchars($short, ENT_QUOTES, 'UTF-8');
?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<p class="text-xs text-gray-500 mt-2">
サーバー側からは <span class="font-mono">$_COOKIE</span> に届いたもののみ確認できます。
</p>
<?php else: ?>
<div class="rounded-lg border border-amber-200 bg-amber-50 p-4">
<p class="text-amber-800">現在、サーバーに送信されている Cookie は検出されませんでした。</p>
</div>
<?php endif; ?>
</section>
<section class="mb-12">
<form method="post" class="flex items-center gap-3">
<button
type="submit"
class="inline-flex items-center rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium hover:bg-gray-50"
onclick="return confirm('このドメインの Cookie を削除します。よろしいですか?');">
このドメインの Cookie を削除する
</button>
<a href="<?= htmlspecialchars(strtok($_SERVER['REQUEST_URI'], '?'), ENT_QUOTES, 'UTF-8') ?>"
class="inline-flex items-center rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-medium hover:bg-gray-50">
再読み込み
</a>
</form>
<div class="mt-4 text-xs text-gray-500 space-y-1">
<p>削除時は、以下の組合せで失効させます: <span class="font-mono">Domain</span> =(未指定 / 現在のホスト / 先頭ドット付き / 親ドメイン)、<span class="font-mono">Path</span> = 現在ディレクトリからルートまで + よくあるパス。</p>
<p><span class="font-semibold">注意:</span> 他サイト(例: <span class="font-mono">.twitter.com</span>)の Cookie は、そのサイトで本ツールを実行しない限り削除できません。</p>
</div>
</section>
<footer class="text-xs text-gray-500">
<p>© <?= date('Y') ?> Cookie clear tool</p>
</footer>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment