chore(*.php): use pint for php formatting
This commit is contained in:
parent
029caaaa9e
commit
cf1ee4c97f
40 changed files with 2261 additions and 1900 deletions
276
api/search.php
276
api/search.php
|
@ -1,150 +1,164 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
require_once __DIR__.'/../bootstrap.php';
|
||||
|
||||
use App\Classes\BaseHandler;
|
||||
|
||||
class SearchHandler extends BaseHandler
|
||||
{
|
||||
protected int $cacheTTL = 300;
|
||||
protected int $cacheTTL = 300;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->initializeCache();
|
||||
}
|
||||
|
||||
public function handleRequest(): void
|
||||
{
|
||||
try {
|
||||
$query = $this->validateAndSanitizeQuery($_GET["q"] ?? null);
|
||||
$sections = $this->validateAndSanitizeSections($_GET["section"] ?? "");
|
||||
$page = isset($_GET["page"]) ? intval($_GET["page"]) : 1;
|
||||
$pageSize = isset($_GET["pageSize"]) ? intval($_GET["pageSize"]) : 10;
|
||||
$offset = ($page - 1) * $pageSize;
|
||||
$cacheKey = $this->generateCacheKey($query, $sections, $page, $pageSize);
|
||||
$results = [];
|
||||
$results = $this->getCachedResults($cacheKey) ?? $this->fetchSearchResults($query, $sections, $pageSize, $offset);
|
||||
|
||||
if (empty($results) || empty($results["data"])) {
|
||||
$this->sendResponse(["results" => [], "total" => 0, "page" => $page, "pageSize" => $pageSize], 200);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cacheResults($cacheKey, $results);
|
||||
$this->sendResponse(
|
||||
[
|
||||
"results" => $results["data"],
|
||||
"total" => $results["total"],
|
||||
"page" => $page,
|
||||
"pageSize" => $pageSize,
|
||||
],
|
||||
200
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
error_log("Search API Error: " . $e->getMessage());
|
||||
$this->sendErrorResponse("Invalid request. Please check your query and try again.", 400);
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->initializeCache();
|
||||
}
|
||||
}
|
||||
|
||||
private function validateAndSanitizeQuery(?string $query): string
|
||||
{
|
||||
if (empty($query) || !is_string($query)) throw new \Exception("Invalid 'q' parameter. Must be a non-empty string.");
|
||||
public function handleRequest(): void
|
||||
{
|
||||
try {
|
||||
$query = $this->validateAndSanitizeQuery($_GET['q'] ?? null);
|
||||
$sections = $this->validateAndSanitizeSections($_GET['section'] ?? '');
|
||||
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
|
||||
$pageSize = isset($_GET['pageSize']) ? intval($_GET['pageSize']) : 10;
|
||||
$offset = ($page - 1) * $pageSize;
|
||||
$cacheKey = $this->generateCacheKey($query, $sections, $page, $pageSize);
|
||||
$results = [];
|
||||
$results = $this->getCachedResults($cacheKey) ?? $this->fetchSearchResults($query, $sections, $pageSize, $offset);
|
||||
|
||||
$query = trim($query);
|
||||
if (empty($results) || empty($results['data'])) {
|
||||
$this->sendResponse(['results' => [], 'total' => 0, 'page' => $page, 'pageSize' => $pageSize], 200);
|
||||
|
||||
if (strlen($query) > 255) throw new \Exception("Invalid 'q' parameter. Exceeds maximum length of 255 characters.");
|
||||
if (!preg_match('/^[a-zA-Z0-9\s\-_\'"]+$/', $query)) throw new \Exception("Invalid 'q' parameter. Contains unsupported characters.");
|
||||
return;
|
||||
}
|
||||
|
||||
$query = preg_replace("/\s+/", " ", $query);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
private function validateAndSanitizeSections(string $rawSections): ?array
|
||||
{
|
||||
$allowedSections = ["post", "artist", "genre", "book", "movie", "show"];
|
||||
|
||||
if (empty($rawSections)) return null;
|
||||
|
||||
$sections = array_map(
|
||||
fn($section) => strtolower(
|
||||
trim(htmlspecialchars($section, ENT_QUOTES, "UTF-8"))
|
||||
),
|
||||
explode(",", $rawSections)
|
||||
);
|
||||
$invalidSections = array_diff($sections, $allowedSections);
|
||||
|
||||
if (!empty($invalidSections)) throw new Exception("Invalid 'section' parameter. Unsupported sections: " . implode(", ", $invalidSections));
|
||||
|
||||
return $sections;
|
||||
}
|
||||
|
||||
private function fetchSearchResults(
|
||||
string $query,
|
||||
?array $sections,
|
||||
int $pageSize,
|
||||
int $offset
|
||||
): array {
|
||||
$sectionsParam = $sections && count($sections) > 0 ? "%7B" . implode(",", $sections) . "%7D" : "";
|
||||
$endpoint = "rpc/search_optimized_index";
|
||||
$queryString =
|
||||
"search_query=" .
|
||||
urlencode($query) .
|
||||
"&page_size={$pageSize}&page_offset={$offset}" .
|
||||
($sectionsParam ? "§ions={$sectionsParam}" : "");
|
||||
$data = $this->makeRequest("GET", "{$endpoint}?{$queryString}");
|
||||
$total = count($data) > 0 ? $data[0]["total_count"] : 0;
|
||||
$results = array_map(function ($item) {
|
||||
unset($item["total_count"]);
|
||||
|
||||
if (!empty($item["description"])) $item["description"] = truncateText(strip_tags(parseMarkdown($item["description"])), 225);
|
||||
|
||||
return $item;
|
||||
|
||||
}, $data);
|
||||
|
||||
return ["data" => $results, "total" => $total];
|
||||
}
|
||||
|
||||
private function generateCacheKey(
|
||||
string $query,
|
||||
?array $sections,
|
||||
int $page,
|
||||
int $pageSize
|
||||
): string {
|
||||
$sectionsKey = $sections ? implode(",", $sections) : "all";
|
||||
|
||||
return sprintf(
|
||||
"search:%s:sections:%s:page:%d:pageSize:%d",
|
||||
md5($query),
|
||||
$sectionsKey,
|
||||
$page,
|
||||
$pageSize
|
||||
);
|
||||
}
|
||||
|
||||
private function getCachedResults(string $cacheKey): ?array
|
||||
{
|
||||
if ($this->cache instanceof \Redis) {
|
||||
$cachedData = $this->cache->get($cacheKey);
|
||||
|
||||
return $cachedData ? json_decode($cachedData, true) : null;
|
||||
} elseif (is_array($this->cache)) {
|
||||
return $this->cache[$cacheKey] ?? null;
|
||||
$this->cacheResults($cacheKey, $results);
|
||||
$this->sendResponse(
|
||||
[
|
||||
'results' => $results['data'],
|
||||
'total' => $results['total'],
|
||||
'page' => $page,
|
||||
'pageSize' => $pageSize,
|
||||
],
|
||||
200
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
error_log('Search API Error: '.$e->getMessage());
|
||||
$this->sendErrorResponse('Invalid request. Please check your query and try again.', 400);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function cacheResults(string $cacheKey, array $results): void
|
||||
{
|
||||
if ($this->cache instanceof \Redis) {
|
||||
$this->cache->set($cacheKey, json_encode($results));
|
||||
$this->cache->expire($cacheKey, $this->cacheTTL);
|
||||
} elseif (is_array($this->cache)) {
|
||||
$this->cache[$cacheKey] = $results;
|
||||
private function validateAndSanitizeQuery(?string $query): string
|
||||
{
|
||||
if (empty($query) || ! is_string($query)) {
|
||||
throw new \Exception("Invalid 'q' parameter. Must be a non-empty string.");
|
||||
}
|
||||
|
||||
$query = trim($query);
|
||||
|
||||
if (strlen($query) > 255) {
|
||||
throw new \Exception("Invalid 'q' parameter. Exceeds maximum length of 255 characters.");
|
||||
}
|
||||
if (! preg_match('/^[a-zA-Z0-9\s\-_\'"]+$/', $query)) {
|
||||
throw new \Exception("Invalid 'q' parameter. Contains unsupported characters.");
|
||||
}
|
||||
|
||||
$query = preg_replace("/\s+/", ' ', $query);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
private function validateAndSanitizeSections(string $rawSections): ?array
|
||||
{
|
||||
$allowedSections = ['post', 'artist', 'genre', 'book', 'movie', 'show'];
|
||||
|
||||
if (empty($rawSections)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$sections = array_map(
|
||||
fn ($section) => strtolower(
|
||||
trim(htmlspecialchars($section, ENT_QUOTES, 'UTF-8'))
|
||||
),
|
||||
explode(',', $rawSections)
|
||||
);
|
||||
$invalidSections = array_diff($sections, $allowedSections);
|
||||
|
||||
if (! empty($invalidSections)) {
|
||||
throw new Exception("Invalid 'section' parameter. Unsupported sections: ".implode(', ', $invalidSections));
|
||||
}
|
||||
|
||||
return $sections;
|
||||
}
|
||||
|
||||
private function fetchSearchResults(
|
||||
string $query,
|
||||
?array $sections,
|
||||
int $pageSize,
|
||||
int $offset
|
||||
): array {
|
||||
$sectionsParam = $sections && count($sections) > 0 ? '%7B'.implode(',', $sections).'%7D' : '';
|
||||
$endpoint = 'rpc/search_optimized_index';
|
||||
$queryString =
|
||||
'search_query='.
|
||||
urlencode($query).
|
||||
"&page_size={$pageSize}&page_offset={$offset}".
|
||||
($sectionsParam ? "§ions={$sectionsParam}" : '');
|
||||
$data = $this->makeRequest('GET', "{$endpoint}?{$queryString}");
|
||||
$total = count($data) > 0 ? $data[0]['total_count'] : 0;
|
||||
$results = array_map(function ($item) {
|
||||
unset($item['total_count']);
|
||||
|
||||
if (! empty($item['description'])) {
|
||||
$item['description'] = truncateText(strip_tags(parseMarkdown($item['description'])), 225);
|
||||
}
|
||||
|
||||
return $item;
|
||||
|
||||
}, $data);
|
||||
|
||||
return ['data' => $results, 'total' => $total];
|
||||
}
|
||||
|
||||
private function generateCacheKey(
|
||||
string $query,
|
||||
?array $sections,
|
||||
int $page,
|
||||
int $pageSize
|
||||
): string {
|
||||
$sectionsKey = $sections ? implode(',', $sections) : 'all';
|
||||
|
||||
return sprintf(
|
||||
'search:%s:sections:%s:page:%d:pageSize:%d',
|
||||
md5($query),
|
||||
$sectionsKey,
|
||||
$page,
|
||||
$pageSize
|
||||
);
|
||||
}
|
||||
|
||||
private function getCachedResults(string $cacheKey): ?array
|
||||
{
|
||||
if ($this->cache instanceof \Redis) {
|
||||
$cachedData = $this->cache->get($cacheKey);
|
||||
|
||||
return $cachedData ? json_decode($cachedData, true) : null;
|
||||
} elseif (is_array($this->cache)) {
|
||||
return $this->cache[$cacheKey] ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function cacheResults(string $cacheKey, array $results): void
|
||||
{
|
||||
if ($this->cache instanceof \Redis) {
|
||||
$this->cache->set($cacheKey, json_encode($results));
|
||||
$this->cache->expire($cacheKey, $this->cacheTTL);
|
||||
} elseif (is_array($this->cache)) {
|
||||
$this->cache[$cacheKey] = $results;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$handler = new SearchHandler();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue