See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
1 <?php 2 3 /** 4 * Creole parser implementation 5 * 6 * @author Josep ArĂºs 7 * 8 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License 9 * @package mod_wiki 10 */ 11 12 include_once ("wikimarkup.php"); 13 14 class creole_parser extends wiki_markup_parser { 15 16 protected $blockrules = array( 17 'nowiki' => array( 18 'expression' => "/^\{\{\{(.*?)\}\}\}/ims", 19 'tags' => array(), 20 'token' => array('{{{', '}}}') 21 ), 22 'header' => array( 23 'expression' => "/^\ *(={1,6})\ *(.+?)=*\ *$/ims", 24 'tags' => array(), //none 25 'token' => '=' 26 ), 27 'table' => array( 28 'expression' => "/^(?:\|.*?\|\ *\n)+/ims" 29 ), 30 'line_break' => array( 31 'expression' => "/^----\s*$/im", 32 'token' => '----', 33 'tags' => array() 34 ), 35 'list' => array( 36 'expression' => "/((?:^\ *[\*#][^\*#]\ *.+?)(?:^\ *[\*#]{1,5}\ *.+?)*)(\n\s*(?:\n|<(?:h\d|pre|table|tbody|thead|tr|th|td|ul|li|ol|hr)))/ims", 37 'tags' => array(), 38 'token' => array('*', '#') 39 ), 40 'paragraph' => array( 41 'expression' => "/^\ *((?:<(?!\ *\/?(?:h\d|pre|table|tbody|thead|tr|th|td|ul|li|ol|hr)\ *\/?>)|[^<\s]).+?)\n\s*\n/ims", 42 //not specified -> all tags (null or unset) 43 'tag' => 'p' 44 ) 45 ); 46 47 protected $tagrules = array( 48 'nowiki' => array( 49 'expression' => "/\{\{\{(.*?)\}\}\}/is", 50 'token' => array('{{{', '}}}') 51 ), 52 'image' => array( 53 'expression' => "/\~?\{\{(.+)\|(.+)\}\}/i", 54 'tags' => array(), 55 'token' => array('{{', '|Alt}}') 56 ), 57 'link' => array( 58 'expression' => "/\~?\[\[(.+?)\]\]/is", 59 'tag' => 'a', 60 'token' => array('[[', ']]') 61 ), 62 'url' => array( 63 'expression' => "/\~?(?<!=\")((?:https?|ftp):\/\/[^\s\n]+[^,\.\?!:;\"\'\n\ ])/is", 64 'tag' => 'a', 65 'token' => "http://" 66 ), 67 'line_break' => array( 68 'expression' => "/\\\\\\\\/", 69 'tag' => 'br', 70 'simple' => true, 71 'token' => '----' 72 ), 73 'bold' => array( 74 'expression' => "/\*\*(.*?)(?:\*\*|$)/is", 75 'tag' => 'strong', 76 'token' => array('**', '**') 77 ), 78 'italic' => array( 79 'expression' => "#(?<!http:|https:|ftp:)//(.+?)(?<!http:|https:|ftp:)//#is", 80 'tag' => 'em', 81 'token' => array('//', '//') 82 ) 83 ); 84 85 /** 86 * Block hooks 87 */ 88 89 protected function before_parsing() { 90 $this->string = htmlspecialchars($this->string, ENT_COMPAT); 91 parent::before_parsing(); 92 } 93 94 public function get_section($header, $text, $clean = false) { 95 // The requested header is likely to have been passed to htmlspecialchars in 96 // self::before_parsing(), therefore we should decode it when looking for it. 97 return parent::get_section(htmlspecialchars_decode($header, ENT_COMPAT), $text, $clean); 98 } 99 100 protected function header_block_rule($match) { 101 $num = strlen($match[1]); 102 103 $text = trim($match[2]); 104 105 $text = preg_replace("/\s*={1,$num}$/im", "", $text); 106 107 return $this->generate_header($text, $num); 108 } 109 110 /** 111 * Table generation 112 */ 113 114 protected function table_block_rule($match) { 115 116 $rows = explode("\n", $match[0]); 117 $table = array(); 118 foreach($rows as $r) { 119 if(empty($r)) { 120 continue; 121 } 122 $rawcells = explode("|", $r); 123 $cells = array(); 124 125 array_shift($rawcells); 126 array_pop($rawcells); 127 128 foreach($rawcells as $c) { 129 if(!empty($c)) { 130 if($c[0] == "=") { 131 $type = 'header'; 132 $c = substr($c, 1); 133 } 134 else { 135 $type = 'normal'; 136 } 137 $this->rules($c); 138 $cells[] = array($type, $c); 139 } 140 } 141 $table[] = $cells; 142 } 143 144 return $this->generate_table($table); 145 } 146 147 protected function paragraph_block_rule($match) { 148 $text = $match[1]; 149 foreach($this->tagrules as $tr) { 150 if(isset($tr['token'])) { 151 if(is_array($tr['token'])) { 152 $this->escape_token_string($text, $tr['token'][0]); 153 $this->escape_token_string($text, $tr['token'][1]); 154 } 155 else { 156 $this->escape_token_string($text, $tr['token']); 157 } 158 } 159 } 160 $this->escape_token_string($text, "~"); 161 162 return $text; 163 } 164 165 /** 166 * Escape token when it is "negated" 167 */ 168 private function escape_token_string(&$text, $token) { 169 $text = str_replace("~".$token, $this->protect($token), $text); 170 } 171 172 /** 173 * Tag functions 174 */ 175 176 protected function url_tag_rule($match) { 177 if(strpos($match[0], "~") === 0) { 178 return substr($match[0], 1); 179 } 180 else { 181 $text = trim($match[0]); 182 $options = array('href' => $text); 183 184 return array($text, $options); 185 } 186 } 187 188 protected function link_tag_rule($match) { 189 $text = trim($match[1]); 190 191 if(strpos($match[0], "~") === 0) { 192 return substr($match[0], 1); 193 } 194 else { 195 return $this->format_link($text); 196 } 197 } 198 199 /** 200 * Special treatment of // ** // ** // 201 */ 202 protected function bold_tag_rule($match) { 203 $text = $match[1]; 204 $this->rules($text, array('only' => array('italic'))); 205 if(strpos($text, "//") !== false) { 206 $text = str_replace("//", $this->protect("//"), $text); 207 } 208 return array($text, array()); 209 } 210 211 protected function image_tag_rule($match) { 212 if(strpos($match[0], "~") === 0) { 213 return substr($match[0], 1); 214 } 215 216 return $this->format_image($match[1], $match[2]); 217 } 218 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body