fix: harden null/missing-data access surfaced by panel error logs

Fixes five runtime errors seen in production panel logs (v2.3.9):

- HomeController: player home page fatally crashed (count(): null given)
  when content/tmdb_popular was absent or corrupt. Guard the read +
  unserialize, default movies/series to arrays, null-safe the counts.
- ShutdownHandler: "array offset on null" on every live session close
  when $rChannelInfo was null (vod/timeshift or early exit). Use !empty().
- ProcessManager::acquireCronLock: TOCTOU race — a competing cron removed
  the lock file between file_exists() and file_get_contents()/filemtime(),
  emitting "failed to open stream"/"stat failed". Read content+mtime once
  under @, and take the lock if the file vanished.
- AuthRepository::updateCodes: "foreach() argument must be array, null"
  when a code's whitelist JSON decoded to null. Cast to (array).
- admin/review.php: "Undefined array key extension" for URLs without an
  extension. Coalesce pathinfo()['extension'] to ''.
This commit is contained in:
Divarion_D
2026-08-15 23:42:16 +03:00
parent 01c3c4ebaf
commit 82a0cd0289
5 changed files with 41 additions and 16 deletions
+19 -10
View File
@@ -307,18 +307,27 @@ class ProcessManager {
*/
public static function acquireCronLock($lockFile, $timeout = 1800) {
if (file_exists($lockFile)) {
$pid = (int)trim(file_get_contents($lockFile));
// Read content + mtime up front. A competing cron can remove the lock
// file between the exists() check and these reads (TOCTOU), which would
// otherwise emit "failed to open stream" / "stat failed" warnings. If it
// vanished, fall through and take the lock ourselves.
$contents = @file_get_contents($lockFile);
$mtime = @filemtime($lockFile);
if (self::procExists($pid)) {
// Process is running — check if it's stale
if (time() - filemtime($lockFile) >= $timeout) {
// Stale — kill and take over
if ($pid > 0) {
posix_kill($pid, 9);
if ($contents !== false && $mtime !== false) {
$pid = (int)trim($contents);
if (self::procExists($pid)) {
// Process is running — check if it's stale
if (time() - $mtime >= $timeout) {
// Stale — kill and take over
if ($pid > 0) {
posix_kill($pid, 9);
}
} else {
// Still fresh — another instance is running
exit('Running...');
}
} else {
// Still fresh — another instance is running
exit('Running...');
}
}
}