html(rtrim($str), true); } public static function rewrap($str, $l = 72) { $o = new self; return $o->wrap($str, $l); } public static function getSubject($str) { while (preg_match('/^re: /msiu', $str)) { $str = preg_replace('/^re: /msiu', '', $str); } return $str; } public function html($str, $with_signature = false) { $res = ''; $signature = ''; if ($with_signature && preg_match('/^(-- \r?\n.+?)\Z/msu', $str, $m)) { $m[1] = preg_replace('/^-- \r?\n/msu', '', $m[1]); $signature = '
' . $this->htmlParseBlock($m[1]) . '
'; $str = preg_replace('/^-- \r?\n(.+?)\Z/msu', '', $str); $str = rtrim($str); } foreach ($this->getTockens($str) as $t) { switch ($t['type']) { case 'block': $t['content'] = $this->htmlParseBlock($t['content']); $res .= '
' . $t['content'] . "
\n"; break; case 'quote': $res .= "
\n" . $this->html($t['content']) . "
\n\n"; break; } } return $res . $signature; } public function wrap($str, $l = 72) { $str = $this->prepareString($str); $res = ''; foreach (explode("\n", $str) as $line) { $sep = "\n"; if (preg_match('/^([>\|]+\s*)/su', $line, $m)) { $sep .= $m[1]; } $line = wordwrap($line, $l, $sep, false) . "\n"; $res .= $line; } return $res; } protected function prepareString($str) { return preg_replace('/\r?\n/msu', "\n", $str); } protected function getTockens($str) { $str = $this->prepareString($str); $tockens = []; $type = null; $id = -1; foreach (explode("\n", $str) as $line) { if (preg_match('/^(?:\s*)(?:>|\|)(?:\s?)(.*?)$/su', $line, $m)) { if ($type != 'quote' && !trim($m[1])) { continue; } if ($type == 'quote') { $tockens[$id]['content'] .= $m[1] . "\n"; } else { $id++; $type = 'quote'; $tockens[$id]['type'] = $type; $tockens[$id]['content'] = $m[1] . "\n"; } } # Empty line elseif (preg_match('/^\s*$/su', $line)) { if ($type == 'block') { $tockens[$id]['content'] .= "\n"; } } # Defaults to block else { if ($type == 'block') { $tockens[$id]['content'] .= $line . "\n"; } else { $id++; $type = 'block'; $tockens[$id]['type'] = $type; $tockens[$id]['content'] = $line . "\n"; } } } foreach ($tockens as $i => $t) { $tockens[$i]['content'] = preg_replace('/\n$/su', '', $t['content']); } return $tockens; } protected function htmlParseBlock($str) { $str = html::escapeHTML($str); # Transform links $str = preg_replace_callback($this->url_pattern, [$this, 'htmlUrlHandler'], $str); # Transform * / _ strings (does not work, may transform links href) #$str = preg_replace_callback('%([\*_/])([\w\s]+?)([\*_/])%msu',[$this,'htmlFormatHandler'],$str); return $str; } protected function htmlUrlHandler($m) { $url = $m[1] . ':' . html::decodeEntities($m[2] . $m[3]); $content = $url; $title = ''; if (strlen($url) > 42) { $content = substr($url, 0, 42) . '...'; $title = ' title="' . html::escapeHTML($url) . '"'; } return '' . html::escapeHTML($content) . '' . $m[4]; } protected function htmlFormatHandler($m) { switch ($m[1]) { case '*': return '' . $m[2] . ''; case '/': return '' . $m[2] . ''; case '_': return '' . $m[2] . ''; } } }