fix #29 : envoyer le lien magique par email (envoyer_mail_smtp)

This commit is contained in:
Cedric Abonnel
2026-05-13 23:41:58 +02:00
commit 8a85c15372
129 changed files with 22818 additions and 0 deletions
+127
View File
@@ -0,0 +1,127 @@
<?php
declare(strict_types=1);
class SearchLogParser
{
private string $logDir;
private string $vhostBase;
private string $cacheFile;
private int $cacheTtl;
public function __construct(
string $logDir = '/var/log/apache2',
string $vhostBase = 'lan.acegrp.varlog-access.log',
string $cacheFile = '',
int $cacheTtl = 600
) {
$this->logDir = rtrim($logDir, '/');
$this->vhostBase = $vhostBase;
$this->cacheFile = $cacheFile !== ''
? $cacheFile
: dirname(__DIR__) . '/_cache/search_terms.json';
$this->cacheTtl = $cacheTtl;
}
/** @return array<string,int> terme => nombre d'occurrences, trié desc */
public function topTerms(int $limit = 100): array
{
if ($this->cacheValid()) {
$data = json_decode((string) file_get_contents($this->cacheFile), true);
if (is_array($data)) {
return array_slice($data, 0, $limit, true);
}
}
$counts = [];
foreach ($this->logFiles() as $file) {
$this->parseFile($file, $counts);
}
arsort($counts);
@mkdir(dirname($this->cacheFile), 0755, true);
file_put_contents($this->cacheFile, json_encode($counts, JSON_UNESCAPED_UNICODE));
return array_slice($counts, 0, $limit, true);
}
public function isReadable(): bool
{
$f = $this->logDir . '/' . $this->vhostBase;
return file_exists($f) && is_readable($f);
}
private function cacheValid(): bool
{
return file_exists($this->cacheFile)
&& (time() - filemtime($this->cacheFile)) < $this->cacheTtl;
}
/** @return list<array{path:string,gz:bool}> */
private function logFiles(): array
{
$base = $this->logDir . '/' . $this->vhostBase;
$files = [];
if (file_exists($base) && is_readable($base)) {
$files[] = ['path' => $base, 'gz' => false];
}
for ($i = 1; $i <= 14; $i++) {
$plain = $base . '.' . $i;
$gz = $plain . '.gz';
if (file_exists($plain) && is_readable($plain)) {
$files[] = ['path' => $plain, 'gz' => false];
} elseif (file_exists($gz) && is_readable($gz)) {
$files[] = ['path' => $gz, 'gz' => true];
}
}
return $files;
}
private function parseFile(array $file, array &$counts): void
{
if ($file['gz']) {
$h = @gzopen($file['path'], 'rb');
if (!$h) {
return;
}
while (!gzeof($h)) {
$line = gzgets($h, 8192);
if ($line !== false) {
$this->parseLine($line, $counts);
}
}
gzclose($h);
} else {
$h = @fopen($file['path'], 'rb');
if (!$h) {
return;
}
while (($line = fgets($h)) !== false) {
$this->parseLine($line, $counts);
}
fclose($h);
}
}
private function parseLine(string $line, array &$counts): void
{
if (!str_contains($line, 'GET /search?')) {
return;
}
if (!preg_match('/"GET \/search\?([^"]*) HTTP\//', $line, $m)) {
return;
}
parse_str($m[1], $params);
$q = trim(urldecode($params['q'] ?? ''));
if ($q === '' || mb_strlen($q) > 200) {
return;
}
$q = mb_strtolower($q);
$counts[$q] = ($counts[$q] ?? 0) + 1;
}
}