. class Markdown { public $blockCodeRegex = '/```([\s\S]+?)```/S'; protected $paragraphRegex = '/(?:\r\n|\r|\n){2}/S'; public $inlineCodeRegex = '/(^|[^a-z0-9`])`([^`]+?[\s\S]+?)`([^a-z0-9`]|$)/iS'; // Array for inline code and code block markers protected $codeMarkers = array ( 'block' => array ('marks' => array (), 'count' => 0), 'inline' => array ('marks' => array (), 'count' => 0) ); // Markdown patterns to search for public $search = array ( '/\*\*([^ *])([\s\S]+?)([^ *])\*\*/S', '/\*([^ *])([\s\S]+?)([^ *])\*/S', '/(^|\W)_([^_]+?[\s\S]+?)_(\W|$)/S', '/__([^ _])([\s\S]+?)([^ _])__/S', '/~~([^ ~])([\s\S]+?)([^ ~])~~/S' ); // HTML replacements for markdown patterns public $replace = array ( '\\1\\2\\3', '\\1\\2\\3', '\\1\\2\\3', '\\1\\2\\3', '\\1\\2\\3' ); // Replaces markdown for inline code with a marker protected function codeReplace ($grp, $display) { $markName = 'CODE_' . strtoupper ($display); $markCount = $this->codeMarkers[$display]['count']++; if ($display !== 'block') { $codeMarker = $grp[1] . $markName . '[' . $markCount . ']' . $grp[3]; $this->codeMarkers[$display]['marks'][$markCount] = trim ($grp[2], "\r\n"); } else { $codeMarker = $markName . '[' . $markCount . ']'; $this->codeMarkers[$display]['marks'][$markCount] = trim ($grp[1], "\r\n"); } return $codeMarker; } // Replaces markdown for code block with a marker protected function blockCodeReplace ($grp) { return $this->codeReplace ($grp, 'block'); } // Replaces markdown for inline code with a marker protected function inlineCodeReplace ($grp) { return $this->codeReplace ($grp, 'inline'); } // Returns the original inline markdown code with HTML replacement protected function inlineCodeReturn ($grp) { return '' . $this->codeMarkers['inline']['marks'][($grp[1])] . ''; } // Returns the original markdown code block with HTML replacement protected function blockCodeReturn ($grp) { return '' . $this->codeMarkers['block']['marks'][($grp[1])] . ''; } // Parses a string as markdown public function parseMarkdown ($string) { // Reset marker arrays $this->codeMarkers = array ( 'block' => array ('marks' => array (), 'count' => 0), 'inline' => array ('marks' => array (), 'count' => 0) ); // Replace code blocks with markers $string = preg_replace_callback ($this->blockCodeRegex, 'self::blockCodeReplace', $string); // Break string into paragraphs $paragraphs = preg_split ($this->paragraphRegex, $string); // Run through each paragraph for ($i = 0, $il = count ($paragraphs); $i < $il; $i++) { // Replace inline code with markers $paragraphs[$i] = preg_replace_callback ($this->inlineCodeRegex, 'self::inlineCodeReplace', $paragraphs[$i]); // Replace markdown patterns $paragraphs[$i] = preg_replace ($this->search, $this->replace, $paragraphs[$i]); // Replace markers with original markdown code $paragraphs[$i] = preg_replace_callback ('/CODE_INLINE\[([0-9]+)\]/S', 'self::inlineCodeReturn', $paragraphs[$i]); } // Join paragraphs $string = implode (PHP_EOL . PHP_EOL, $paragraphs); // Replace code block markers with original markdown code $string = preg_replace_callback ('/CODE_BLOCK\[([0-9]+)\]/S', 'self::blockCodeReturn', $string); return $string; } }