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
+135
View File
@@ -0,0 +1,135 @@
<?php
declare(strict_types=1);
function vd($var, ...$moreVars)
{
ob_start();
var_dump($var, ...$moreVars);
$output = ob_get_clean();
echo "<pre>$output</pre>";
}
function slugify(string $s): string
{
$map = ['à' => 'a','â' => 'a','ä' => 'a','é' => 'e','è' => 'e','ê' => 'e','ë' => 'e','î' => 'i','ï' => 'i','ô' => 'o','ö' => 'o','ù' => 'u','û' => 'u','ü' => 'u','ç' => 'c','æ' => 'ae','œ' => 'oe'];
$s = mb_strtolower($s);
$s = strtr($s, $map);
$s = (string)preg_replace('/[^a-z0-9]+/', '-', $s);
return trim($s, '-');
}
/**
* Diff ligne-à-ligne via LCS. Retourne un tableau de [op, line] où
* op est '=' (inchangé), '-' (supprimé), '+' (ajouté).
*/
function lineDiff(string $old, string $new): array
{
$a = explode("\n", $old);
$b = explode("\n", $new);
$n = count($a);
$m = count($b);
if ($n * $m > 300000) {
return [['!', "Diff trop grand ({$n}×{$m} lignes), affichage brut."], ['-', $old], ['+', $new]];
}
$dp = array_fill(0, $n + 1, array_fill(0, $m + 1, 0));
for ($i = $n - 1; $i >= 0; $i--) {
for ($j = $m - 1; $j >= 0; $j--) {
$dp[$i][$j] = $a[$i] === $b[$j]
? 1 + $dp[$i + 1][$j + 1]
: max($dp[$i + 1][$j], $dp[$i][$j + 1]);
}
}
$diff = [];
$i = 0;
$j = 0;
while ($i < $n || $j < $m) {
if ($i < $n && $j < $m && $a[$i] === $b[$j]) {
$diff[] = ['=', $a[$i]];
$i++;
$j++;
} elseif ($j < $m && ($i >= $n || $dp[$i][$j + 1] >= $dp[$i + 1][$j])) {
$diff[] = ['+', $b[$j++]];
} else {
$diff[] = ['-', $a[$i++]];
}
}
return $diff;
}
// 16 couleurs RGB de base — distribuées sur le spectre, visuellement distinctes
const COLOR_PALETTE_16 = [
[220, 38, 38], // rouge
[234, 88, 12], // orange
[217, 119, 6], // ambre
[161, 142, 14], // jaune-olive
[77, 124, 15], // citron
[22, 163, 74], // vert
[4, 120, 87], // émeraude
[15, 118, 110], // sarcelle
[8, 145, 178], // cyan
[3, 105, 161], // ciel
[37, 99, 235], // bleu
[79, 70, 229], // indigo
[109, 40, 217], // violet
[147, 51, 234], // pourpre
[192, 38, 211], // fuchsia
[219, 39, 119], // rose
];
/**
* Génère un dégradé CSS pour une catégorie.
* Avec $allCats, l'assignation est séquentielle (par ordre alpha) ;
* au-delà de 16, un décalage de teinte et d'angle différencie les palettes.
* Sans $allCats, fallback par hachage sur la palette.
*/
function coverGradient(string $seed, array $allCats = []): string
{
$key = strtolower(trim($seed));
if (!empty($allCats)) {
$keys = array_map(fn ($k) => strtolower(trim((string)$k)), array_keys($allCats));
$pos = array_search($key, $keys, true);
if ($pos !== false) {
$idx = (int) $pos;
$tier = (int) floor($idx / 16);
$ci = $idx % 16;
return _paletteGradient(COLOR_PALETTE_16[$ci], $tier);
}
}
// Hachage déterministe en l'absence de liste
$ci = abs(crc32($key)) % 16;
return _paletteGradient(COLOR_PALETTE_16[$ci], 0);
}
function _paletteGradient(array $rgb, int $tier): string
{
[$r, $g, $b] = $rgb;
// Tier 0 : dégradé standard clair → foncé, 135°
// Tier 1 : plus saturé, angle inversé, 315°
// Tier 2+ : plus sombre encore, 225°
$tintMix = match ($tier) {
0 => 0.65, 1 => 0.48, default => 0.35
};
$shadeK = match ($tier) {
0 => 0.35, 1 => 0.25, default => 0.18
};
$angle = match ($tier) {
0 => 135, 1 => 315, default => 225
};
$tr = (int) round($r * (1 - $tintMix) + 255 * $tintMix);
$tg = (int) round($g * (1 - $tintMix) + 255 * $tintMix);
$tb = (int) round($b * (1 - $tintMix) + 255 * $tintMix);
$sr = (int) round($r * $shadeK);
$sg = (int) round($g * $shadeK);
$sb = (int) round($b * $shadeK);
return "linear-gradient({$angle}deg,rgb($tr,$tg,$tb) 0%,rgb($sr,$sg,$sb) 100%)";
}