feat : magic link confirm, notif auteur, rate-limit IP, duplicate, cache MD, lazy img (v1.6.18)
- magic.php : GET=confirmation page, POST=consommation (protège vs scanners) (#27) - verify_comment : email de notification à l'auteur de l'article (#44) - login/index.php : rate limit par IP (MAGIC_MAX_PER_IP_HOUR=10) (#23) - ArticleManager::duplicate() + route POST /duplicate/{uuid} + bouton ⧉ admin/articles (#7) - post_view.php : cache JSON du rendu Markdown (invalidé sur mtime index.md) (#17) - post_view.php : loading="lazy" sur toutes les <img> du contenu (#21) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+56
-27
@@ -9,33 +9,62 @@ $_accentMap = [
|
||||
];
|
||||
$_tocItems = [];
|
||||
$_tocSeen = [];
|
||||
// Le titre H1 est déjà affiché par le template ; on le retire du rendu.
|
||||
$_rawForRender = preg_replace('/^\s*# [^\n]*\n*/u', '', $rawContent);
|
||||
$_renderedContent = preg_replace_callback(
|
||||
'/<(h[23])>(.+?)<\/h[23]>/i',
|
||||
function ($m) use (&$_tocItems, &$_tocSeen, $_accentMap) {
|
||||
$tag = $m[1];
|
||||
$inner = $m[2];
|
||||
$level = (int) substr($tag, 1);
|
||||
$plain = strip_tags($inner);
|
||||
$slug = trim(preg_replace(
|
||||
'/[^a-z0-9]+/',
|
||||
'-',
|
||||
mb_strtolower(strtr($plain, $_accentMap), 'UTF-8')
|
||||
), '-') ?: 'section';
|
||||
if (isset($_tocSeen[$slug])) {
|
||||
$_tocSeen[$slug]++;
|
||||
$id = $slug . '-' . $_tocSeen[$slug];
|
||||
} else {
|
||||
$_tocSeen[$slug] = 0;
|
||||
$id = $slug;
|
||||
}
|
||||
$_tocItems[] = ['level' => $level, 'text' => $plain, 'id' => $id];
|
||||
return "<{$tag} id=\"" . htmlspecialchars($id) . "\">{$inner}</{$tag}>";
|
||||
},
|
||||
$Parsedown->text($_rawForRender)
|
||||
);
|
||||
$_renderedContent = typographieHtml($_renderedContent ?? '');
|
||||
|
||||
// Cache du rendu Markdown (invalidé si index.md est plus récent)
|
||||
$_mdFile = defined('DATA_PATH') ? DATA_PATH . '/' . ($article['uuid'] ?? '') . '/index.md' : '';
|
||||
$_cacheFile = defined('DATA_PATH') ? DATA_PATH . '/' . ($article['uuid'] ?? '') . '/_cache/content_rendered.json' : '';
|
||||
$_mdMtime = ($_mdFile !== '' && file_exists($_mdFile)) ? (int)filemtime($_mdFile) : 0;
|
||||
|
||||
$_renderedContent = null;
|
||||
if ($_cacheFile !== '' && file_exists($_cacheFile)) {
|
||||
$_tmp = json_decode((string)file_get_contents($_cacheFile), true);
|
||||
if (is_array($_tmp) && isset($_tmp['ts'], $_tmp['html'], $_tmp['toc'])
|
||||
&& (int)$_tmp['ts'] >= $_mdMtime && $_mdMtime > 0) {
|
||||
$_renderedContent = $_tmp['html'];
|
||||
$_tocItems = $_tmp['toc'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($_renderedContent === null) {
|
||||
// Le titre H1 est déjà affiché par le template ; on le retire du rendu.
|
||||
$_rawForRender = preg_replace('/^\s*# [^\n]*\n*/u', '', $rawContent);
|
||||
$_renderedContent = preg_replace_callback(
|
||||
'/<(h[23])>(.+?)<\/h[23]>/i',
|
||||
function ($m) use (&$_tocItems, &$_tocSeen, $_accentMap) {
|
||||
$tag = $m[1];
|
||||
$inner = $m[2];
|
||||
$level = (int) substr($tag, 1);
|
||||
$plain = strip_tags($inner);
|
||||
$slug = trim(preg_replace(
|
||||
'/[^a-z0-9]+/',
|
||||
'-',
|
||||
mb_strtolower(strtr($plain, $_accentMap), 'UTF-8')
|
||||
), '-') ?: 'section';
|
||||
if (isset($_tocSeen[$slug])) {
|
||||
$_tocSeen[$slug]++;
|
||||
$id = $slug . '-' . $_tocSeen[$slug];
|
||||
} else {
|
||||
$_tocSeen[$slug] = 0;
|
||||
$id = $slug;
|
||||
}
|
||||
$_tocItems[] = ['level' => $level, 'text' => $plain, 'id' => $id];
|
||||
return "<{$tag} id=\"" . htmlspecialchars($id) . "\">{$inner}</{$tag}>";
|
||||
},
|
||||
$Parsedown->text($_rawForRender)
|
||||
);
|
||||
$_renderedContent = typographieHtml($_renderedContent ?? '');
|
||||
// Lazy loading sur toutes les images du contenu
|
||||
$_renderedContent = preg_replace('/<img\b([^>]*)>/i', '<img$1 loading="lazy">', $_renderedContent ?? '') ?? $_renderedContent;
|
||||
|
||||
// Écriture du cache
|
||||
if ($_cacheFile !== '' && $_mdMtime > 0) {
|
||||
@mkdir(dirname($_cacheFile), 0755, true);
|
||||
@file_put_contents($_cacheFile, json_encode(
|
||||
['ts' => $_mdMtime, 'html' => $_renderedContent, 'toc' => $_tocItems],
|
||||
JSON_UNESCAPED_UNICODE
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user