HTML
<?PHP
// Create cache busting version
$cacheVer = filemtime(__FILE__);
?>
<script src="jquery.min.js?v=<?=$cacheVer?>"></script>
<input type="checkbox" checked id="chk1">
<input type="checkbox" checked id="chk2">
<pre id="output" style="width: 100%; height: 100%; max-height:650px; overflow-y:scroll;"></pre>
<script src="taillog.js?v=<?=$cacheVer?>"></script>
taillog.js
/* Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
var offset,
timer,
pre,
scrolling = true;
// Check every 200msec for fresh data
var interval = 200;
// Function that asks the API for new data
function reloadData() {
clearTimeout(timer);
$.getJSON("tailLog.php?offset=" + offset, function (data) {
pre.append(data.lines);
if (scrolling && offset !== data.offset) {
pre.scrollTop(pre[0].scrollHeight);
}
offset = data.offset;
});
timer = setTimeout(reloadData, interval);
}
$(function () {
// Get offset at first loading of page
$.getJSON("tailLog.php", function (data) {
offset = data.offset;
});
pre = $("#output");
// Trigger function that looks for new data
reloadData();
});
$("#chk1").click(function () {
$("#chk2").prop("checked", this.checked);
scrolling = this.checked;
});
$("#chk2").click(function () {
$("#chk1").prop("checked", this.checked);
scrolling = this.checked;
});
tailLog.php
<?php
/* Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
// Not using SplFileObject here, since direct
// usage of f-streams will be much faster for
// files as large as the pihole.log
if(isset($_GET["FTL"]))
{
$file = fopen('A:\php\batch\log.txt',"r");
}
else
{
$file = fopen('A:\php\batch\log.txt',"r");
}
if(!$file)
{
die(json_encode(array("offset" => 0, "lines" => array("Failed to open log file. Check permissions!\n"))));
}
if(isset($_GET["offset"]))
{
$offset = intval($_GET['offset']);
if($offset > 0)
{
// Seeks on the file pointer where we want to continue reading is known
fseek($file, $offset);
$lines = [];
while (!feof($file))
array_push($lines, htmlspecialchars(fgets($file)));
die(json_encode(array("offset" => ftell($file), "lines" => $lines)));
}
}
// Locate the current position of the file read/write pointer
fseek($file, -1, SEEK_END);
// Add one to skip the very last "\n" in the log file
die(json_encode(array("offset" => ftell($file)+1)));
?>