Refactored search php file

This commit is contained in:
Dan Brown 2025-07-09 21:48:49 +01:00
commit 344072aae0
Signed by: danb
GPG key ID: 46D9F943C24A2EF9

View file

@ -1,26 +1,40 @@
<?php
header('Content-Type: application/json');
/**
* Send a JSON response and exit.
* @param array $data
* @param int $status_code
* @return void
*/
function send_json(array $data, int $status_code = 200): void
{
http_response_code($status_code);
header('Content-Type: application/json');
try {
echo json_encode($data, JSON_THROW_ON_ERROR);
} catch (JsonException) {
http_response_code(500);
// Not using send_json here to avoid potential recursion on error
echo '{"error":"Failed to encode JSON response."}';
}
exit;
}
$query = $_GET['query'] ?? '';
if (empty($query)) {
echo json_encode([]);
exit;
send_json([]);
}
$db_path = __DIR__ . '/search.db';
if (!file_exists($db_path)) {
http_response_code(500);
echo json_encode(['error' => 'Search database not found.']);
exit;
send_json(['error' => 'Search database not found.'], 500);
}
try {
$db = new PDO('sqlite:' . $db_path);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
http_response_code(500);
echo json_encode(['error' => 'Failed to connect to the database.']);
exit;
} catch (PDOException) {
send_json(['error' => 'Failed to connect to the database.'], 500);
}
$words = preg_split('/\s+/', strtolower($query));
@ -32,11 +46,9 @@ $idxQuery = $db->prepare("SELECT `page_id` FROM `index` WHERE `word` = :word_id"
foreach ($words as $word) {
if (empty($word)) continue;
$invert = false;
if (strpos($word, '-') === 0) {
$invert = true;
$word = substr($word, 1);
}
$invert = str_starts_with($word, '-');
$word = $invert ? substr($word, 1) : $word;
if (empty($word)) continue;
$wordQuery->execute([':word' => $word]);
@ -47,45 +59,36 @@ foreach ($words as $word) {
$pages = $idxQuery->fetchAll(PDO::FETCH_COLUMN);
foreach ($pages as $page_id) {
if (!isset($pageRank[$page_id])) {
$pageRank[$page_id] = 0;
}
if ($invert) {
$pageRank[$page_id] -= 65535;
} else {
$pageRank[$page_id]++;
}
$pageRank[$page_id] = ($pageRank[$page_id] ?? 0) + ($invert ? -65535 : 1);
}
}
}
$positiveRankPages = array_filter($pageRank, fn($rank) => $rank > 0);
if (empty($positiveRankPages)) {
send_json([]);
}
$sortedPages = [];
foreach ($pageRank as $page_id => $rank) {
if ($rank > 0) {
$sortedPages[] = ['rank' => $rank, 'page_id' => $page_id];
}
foreach ($positiveRankPages as $page_id => $rank) {
$sortedPages[] = ['rank' => $rank, 'page_id' => $page_id];
}
usort($sortedPages, function($a, $b) {
return $b['rank'] - $a['rank'];
});
if (empty($sortedPages)) {
echo json_encode([]);
exit;
}
usort($sortedPages, fn($a, $b) => $b['rank'] <=> $a['rank']);
$pageIds = array_column($sortedPages, 'page_id');
// Extract page details from the database
$placeholders = implode(',', array_fill(0, count($pageIds), '?'));
$placeholders = str_repeat('?,', count($pageIds) - 1) . '?';
$pageQuery = $db->prepare("SELECT id, url, title FROM pages WHERE id IN ($placeholders)");
$pageQuery->execute($pageIds);
$pagesData = $pageQuery->fetchAll(PDO::FETCH_ASSOC);
// Sort the results to match the sorted IDs above
// Create a map for efficient lookup
$pagesById = array_column($pagesData, null, 'id');
// Build final results in the correct rank order
$results = [];
foreach ($pageIds as $id) {
if (isset($pagesById[$id])) {
@ -94,4 +97,5 @@ foreach ($pageIds as $id) {
}
}
echo json_encode($results);
send_json($results);