From 9ea3249f9d148678851d6b949d3185dcbb0355d0 Mon Sep 17 00:00:00 2001 From: Twarner491 Date: Thu, 28 May 2026 11:16:38 -0700 Subject: [PATCH] PHP shims: derive paths from __DIR__ (PHP-FPM runs as caddy user) BirdNET-Pi's installer runs PHP-FPM as the caddy user, so getenv('HOME') resolves to /var/lib/caddy - not the install user's home. Every path constructed from getenv('HOME') was broken on first install. PHP resolves __DIR__ through the install_services.sh symlink to the realpath ($HOME/BirdNET-Pi/avian/api), so dirname(__DIR__, 2) = the BirdNET-Pi install root and dirname(__DIR__, 3) = the user's home. Works under any username because nothing is hardcoded. Also fixed birdnet-api.php's DB_PATH which walked one level too far (used , 3) - the BirdNET-Pi root is , 2). --- avian/api/birdnet-api.php | 20 ++++++++------------ avian/api/cutout.php | 2 +- avian/api/recording.php | 6 +++--- avian/api/spectrogram.php | 6 +++--- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/avian/api/birdnet-api.php b/avian/api/birdnet-api.php index 59df5db..4fc8aa3 100644 --- a/avian/api/birdnet-api.php +++ b/avian/api/birdnet-api.php @@ -18,18 +18,14 @@ declare(strict_types=1); header('Content-Type: application/json; charset=utf-8'); header('Cache-Control: public, max-age=30'); -// SCRIPT_FILENAME on the Pi resolves through the symlink to -// $HOME/BirdNET-Pi/avian/api/birdnet-api.php - walk three dirs up to -// reach the install root, then point at scripts/birds.db. Lets a Pi -// installed under any username (the BirdNET-Pi installer uses $USER, -// not a fixed name) work without editing this file. -$DB_PATH = dirname(__DIR__, 3) . '/scripts/birds.db'; -// Fallback if the symlink layout ever changes - keeps the most common -// install path working even if SCRIPT_FILENAME oddities trip __DIR__. -if (!file_exists($DB_PATH)) { - $alt = getenv('HOME') . '/BirdNET-Pi/scripts/birds.db'; - if (file_exists($alt)) $DB_PATH = $alt; -} +// PHP resolves __DIR__ through symlinks to the realpath. This script +// lives at $HOME/BirdNET-Pi/avian/api/birdnet-api.php (served via the +// ${EXTRACTED}/avian symlink). dirname(..., 2) walks to the BirdNET-Pi +// install root. Works under any username because we never bake the +// home directory in. getenv('HOME') would resolve to /var/lib/caddy +// under PHP-FPM (BirdNET-Pi runs it as the caddy user), so it can't +// be relied on. +$DB_PATH = dirname(__DIR__, 2) . '/scripts/birds.db'; if (!file_exists($DB_PATH)) { http_response_code(503); diff --git a/avian/api/cutout.php b/avian/api/cutout.php index c4621b8..d33334b 100644 --- a/avian/api/cutout.php +++ b/avian/api/cutout.php @@ -54,7 +54,7 @@ if (is_file($cutout) && filesize($cutout) > 1024) { } // 3. Dynamic cache from a previous Wikipedia + rembg run. -$cacheDir = getenv('HOME') . '/BirdSongs/Extracted/cutouts'; +$cacheDir = dirname(__DIR__, 3) . '/BirdSongs/Extracted/cutouts'; $cachePath = "$cacheDir/$slug.png"; if (is_file($cachePath) && filesize($cachePath) > 1024) { serve_png($cachePath); diff --git a/avian/api/recording.php b/avian/api/recording.php index 43e5f03..c3baa0c 100644 --- a/avian/api/recording.php +++ b/avian/api/recording.php @@ -32,7 +32,7 @@ if ($sci !== '' && !preg_match('/^[A-Za-z]{2,40}(?:[ ][a-z]{2,40}){1,3}$/', $sci exit; } -$BY_DATE = getenv('HOME') . '/BirdSongs/Extracted/By_Date'; +$BY_DATE = dirname(__DIR__, 3) . '/BirdSongs/Extracted/By_Date'; // ---- Direct-by-file lookup ---- // Used by the atlas detail modal to play any past recording. @@ -96,7 +96,7 @@ if ($file !== '') { // ---- Resolve scientific name → common name (with underscores) ---- function resolve_common(string $sci): ?string { // Try birds.json first (preferred - has clean sci/com pairs). - foreach ([getenv('HOME') . '/BirdNET-Pi/scripts/birds.json'] as $f) { + foreach ([dirname(__DIR__, 3) . '/BirdNET-Pi/scripts/birds.json'] as $f) { if (is_readable($f)) { $list = json_decode((string)file_get_contents($f), true); if (is_array($list)) { @@ -112,7 +112,7 @@ function resolve_common(string $sci): ?string { } } // Fallback: labels.txt has "_" or ", " per line. - $labels = getenv('HOME') . '/BirdNET-Pi/model/labels.txt'; + $labels = dirname(__DIR__, 3) . '/BirdNET-Pi/model/labels.txt'; if (is_readable($labels)) { foreach (file($labels, FILE_IGNORE_NEW_LINES) as $line) { if (strpos($line, '_') !== false) { diff --git a/avian/api/spectrogram.php b/avian/api/spectrogram.php index 865f2f0..3552499 100644 --- a/avian/api/spectrogram.php +++ b/avian/api/spectrogram.php @@ -31,7 +31,7 @@ if ($sci !== '' && !preg_match('/^[A-Za-z]{2,40}(?:[ ][a-z]{2,40}){1,3}$/', $sci exit; } -$BY_DATE = getenv('HOME') . '/BirdSongs/Extracted/By_Date'; +$BY_DATE = dirname(__DIR__, 3) . '/BirdSongs/Extracted/By_Date'; // ---- Direct-by-file lookup ---- // BirdNET-Pi writes .mp3 and .png next to each other under @@ -93,7 +93,7 @@ if ($file !== '') { } function resolve_common(string $sci): ?string { - $f = getenv('HOME') . '/BirdNET-Pi/scripts/birds.json'; + $f = dirname(__DIR__, 3) . '/BirdNET-Pi/scripts/birds.json'; if (is_readable($f)) { $list = json_decode((string)file_get_contents($f), true); if (is_array($list)) { @@ -107,7 +107,7 @@ function resolve_common(string $sci): ?string { } } } - $labels = getenv('HOME') . '/BirdNET-Pi/model/labels.txt'; + $labels = dirname(__DIR__, 3) . '/BirdNET-Pi/model/labels.txt'; if (is_readable($labels)) { foreach (file($labels, FILE_IGNORE_NEW_LINES) as $line) { if (strpos($line, '_') !== false) {