' . $code . '' . "\n";
$i++;
}
// Heading
elseif (preg_match('/^(#{1,6})\s+(.+)$/', $line, $m)) {
$lvl = strlen($m[1]);
$text = md_inline(h($m[2]));
$html .= "' . markdown_to_html($bq) . '' . "\n"; } // Unordered list elseif (preg_match('/^[-*+]\s+(.+)$/', $line, $m)) { $html .= "
' . md_inline(h($para)) . "
\n"; } } // Absolute safety net: if $i did not advance in any branch above, // force it forward. This prevents infinite loops on any input. if ($i === $prev_i) { $i++; } } return $html; } // Inline markdown: bold, italic, code, links function md_inline(string $s): string { // Inline code (already HTML-escaped input, so backtick safe) $s = preg_replace('/`([^`]+)`/', '$1', $s);
// Bold+italic
$s = preg_replace('/\*\*\*(.+?)\*\*\*/', '$1', $s);
// Bold
$s = preg_replace('/\*\*(.+?)\*\*/', '$1', $s);
// Italic
$s = preg_replace('/\*(.+?)\*/', '$1', $s);
// Links: must whitelist to http/https/ftp/mailto
$s = preg_replace_callback(
'/\[([^\]]+)\]\(((?:https?|ftp|mailto):[^\)]+)\)/',
fn($m) => '' . $m[1] . '',
$s
);
return $s;
}