$title, 'excerpt' => self::plainLine($excerpt, self::EXCERPT_MAX), 'body' => self::toHtml($body)]; } /** Plain single line: tags removed, whitespace collapsed, bounded. */ public static function plainLine(string $text, int $max): string { $text = (string) preg_replace('/<[^>]*>?/u', '', $text); $text = trim((string) preg_replace('/\s+/u', ' ', $text)); return mb_substr($text, 0, $max); } public static function toHtml(string $text): string { $text = mb_substr(trim($text), 0, self::BODY_MAX); if ($text === '') { return ''; } $html = ''; $para = []; $list = []; $flush = static function () use (&$html, &$para, &$list): void { if ($para !== []) { $html .= '

' . implode(' ', $para) . "

\n"; $para = []; } if ($list !== []) { $html .= "\n"; $list = []; } }; foreach (explode("\n", $text) as $line) { $line = trim($line); if ($line === '') { $flush(); } elseif (preg_match('/^(#{1,3})\s+(.+)$/u', $line, $m)) { $flush(); $level = strlen($m[1]) <= 2 ? 2 : 3; $html .= "" . self::esc($m[2]) . "\n"; } elseif (preg_match('/^[-*]\s+(.+)$/u', $line, $m)) { if ($para !== []) { $flush(); } $list[] = self::esc($m[1]); } else { if ($list !== []) { $flush(); } $para[] = self::esc($line); } } $flush(); return rtrim($html); } private static function esc(string $s): string { return htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } }