Last active
August 16, 2024 12:49
-
-
Save shimarin/cd45dafd2dba478b395cb1113dc01d2c to your computer and use it in GitHub Desktop.
JavaScriptのEventSource APIにサーバー側でのファイル更新イベントを通知するためのエンドポイント
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* event.php | |
* JavaScriptのEventSource APIにサーバー側でのファイル更新イベントを通知するためのエンドポイント | |
* | |
* PHPにinotifyエクステンションが必要 https://github.com/arnaud-lb/php-inotify | |
* | |
* 2024 Tomoatsu Shimada | |
*/ | |
// ポーリングのタイムアウトを設定 | |
$timeout = 90; // Cloudflareがタイムアウトしないラインがこれくらい | |
// 変更(書き込みクローズ)をウォッチしたいファイルのリストを設定 | |
$targets = ["index.html"]; | |
// タイムアウト処理のため開始時刻を記録 | |
$start_time = time(); | |
// inotify インスタンスを作成 | |
$inotify = inotify_init(); | |
// 指定されたファイルを全てウォッチ開始 | |
$watch_descriptors = array(); | |
foreach ($targets as $target) { | |
$wd = inotify_add_watch($inotify, $target, IN_CLOSE_WRITE); | |
$watch_descriptors[$wd] = $target; | |
} | |
// EventSource向けのレスポンスヘッダを出力 | |
header("Content-Type: text/event-stream"); | |
header("Cache-Control: no-cache"); | |
// 出力バッファを無効にする。以降の出力は全て即時に送信される | |
ob_implicit_flush(true); | |
ob_end_flush(); | |
while (time() - $start_time < $timeout && connection_status() == CONNECTION_NORMAL) { | |
$read = [$inotify]; | |
$write = null; $except = null; | |
$rst = stream_select($read,$write,$except, 1); | |
if ($rst === 0) continue; // no events | |
if ($rst === false) break; // stream_select failed | |
//else | |
$events = inotify_read($inotify); | |
if (!$events) break; | |
//else | |
foreach ($events as $event) { | |
$target = $watch_descriptors[$event["wd"]]; | |
echo "data: {$target}\n\n"; | |
flush(); | |
} | |
} | |
// ウォッチャーを削除し、inotifyインスタンスを閉じる | |
foreach ($watch_descriptors as $watch_descriptor => $target) { | |
inotify_rm_watch($inotify, $watch_descriptor); | |
} | |
fclose($inotify); | |
/* | |
クライアント例: | |
<script> | |
// サーバーにファイルの更新を監視してもらい、更新されたらブラウザをリロードする | |
const eventSource = new EventSource('event.php'); | |
eventSource.onmessage = function(event) { | |
if (event.data === 'index.html') { | |
window.location.reload(); // index.htmlの更新メッセージを受け取ったらリロード | |
} | |
}; | |
</script> | |
*/ | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment