Advertisement
NokitaKaze

Nokita Markdown Parser

Oct 27th, 2015
253
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 9.70 KB | None | 0 0
  1. <?php
  2. /**
  3.  * Версия от 28 мая 2015
  4.  */
  5.     class MarkdownParser {
  6.         static $code_blocks = array();
  7.         static $quote_blocks = array();
  8.         static $images = array();
  9.         static $links = array();
  10.         static $videos = array();
  11.  
  12.         /**
  13.          * @param string $text
  14.          *
  15.          * @return string
  16.          */
  17.         static function markdown_to_html($text) {
  18.             self::$code_blocks = array();
  19.             self::$quote_blocks = array();
  20.             self::$images = array();
  21.             self::$links = array();
  22.             self::$videos = array();
  23.  
  24.             $text = str_replace("\r", '', $text);
  25.  
  26.             // Code blocks
  27.             $text = preg_replace_callback("|\\n```\\n(.+?)\\n```\\n|s", function ($a) {
  28.                 $text = preg_replace('|^\\s*\\n(.+?)\\n$|', '$1', $a[1]);
  29.                 $hash = AscetCMSEngine::generate_hash(30);
  30.                 self::$code_blocks[$hash] = $text;
  31.  
  32.                 return "\n".'{#code_block:'.$hash.'#}'."\n";
  33.             }, $text);
  34.  
  35.             // Quote blocks
  36.             $c = 1;
  37.             $text = "\n".$text."\n";
  38.             while ($c > 0) {
  39.                 $text = preg_replace_callback("|\\n>[ \\t]*([^\\n]*?)\\n|s", function ($a) {
  40.                     $hash = AscetCMSEngine::generate_hash(30);
  41.                     self::$quote_blocks[$hash] = $a[1];
  42.  
  43.                     return "\n".'{#quote_block:'.$hash.'#}'."\n";
  44.                 }, $text, 1, $c);
  45.             }
  46.  
  47.             // Собираем Quote blocks
  48.             $c = 1;
  49.             while ($c > 0) {
  50.                 $text = preg_replace_callback("|\\n{#quote_block:(.+?)#}\\n{#quote_block:(.+?)#}\\n|s", function ($a) {
  51.                     self::$quote_blocks[$a[1]] =
  52.                         self::null_to_nbsp(self::$quote_blocks[$a[1]])."\n".
  53.                         self::null_to_nbsp(self::$quote_blocks[$a[2]]);
  54.                     unset(self::$quote_blocks[$a[2]]);
  55.  
  56.                     return "\n".'{#quote_block:'.$a[1].'#}'."\n";
  57.                 }, $text, 1, $c);
  58.             }
  59.  
  60.             // Парсим
  61.             $text = self::parse_plain_text($text);
  62.             foreach (self::$quote_blocks as $key => &$value) {
  63.                 $value = self::parse_plain_text($value);
  64.             }
  65.  
  66.             // Вставляем обратно quote blocks
  67.             $c = 1;
  68.             while ($c > 0) {
  69.                 $text = preg_replace_callback('`{#(quote_block):([a-z0-9]+)#}`i', function ($a) {
  70.                     $r = '<blockquote class="quote">'.self::$quote_blocks[$a[2]]."</blockquote>\n";
  71.                     unset(self::$quote_blocks[$a[2]]);
  72.  
  73.                     return $r;
  74.                 }, $text, -1, $c);
  75.             }
  76.  
  77.             // @todo Вставляем обратно code blocks
  78.             $c = 1;
  79.             while ($c > 0) {
  80.                 $text = preg_replace_callback('`{#(code_block):([a-z0-9]+)#}`i', function ($a) {
  81.                     $r = '<blockquote class="code">'.self::$code_blocks[$a[2]]."</blockquote>\n";
  82.                     unset(self::$code_blocks[$a[2]]);
  83.  
  84.                     return $r;
  85.                 }, $text, -1, $c);
  86.             }
  87.  
  88.             return $text;
  89.         }
  90.  
  91.         /**
  92.          * @param string $text
  93.          *
  94.          * @return string
  95.          */
  96.         static function parse_plain_text($text) {
  97.             // @todo markdown photo
  98.  
  99.             // Фото
  100.             $c = 1;
  101.             while ($c > 0) {
  102.                 $text = preg_replace_callback("`(\\W)(https?://[a-z0-9.-]+/[a-z0-9%:./_+-]+".
  103.                                               "\\.(jpe?g|bmp|gif|png)(\\?.*)?)(\\W)`si", function ($a) {
  104.                     $hash = AscetCMSEngine::generate_hash(30);
  105.                     self::$images[$hash] = array($a[2], $a[2]);
  106.  
  107.                     return $a[1].'{#image:'.$hash.'#}'.$a[5];
  108.                 }, $text, -1, $c);
  109.             }
  110.  
  111.             // video
  112.             $c = 1;
  113.             while ($c > 0) {
  114.                 $text = preg_replace_callback("`(\\W)(https?://[a-z0-9.-]+/[a-z0-9%:./_+-]+".
  115.                                               "\\.(webm|mp4)(\\?.*)?)(\\W)`si", function ($a) {
  116.                     $hash = AscetCMSEngine::generate_hash(30);
  117.                     self::$videos[$hash] = $a[2];
  118.  
  119.                     return $a[1].'{#video:'.$hash.'#}'.$a[5];
  120.                 }, $text, -1, $c);
  121.             }
  122.  
  123.             // markdown links
  124.             $c = 1;
  125.             while ($c > 0) {
  126.                 $text = preg_replace_callback("`\\[([\\w\\s]+)\\]\\((https?://[a-z0-9.-]+/[a-z0-9%:./_+-]*".
  127.                                               "(\\?.*)?(#.*)?)(\\s*\"(.+)\")?\\)`i",
  128.                     function ($a) {
  129.                         $hash = AscetCMSEngine::generate_hash(30);
  130.                         self::$links[$hash] = array($a[2], $a[1], isset($a[6]) ? $a[6] : '');
  131.  
  132.                         return '{#link:'.$hash.'#}';
  133.                     }, $text, -1, $c);
  134.             }
  135.  
  136.             // links
  137.             $c = 1;
  138.             while ($c > 0) {
  139.                 $text = preg_replace_callback("`(\\W)(https?://[a-z0-9.-]+/[a-z0-9%:./_+-]*(\\?.*)?)(\\W)`si", function ($a) {
  140.                     $hash = AscetCMSEngine::generate_hash(30);
  141.                     self::$links[$hash] = array($a[2], self::get_short_link($a[2]), '');
  142.  
  143.                     return $a[1].'{#link:'.$hash.'#}'.$a[4];
  144.                 }, $text, -1, $c);
  145.             }
  146.  
  147.             //
  148.             $text = sad_safe_html($text);
  149.  
  150.             // Жирное выделение
  151.             $c = 1;
  152.             while ($c > 0) {
  153.                 $text = preg_replace_callback('`\\*\\*(.+?)\\*\\*`s', function ($a) {
  154.                     return '<strong>'.$a[1].'</strong>';
  155.                 }, $text, -1, $c);
  156.             }
  157.  
  158.             // Em выделение
  159.             $c = 1;
  160.             while ($c > 0) {
  161.                 $text = preg_replace_callback('`\\*(.+?)\\*`s', function ($a) {
  162.                     return '<em>'.$a[1].'</em>';
  163.                 }, $text, -1, $c);
  164.             }
  165.  
  166.             // Em выделение
  167.             /*
  168.             $c = 1;
  169.             while ($c > 0) {
  170.                 $text = preg_replace_callback('`_(.+?)_`s', function ($a) {
  171.                     return '<em>'.$a[1].'</em>';
  172.                 }, $text, -1, $c);
  173.             }
  174.             */
  175.  
  176.             //
  177.             if (mb_substr($text, 0, 1) == "\n") {
  178.                 $text = mb_substr($text, 1);
  179.             }
  180.             if (mb_substr($text, mb_strlen($text) - 1, 1) == "\n") {
  181.                 $text = mb_substr($text, 0, mb_strlen($text) - 1);
  182.             }
  183.             $text = str_replace("\n", "</p>\n<p>", $text);
  184.             $text = str_replace("<p> </p>", "<p>&nbsp;</p>", $text);
  185.             $text = '<p>'.$text.'</p>';
  186.  
  187.             // Переносим всё обратно
  188.             $c = 1;
  189.             while ($c > 0) {
  190.                 $text = preg_replace_callback('`{#(image|link|video):([a-z0-9]+)#}`i', function ($a) {
  191.                     if ($a[1] == 'image') {
  192.                         return self::get_image($a[2]);
  193.                     } elseif ($a[1] == 'video') {
  194.                         return self::get_video($a[2]);
  195.                     } elseif ($a[1] == 'link') {
  196.                         return self::get_link($a[2]);
  197.                     } else {
  198.                         return $a[0];
  199.                     }
  200.                 }, $text, -1, $c);
  201.             }
  202.  
  203.             return $text;
  204.         }
  205.  
  206.         /**
  207.          * @param string $hash
  208.          *
  209.          * @return string
  210.          */
  211.         static function get_image($hash) {
  212.             $url = '/goto.php?url='.urlencode(self::$images[$hash][0]);
  213.  
  214.             return '<a href="'.sad_safe_html($url).'" title="'.sad_safe_html(self::$images[$hash][1]).
  215.                    '" target="_blank" rel="nofollow" data-fancybox-group="post" class="gallery">'.
  216.                    '<img src="'.sad_safe_html(self::$images[$hash][0]).'" alt="'.sad_safe_html(self::$images[$hash][1]).'">'.
  217.                    '</a>';
  218.         }
  219.  
  220.         /**
  221.          * @param string $hash
  222.          *
  223.          * @return string
  224.          */
  225.         static function get_video($hash) {
  226.             return '<video style="display: block; max-width: 95%;" controls="controls">'.
  227.                    '<source src="'.sad_safe_html(self::$videos[$hash]).'">'.
  228.                    '</video>';
  229.         }
  230.  
  231.         /**
  232.          * @param string $hash
  233.          *
  234.          * @return string
  235.          */
  236.         static function get_link($hash) {
  237.             $url = '/goto.php?url='.urlencode(self::$links[$hash][0]);
  238.             $snippet = self::$links[$hash][1];
  239.             $title = (self::$links[$hash][2] != '')
  240.                 ? 'title="'.sad_safe_html(self::$links[$hash][2]).'"'
  241.                 : '';
  242.  
  243.             return '<a href="'.sad_safe_html($url).'" '.$title.' target="_blank" rel="nofollow">'.
  244.                    sad_safe_html($snippet).'</a>';
  245.         }
  246.  
  247.         static function get_short_link($url) {
  248.             $a = parse_url($url);
  249.             $s = $a['path'].
  250.                  (isset($a['query']) ? '?'.$a['query'] : '').
  251.                  (isset($a['fragment']) ? '#'.$a['fragment'] : '');
  252.             if (strlen($s) > 18) {
  253.                 $cut = preg_replace('|^(.{5,5})(.+?)(.{6,10})$|', '$1...$3', $s);
  254.             } else {
  255.                 $cut = $s;
  256.             }
  257.  
  258.             return $a['scheme'].'://'.$a['host'].(isset($a['port']) ? ':'.$a['port'] : '').$cut;
  259.         }
  260.  
  261.         static function null_to_nbsp($s) {
  262.             if (($s === null) || ($s === '')) {
  263.                 return ' ';
  264.             } else {
  265.                 return $s;
  266.             }
  267.         }
  268.  
  269.     }
  270.  
  271. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement