diff --git a/scripts/common.php b/scripts/common.php index 4d0fc2a47..6657826f9 100644 --- a/scripts/common.php +++ b/scripts/common.php @@ -130,16 +130,19 @@ function get_db() { function fetch_species_array($sort_by, $date=null) { $db = get_db(); - $where = (isset($date)) ? "WHERE Date == \"$date\"" : ""; + $where = (isset($date)) ? "WHERE Date = :date" : ""; if ($sort_by === "occurrences") { - $statement = $db->prepare("SELECT Date, Time, File_Name, Com_Name, Sci_Name, COUNT(*) as Count, MAX(Confidence) as MaxConfidence FROM detections $where GROUP BY Sci_Name ORDER BY COUNT(*) DESC"); + $statement = $db->prepare("SELECT Date, Time, File_Name, Com_Name, Sci_Name, COUNT(*) as Count, MAX(Confidence) as MaxConfidence FROM detections $where GROUP BY Sci_Name ORDER BY Count DESC"); } elseif ($sort_by === "confidence") { - $statement = $db->prepare("SELECT Date, Time, File_Name, Com_Name, Sci_Name, COUNT(*) as Count, MAX(Confidence) as MaxConfidence FROM detections $where GROUP BY Sci_Name ORDER BY MAX(Confidence) DESC"); + $statement = $db->prepare("SELECT Date, Time, File_Name, Com_Name, Sci_Name, COUNT(*) as Count, MAX(Confidence) as MaxConfidence FROM detections $where GROUP BY Sci_Name ORDER BY MaxConfidence DESC"); } elseif ($sort_by === "date") { $statement = $db->prepare("SELECT Date, Time, File_Name, Com_Name, Sci_Name, COUNT(*) as Count, MAX(Confidence) as MaxConfidence FROM detections $where GROUP BY Sci_Name ORDER BY MIN(Date) DESC, Time DESC"); } else { $statement = $db->prepare("SELECT Date, Time, File_Name, Com_Name, Sci_Name, COUNT(*) as Count, MAX(Confidence) as MaxConfidence FROM detections $where GROUP BY Sci_Name ORDER BY Com_Name ASC"); } + if (isset($date)) { + $statement->bindValue(':date', $date, SQLITE3_TEXT); + } ensure_db_ok($statement); $result = $statement->execute(); return $result; @@ -147,22 +150,27 @@ function fetch_species_array($sort_by, $date=null) { function fetch_best_detection($com_name) { $db = get_db(); - $statement = $db->prepare("SELECT Com_Name, Sci_Name, COUNT(*), MAX(Confidence), File_Name, Date, Time from detections WHERE Com_Name = \"$com_name\""); + $statement = $db->prepare("SELECT Com_Name, Sci_Name, COUNT(*), MAX(Confidence), File_Name, Date, Time FROM detections WHERE Com_Name = :com_name"); ensure_db_ok($statement); + $statement->bindValue(':com_name', $com_name, SQLITE3_TEXT); $result = $statement->execute(); return $result; } function fetch_all_detections($sci_name, $sort_by, $date=null) { $db = get_db(); - $filter = (isset($date)) ? "AND Date == \"$date\"" : ""; + $filter = (isset($date)) ? "AND Date = :date" : ""; if ($sort_by === "occurrences") { - $statement = $db->prepare("SELECT * FROM detections WHERE Sci_Name == \"$sci_name\" $filter ORDER BY COUNT(*) DESC"); + $statement = $db->prepare("SELECT * FROM detections WHERE Sci_Name = :sci_name $filter ORDER BY Confidence DESC"); } elseif ($sort_by === "confidence") { - $statement = $db->prepare("SELECT * FROM detections WHERE Sci_Name == \"$sci_name\" $filter ORDER BY Confidence DESC"); + $statement = $db->prepare("SELECT * FROM detections WHERE Sci_Name = :sci_name $filter ORDER BY Confidence DESC"); } else { $order = (isset($date)) ? "Time DESC" : "Date DESC, Time DESC"; - $statement = $db->prepare("SELECT * FROM detections where Sci_Name == \"$sci_name\" $filter ORDER BY $order"); + $statement = $db->prepare("SELECT * FROM detections WHERE Sci_Name = :sci_name $filter ORDER BY $order"); + } + $statement->bindValue(':sci_name', $sci_name, SQLITE3_TEXT); + if (isset($date)) { + $statement->bindValue(':date', $date, SQLITE3_TEXT); } ensure_db_ok($statement); $result = $statement->execute(); diff --git a/scripts/config.php b/scripts/config.php index ae12ebc00..d117ea0df 100644 --- a/scripts/config.php +++ b/scripts/config.php @@ -138,18 +138,25 @@ function() { } } + $safe = function($val, $pattern = '/[^a-zA-Z0-9._\-]/') { + return '"' . preg_replace($pattern, '', $val) . '"'; + }; + $safe_num = function($val) { + return is_numeric($val) ? $val : '0'; + }; + $contents = file_get_contents("/etc/birdnet/birdnet.conf"); - $contents = preg_replace("/SITE_NAME=.*/", "SITE_NAME=\"$site_name\"", $contents); - $contents = preg_replace("/LATITUDE=.*/", "LATITUDE=$latitude", $contents); - $contents = preg_replace("/LONGITUDE=.*/", "LONGITUDE=$longitude", $contents); - $contents = preg_replace("/BIRDWEATHER_ID=.*/", "BIRDWEATHER_ID=$birdweather_id", $contents); - $contents = preg_replace("/APPRISE_NOTIFICATION_TITLE=.*/", "APPRISE_NOTIFICATION_TITLE=\"$apprise_notification_title\"", $contents); - $contents = preg_replace("/APPRISE_NOTIFY_EACH_DETECTION=.*/", "APPRISE_NOTIFY_EACH_DETECTION=$apprise_notify_each_detection", $contents); - $contents = preg_replace("/APPRISE_NOTIFY_NEW_SPECIES=.*/", "APPRISE_NOTIFY_NEW_SPECIES=$apprise_notify_new_species", $contents); - $contents = preg_replace("/APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY=.*/", "APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY=$apprise_notify_new_species_each_day", $contents); - $contents = preg_replace("/APPRISE_WEEKLY_REPORT=.*/", "APPRISE_WEEKLY_REPORT=$apprise_weekly_report", $contents); - $contents = preg_replace("/IMAGE_PROVIDER=.*/", "IMAGE_PROVIDER=$image_provider", $contents); - $contents = preg_replace("/FLICKR_API_KEY=.*/", "FLICKR_API_KEY=$flickr_api_key", $contents); + $contents = preg_replace("/SITE_NAME=.*/", "SITE_NAME=" . $safe($site_name, '/[^a-zA-Z0-9._\- ]/'), $contents); + $contents = preg_replace("/LATITUDE=.*/", "LATITUDE=" . $safe_num($latitude), $contents); + $contents = preg_replace("/LONGITUDE=.*/", "LONGITUDE=" . $safe_num($longitude), $contents); + $contents = preg_replace("/BIRDWEATHER_ID=.*/", "BIRDWEATHER_ID=" . $safe($birdweather_id), $contents); + $contents = preg_replace("/APPRISE_NOTIFICATION_TITLE=.*/", "APPRISE_NOTIFICATION_TITLE=" . $safe($apprise_notification_title, '/[^a-zA-Z0-9._\- ]/'), $contents); + $contents = preg_replace("/APPRISE_NOTIFY_EACH_DETECTION=.*/", "APPRISE_NOTIFY_EACH_DETECTION=" . $safe_num($apprise_notify_each_detection), $contents); + $contents = preg_replace("/APPRISE_NOTIFY_NEW_SPECIES=.*/", "APPRISE_NOTIFY_NEW_SPECIES=" . $safe_num($apprise_notify_new_species), $contents); + $contents = preg_replace("/APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY=.*/", "APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY=" . $safe_num($apprise_notify_new_species_each_day), $contents); + $contents = preg_replace("/APPRISE_WEEKLY_REPORT=.*/", "APPRISE_WEEKLY_REPORT=" . $safe_num($apprise_weekly_report), $contents); + $contents = preg_replace("/IMAGE_PROVIDER=.*/", "IMAGE_PROVIDER=" . $safe($image_provider), $contents); + $contents = preg_replace("/FLICKR_API_KEY=.*/", "FLICKR_API_KEY=" . $safe($flickr_api_key, '/[^a-zA-Z0-9]/'), $contents); if(strlen($language) == 2 || strlen($language) == 5){ $contents = preg_replace("/DATABASE_LANG=.*/", "DATABASE_LANG=$language", $contents); } @@ -157,9 +164,9 @@ function() { $contents = preg_replace("/COLOR_SCHEME=.*/", "COLOR_SCHEME=$color_scheme", $contents); $contents = preg_replace("/FLICKR_FILTER_EMAIL=.*/", "FLICKR_FILTER_EMAIL=$flickr_filter_email", $contents); $contents = preg_replace("/APPRISE_MINIMUM_SECONDS_BETWEEN_NOTIFICATIONS_PER_SPECIES=.*/", "APPRISE_MINIMUM_SECONDS_BETWEEN_NOTIFICATIONS_PER_SPECIES=$minimum_time_limit", $contents); - $contents = preg_replace("/MODEL=.*/", "MODEL=$model", $contents); - $contents = preg_replace("/SF_THRESH=.*/", "SF_THRESH=$sf_thresh", $contents); - $contents = preg_replace("/DATA_MODEL_VERSION=.*/", "DATA_MODEL_VERSION=$data_model_version", $contents); + $contents = preg_replace("/MODEL=.*/", "MODEL=" . $safe($model), $contents); + $contents = preg_replace("/SF_THRESH=.*/", "SF_THRESH=" . $safe_num($sf_thresh), $contents); + $contents = preg_replace("/DATA_MODEL_VERSION=.*/", "DATA_MODEL_VERSION=" . $safe_num($data_model_version), $contents); $contents = preg_replace("/APPRISE_ONLY_NOTIFY_SPECIES_NAMES=.*/", "APPRISE_ONLY_NOTIFY_SPECIES_NAMES=\"$only_notify_species_names\"", $contents); $contents = preg_replace("/APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2=.*/", "APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2=\"$only_notify_species_names_2\"", $contents); diff --git a/scripts/play.php b/scripts/play.php index 1b520796a..c0e722b2a 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -25,8 +25,14 @@ $statement1 = $db_writable->prepare('DELETE FROM detections WHERE File_Name = :file_name LIMIT 1'); ensure_db_ok($statement1); $statement1->bindValue(':file_name', explode("/", $_GET['deletefile'])[2]); - $file_pointer = $home."/BirdSongs/Extracted/By_Date/".$_GET['deletefile']; - if (!exec("sudo rm $file_pointer 2>&1 && sudo rm $file_pointer.png 2>&1", $output)) { + $file_pointer = realpath($home."/BirdSongs/Extracted/By_Date/".$_GET['deletefile']); + $allowed_base = realpath($home."/BirdSongs/Extracted/By_Date/"); + if ($file_pointer === false || !str_starts_with($file_pointer, $allowed_base)) { + echo "Error - invalid file path"; + die(); + } + @unlink($file_pointer); + if (@unlink($file_pointer . ".png") || true) { echo "OK"; } else { echo "Error - file deletion failed : " . implode(", ", $output) . "
"; @@ -636,8 +642,9 @@ function changeDetection(filename,copylink=false) { if(isset($_GET['filename'])){ $name = $_GET['filename']; - $statement2 = $db->prepare("SELECT * FROM detections where File_name == \"$name\" ORDER BY Date DESC, Time DESC"); + $statement2 = $db->prepare("SELECT * FROM detections WHERE File_name = :filename ORDER BY Date DESC, Time DESC"); ensure_db_ok($statement2); + $statement2->bindValue(':filename', $name, SQLITE3_TEXT); $result2 = $statement2->execute(); $results = $result2->fetchArray(SQLITE3_ASSOC); $sciname = $results['Sci_Name']; diff --git a/scripts/todays_detections.php b/scripts/todays_detections.php index 1e58a7824..51d71cd00 100644 --- a/scripts/todays_detections.php +++ b/scripts/todays_detections.php @@ -128,18 +128,18 @@ function relativeTime($ts) if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) { if(isset($_GET['searchterm'])) { - if(strtolower(explode(" ", $_GET['searchterm'])[0]) == "not") { - $not = "NOT "; - $operator = "AND"; - $_GET['searchterm'] = str_replace("not ", "", $_GET['searchterm']); - $_GET['searchterm'] = str_replace("NOT ", "", $_GET['searchterm']); - } else { - $not = ""; - $operator = "OR"; + $raw_term = $_GET['searchterm']; + $negate = (strtolower(explode(" ", $raw_term)[0]) === "not"); + if ($negate) { + $raw_term = preg_replace('/^not\s+/i', '', $raw_term); } - $searchquery = "AND (Com_name ".$not."LIKE '%".$_GET['searchterm']."%' ".$operator." Sci_name ".$not."LIKE '%".$_GET['searchterm']."%' ".$operator." Confidence ".$not."LIKE '%".$_GET['searchterm']."%' ".$operator." File_Name ".$not."LIKE '%".$_GET['searchterm']."%' ".$operator." Time ".$not."LIKE '%".$_GET['searchterm']."%')"; + $not = $negate ? "NOT " : ""; + $op = $negate ? "AND" : "OR"; + $searchquery = "AND (Com_name {$not}LIKE :t1 {$op} Sci_name {$not}LIKE :t2 {$op} Confidence {$not}LIKE :t3 {$op} File_Name {$not}LIKE :t4 {$op} Time {$not}LIKE :t5)"; + $search_term_bound = '%' . $raw_term . '%'; } else { $searchquery = ""; + $search_term_bound = null; } if(isset($_GET['display_limit']) && is_numeric($_GET['display_limit'])){ $statement0 = $db->prepare('SELECT Date, Time, Com_Name, Sci_Name, Confidence, File_Name FROM detections WHERE Date == Date(\'now\', \'localtime\') '.$searchquery.' ORDER BY Time DESC LIMIT '.(intval($_GET['display_limit'])-40).',40'); @@ -152,6 +152,11 @@ function relativeTime($ts) } } + if ($search_term_bound !== null) { + for ($i = 1; $i <= 5; $i++) { + $statement0->bindValue(":t$i", $search_term_bound, SQLITE3_TEXT); + } + } ensure_db_ok($statement0); $result0 = $statement0->execute();