Use legit engines

This commit is contained in:
cedric 2025-12-11 21:21:56 +00:00
parent 65f977918f
commit dbd255da96

128
index.php
View file

@ -4,18 +4,21 @@ declare(strict_types=1);
// -------------------- CONSTANTES -------------------- // -------------------- CONSTANTES --------------------
const CACHE_DIR = '/var/cache/homepage'; const CACHE_DIR = '/var/cache/homepage';
const INSTANCES_JSON = CACHE_DIR . '/instances.json'; const INSTANCES_JSON = CACHE_DIR . '/instances.json';
const URLS_TXT = CACHE_DIR . '/urls.txt'; const URLS_TXT = __DIR__ . '/urls.txt'; // ← Hors du cache, à la racine
const INSTANCES_URL = 'https://searx.space/data/instances.json'; const INSTANCES_URL = 'https://searx.space/data/instances.json';
const CACHE_MAX_AGE = 3600; // 1 heure const CACHE_MAX_AGE = 3600; // 1 heure
const BANG_FILE = __DIR__ . '/bang.json'; const BANG_FILE = __DIR__ . '/bang.json';
const USE_SEARX_INSTANCES = true; // false → utilise engines.txt
// -------------------- HEADERS DE SÉCURITÉ -------------------- // -------------------- HEADERS DE SÉCURITÉ --------------------
header('X-Frame-Options: SAMEORIGIN'); header('X-Frame-Options: SAMEORIGIN');
header('X-Content-Type-Options: nosniff'); header('X-Content-Type-Options: nosniff');
header('Referrer-Policy: no-referrer-when-downgrade'); header('Referrer-Policy: no-referrer-when-downgrade');
header("Content-Security-Policy: default-src 'none'; frame-ancestors 'none'; sandbox"); header("Content-Security-Policy: default-src 'none'; frame-ancestors 'none'; sandbox");
header('X-Search-Mode: ' . (USE_SEARX_INSTANCES ? 'searx' : 'engines')); // ← Point 6
// -------------------- CLASSES -------------------- // -------------------- CLASSES --------------------
class CacheManager class CacheManager
{ {
private array $urlsCache = []; private array $urlsCache = [];
@ -109,22 +112,58 @@ class BangManager
} }
} }
class RequestHandler class EngineManager
{
private static ?array $cachedEngines = null;
private array $engines = [];
public function __construct(private string $file = __DIR__ . '/engines.txt')
{
if (self::$cachedEngines === null) {
$this->loadEngines();
self::$cachedEngines = $this->engines;
} else {
$this->engines = self::$cachedEngines;
}
}
private function loadEngines(): void
{
if (!file_exists($this->file)) {
throw new RuntimeException("Fichier engines.txt introuvable");
}
$lines = file($this->file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$this->engines = array_filter($lines, fn($line) => !empty(trim($line)));
}
public function getRandomEngine(): string
{
if (empty($this->engines)) {
throw new RuntimeException("Aucun moteur de recherche configuré dans engines.txt");
}
return $this->engines[array_rand($this->engines)];
}
}
class SearxHandler
{ {
public function __construct(private CacheManager $cache, private BangManager $bang) {} public function __construct(private CacheManager $cache, private BangManager $bang) {}
public function handle(): void { public function handle(): void
{
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET'; $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$query = $_REQUEST['q'] ?? null; $query = $_REQUEST['q'] ?? null;
if ($query !== null && !$this->bang->tryRedirect($query)) { if ($query !== null && !$this->bang->tryRedirect($query)) {
$instance = rtrim($this->cache->getRandomUrl(), '/'); $instance = rtrim($this->cache->getRandomUrl(), '/');
$url = $instance . '/search?' . http_build_query(['q' => $query]);
if ($method === 'GET') { if ($method === 'GET') {
$this->redirectGet($instance, $query); header("Location: $url");
exit;
} elseif ($method === 'POST') { } elseif ($method === 'POST') {
$this->redirectGet($instance, $query); header("Location: $url"); // Redirige en GET pour simplifier
// $this->proxyPost($instance, $_POST); exit;
} else { } else {
http_response_code(405); http_response_code(405);
exit('Méthode non autorisée'); exit('Méthode non autorisée');
@ -135,57 +174,80 @@ class RequestHandler
header("Location: $instance"); header("Location: $instance");
exit; exit;
} elseif ($method === 'POST') { } elseif ($method === 'POST') {
$this->proxyPost($instance, $_POST); header("Location: $instance");
exit;
} else { } else {
http_response_code(405); http_response_code(405);
exit('Méthode non autorisée'); exit('Méthode non autorisée');
} }
} }
} }
}
private function redirectGet(string $instance, string $query): void { class EngineHandler
$url = $instance . '/search?' . http_build_query(['q' => $query]); {
public function __construct(private EngineManager $engineManager, private BangManager $bang) {}
public function handle(): void
{
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$query = $_REQUEST['q'] ?? null;
if ($query !== null && !$this->bang->tryRedirect($query)) {
$engineTemplate = $this->engineManager->getRandomEngine();
$url = sprintf($engineTemplate, rawurlencode($query));
if ($method === 'GET') {
header("Location: $url"); header("Location: $url");
exit; exit;
} } elseif ($method === 'POST') {
header("Location: $url"); // Redirige en GET
private function proxyPost(string $urlBase, array $postData): void {
$url = $urlBase . '/search';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($postData),
CURLOPT_HEADER => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => true,
]);
$response = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
http_response_code($code);
echo $response;
exit; exit;
} else {
http_response_code(405);
exit('Méthode non autorisée');
}
} elseif ($query === null) {
// Rediriger vers la page d'accueil du premier moteur
$engineTemplate = $this->engineManager->getRandomEngine();
$homepage = str_replace('?query=%s', '', str_replace('?q=%s', '', $engineTemplate));
if ($method === 'GET') {
header("Location: $homepage");
exit;
} elseif ($method === 'POST') {
header("Location: $homepage");
exit;
} else {
http_response_code(405);
exit('Méthode non autorisée');
}
}
} }
} }
// -------------------- EXECUTION -------------------- // -------------------- EXECUTION --------------------
try { try {
$bang = new BangManager();
$engineManager = new EngineManager();
if (USE_SEARX_INSTANCES) {
$cache = new CacheManager(); $cache = new CacheManager();
if ($cache->isExpired()) { if ($cache->isExpired()) {
if (!$cache->downloadInstances() || !$cache->extractValidUrls()) { if (!$cache->downloadInstances() || !$cache->extractValidUrls()) {
http_response_code(500); http_response_code(500);
exit('Erreur interne : impossible de générer le cache.'); exit('Erreur interne : veuillez réessayer plus tard.');
} }
} }
$handler = new SearxHandler($cache, $bang);
} else {
$handler = new EngineHandler($engineManager, $bang);
}
$bang = new BangManager();
$handler = new RequestHandler($cache, $bang);
$handler->handle(); $handler->handle();
} catch (\Throwable $e) { } catch (\Throwable $e) {
// Ne pas exposer les détails techniques → Point 3
error_log('Erreur interne : ' . $e->getMessage() . ' | Trace: ' . $e->getTraceAsString());
http_response_code(500); http_response_code(500);
exit('Erreur interne : ' . $e->getMessage()); exit('Erreur interne : veuillez réessayer plus tard.');
} }