fix #29 : envoyer le lien magique par email (envoyer_mail_smtp)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user