chore(*.php): use pint for php formatting

This commit is contained in:
Cory Dransfeldt 2025-06-14 16:55:03 -07:00
parent bd1855a65e
commit 753f3433ce
No known key found for this signature in database
40 changed files with 2261 additions and 1900 deletions

View file

@ -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 ? "&sections={$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 ? "&sections={$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();