1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Library of functions and constants for module wiki 19 * 20 * It contains the great majority of functions defined by Moodle 21 * that are mandatory to develop a module. 22 * 23 * @package mod_wiki 24 * @copyright 2009 Marc Alier, Jordi Piguillem marc.alier@upc.edu 25 * @copyright 2009 Universitat Politecnica de Catalunya http://www.upc.edu 26 * 27 * @author Jordi Piguillem 28 * @author Marc Alier 29 * @author David Jimenez 30 * @author Josep Arus 31 * @author Kenneth Riba 32 * 33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 */ 35 36 defined('MOODLE_INTERNAL') || die(); 37 38 /** 39 * Generic parser implementation 40 * 41 * @author Josep ArĂºs 42 * 43 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License 44 * @package mod_wiki 45 */ 46 class wiki_parser_proxy { 47 private static $parsers = array(); 48 private static $basepath = ""; 49 50 public static function parse(&$string, $type, $options = array()) { 51 52 if (empty(self::$basepath)) { 53 global $CFG; 54 self::$basepath = $CFG->dirroot . '/mod/wiki/parser/'; 55 } 56 57 $type = strtolower($type); 58 self::$parsers[$type] = null; // Reset the current parser because it may have other options. 59 if (self::create_parser_instance($type)) { 60 return self::$parsers[$type]->parse($string, $options); 61 } else { 62 return false; 63 } 64 } 65 66 public static function get_token($name, $type) { 67 if (self::create_parser_instance($type)) { 68 return self::$parsers[$type]->get_token($name); 69 } else { 70 return false; 71 } 72 } 73 74 public static function get_section(&$string, $type, $section, $allcontent = false) { 75 if (self::create_parser_instance($type)) { 76 $content = self::$parsers[$type]->get_section($section, $string, true); 77 78 if ($allcontent) { 79 return $content; 80 } else { 81 return is_array($content) ? $content[1] : null; 82 } 83 } else { 84 return false; 85 } 86 } 87 88 private static function create_parser_instance($type) { 89 if (empty(self::$parsers[$type])) { 90 include_once(self::$basepath . "markups/$type.php"); 91 $class = strtolower($type) . "_parser"; 92 if (class_exists($class)) { 93 self::$parsers[$type] = new $class; 94 return true; 95 } else { 96 return false; 97 } 98 } else { 99 return true; 100 } 101 } 102 } 103 104 require_once ('utils.php'); 105 106 abstract class generic_parser { 107 protected $string; 108 109 protected $blockrules = array(); 110 protected $tagrules = array(); 111 112 private $rulestack = array(); 113 114 protected $parserstatus = 'Before'; 115 116 /** 117 * Dynamic return values 118 */ 119 120 protected $returnvalues = array(); 121 122 private $nowikiindex = array(); 123 124 protected $nowikitoken = "%!"; 125 126 public function __construct() { 127 } 128 129 /** 130 * Parse function 131 */ 132 public function parse(&$string, $options = array()) { 133 if (!is_string($string)) { 134 return false; 135 } 136 137 $this->string =& $string; 138 139 $this->set_options(is_array($options) ? $options : array()); 140 141 $this->initialize_nowiki_index(); 142 143 if (method_exists($this, 'before_parsing')) { 144 $this->before_parsing(); 145 } 146 147 $this->parserstatus = 'Parsing'; 148 149 foreach ($this->blockrules as $name => $block) { 150 $this->process_block_rule($name, $block); 151 } 152 153 $this->commit_nowiki_index(); 154 155 $this->parserstatus = 'After'; 156 157 if (method_exists($this, 'after_parsing')) { 158 $this->after_parsing(); 159 } 160 161 return array('parsed_text' => $this->string) + $this->returnvalues; 162 } 163 164 /** 165 * Initialize options 166 */ 167 protected function set_options($options) { 168 } 169 170 /** 171 * Block processing function & callbacks 172 */ 173 protected function process_block_rule($name, $block) { 174 $this->rulestack[] = array('callback' => method_exists($this, $name . "_block_rule") ? $name . "_block_rule" : null, 175 'rule' => $block); 176 177 $this->string = preg_replace_callback($block['expression'], array($this, 'block_callback'), $this->string); 178 179 array_pop($this->rulestack); 180 } 181 182 private function block_callback($match) { 183 $rule = end($this->rulestack); 184 if (!empty($rule['callback'])) { 185 $stuff = $this->{$rule['callback']}($match); 186 } else { 187 $stuff = $match[1]; 188 } 189 190 if (is_array($stuff) && $rule['rule']['tag']) { 191 $this->rules($stuff[0], $rule['rule']['tags']); 192 $stuff = "\n" . parser_utils::h($rule['rule']['tag'], $stuff[0], $stuff[1]) . "\n"; 193 } else { 194 if (!isset($rule['rule']['tags'])) { 195 $rule['rule']['tags'] = null; 196 } 197 $this->rules($stuff, $rule['rule']['tags']); 198 if (isset($rule['rule']['tag']) && is_string($rule['rule']['tag'])) { 199 $stuff = "\n" . parser_utils::h($rule['rule']['tag'], $stuff) . "\n"; 200 } 201 } 202 203 return $stuff; 204 } 205 206 /** 207 * Rules processing function & callback 208 */ 209 210 protected final function rules(&$text, $rules = null) { 211 if ($rules === null) { 212 $rules = array('except' => array()); 213 } else if (is_array($rules) && count($rules) > 1) { 214 $rules = array('only' => $rules); 215 } 216 217 if (isset($rules['only']) && is_array($rules['only'])) { 218 $rules = $rules['only']; 219 foreach ($rules as $r) { 220 if (!empty($this->tagrules[$r])) { 221 $this->process_tag_rule($r, $this->tagrules[$r], $text); 222 } 223 } 224 } else if (isset($rules['except']) && is_array($rules['except'])) { 225 $rules = $rules['except']; 226 foreach ($this->tagrules as $r => $tr) { 227 if (!in_array($r, $rules)) { 228 $this->process_tag_rule($r, $tr, $text); 229 } 230 } 231 } 232 } 233 234 private function process_tag_rule($name, $rule, &$text) { 235 if (method_exists($this, $name . "_tag_rule")) { 236 $this->rulestack[] = array('callback' => $name . "_tag_rule", 'rule' => $rule); 237 $text = preg_replace_callback($rule['expression'], array($this, 'tag_callback'), $text); 238 array_pop($this->rulestack); 239 } else { 240 if (isset($rule['simple'])) { 241 $replace = "<{$rule['tag']} />"; 242 } else { 243 $replace = parser_utils::h($rule['tag'], "$1"); 244 } 245 246 $text = preg_replace($rule['expression'], $replace, $text); 247 } 248 } 249 250 private function tag_callback($match) { 251 $rule = end($this->rulestack); 252 $stuff = $this->{$rule['callback']}($match); 253 254 if (is_array($stuff)) { 255 return parser_utils::h($rule['rule']['tag'], $stuff[0], $stuff[1]); 256 } else { 257 return $stuff; 258 } 259 } 260 261 /** 262 * Special nowiki parser index 263 */ 264 265 private function initialize_nowiki_index() { 266 $token = "\Q" . $this->nowikitoken . "\E"; 267 $this->string = preg_replace_callback("/" . $token . "\d+" . $token . "/", 268 array($this, "initialize_nowiki_index_callback"), $this->string); 269 } 270 271 private function initialize_nowiki_index_callback($match) { 272 return $this->protect($match[0]); 273 } 274 275 protected function protect($text) { 276 $this->nowikiindex[] = $text; 277 278 return $this->nowikitoken . (count($this->nowikiindex) - 1) . $this->nowikitoken; 279 } 280 281 private function commit_nowiki_index() { 282 $token = "\Q" . $this->nowikitoken . "\E"; 283 $this->string = preg_replace_callback("/" . $token . "(\d+)" . $token . "/", 284 array($this, "commit_nowiki_index_callback"), $this->string); 285 } 286 287 private function commit_nowiki_index_callback($match) { 288 return $this->nowikiindex[intval($match[1])]; 289 } 290 291 /** 292 * Get token of the parsable element $name. 293 */ 294 public function get_token($name) { 295 foreach (array_merge($this->blockrules, $this->tagrules) as $n => $v) { 296 if ($name == $n && isset($v['token'])) { 297 return $v['token'] ? $v['token'] : false; 298 } 299 } 300 301 return false; 302 } 303 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body