[ Index ] |
|
Code source de Plume CMS 1.2.2 |
1 <?php 2 3 /** 4 * Bibliotheque d'objets permettant de tranformer un texte, contenant des 5 * signes de formatages 6 * simples de type wiki, en un autre format tel que XHTML 1.0/strict 7 * @author Laurent Jouanneau <jouanneau@netcourrier.com> 8 * @copyright 2003-2004 Laurent Jouanneau 9 * @module Wiki Renderer 10 * @version 2.0dev-php5 11 * @since 28/11/2004 12 * http://ljouanneau.com/softs/wikirenderer/ 13 * Thanks to all users who found bugs : 14 * Loic, Edouard Guerin, Sylvain, Ludovic L. 15 * 16 * This library is free software; you can redistribute it and/or 17 * modify it under the terms of the GNU Lesser General Public 18 * License as published by the Free Software Foundation; either 19 * version 2.1 of the License, or (at your option) any later version. 20 * 21 * This library is distributed in the hope that it will be useful, 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 * Lesser General Public License for more details. 25 * 26 * You should have received a copy of the GNU Lesser General Public 27 * License along with this library; if not, write to the Free Software 28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 29 * ---------------------------------------------------------------------------- 30 * Contributeurs : 31 * Edouard Guérin <eguerin@icitrus.net> (Adapatation PHP5) 32 */ 33 34 define('WIKIRENDERER_PATH', dirname(__FILE__).'/'); 35 define('WIKIRENDERER_VERSION', '2.0dev-php5'); 36 37 38 if (version_compare(phpversion(), '5.0') < 0) { 39 eval(' 40 function clone($object) { 41 return $object; 42 } 43 '); 44 } 45 46 /** 47 * Implémente les propriétés d'un tag inline wiki et 48 * le fonctionnement pour la génération 49 * du code html correspondant 50 */ 51 52 class WikiTag { 53 54 var $name; 55 var $beginTag; 56 var $endTag; 57 var $useSeparator = true; 58 var $attribute = array(); 59 var $builderFunction = null; 60 61 var $contents = array(); 62 var $separatorCount = 0; 63 var $isDummy = false; 64 65 function WikiTag($name, $properties){ 66 $this->name=$name; 67 $this->beginTag=$properties[0]; 68 $this->endTag=$properties[1]; 69 if($this->name == 'dummie') 70 $this->isDummy=true; 71 72 if(is_null($properties[2])) { 73 $this->attribute=array(); 74 $this->useSeparator=false; 75 } 76 else { 77 $this->attribute=$properties[2]; 78 $this->useSeparator=(count($this->attribute)>0); 79 } 80 $this->builderFunction=$properties[3]; 81 } 82 83 function addContent($string, $escape=true){ 84 if(!isset($this->contents[$this->separatorCount])) 85 $this->contents[$this->separatorCount]=''; 86 87 if($escape) 88 $this->contents[$this->separatorCount].= htmlspecialchars($string); 89 else 90 $this->contents[$this->separatorCount] .= $string; 91 } 92 93 function addSeparator() { 94 $this->separatorCount++; 95 } 96 97 function getBeginTag() { 98 return $this->beginTag; 99 } 100 101 function getEndTag() { 102 return $this->endTag; 103 } 104 105 function getNumberSeparator() { 106 return $this->separatorCount; 107 } 108 109 function useSeparator() { 110 return $this->useSeparator; 111 } 112 113 function isDummy() { 114 return $this->isDummy; 115 } 116 117 function getHtmlContent() { 118 if(is_null($this->builderFunction)) { 119 $attr=''; 120 if($this->useSeparator) { 121 $cntattr=count($this->attribute); 122 $count=($this->separatorCount > $cntattr?$cntattr:$this->separatorCount); 123 for($i=1;$i<=$count;$i++) { 124 $attr.=' '.$this->attribute[$i-1].'="'.$this->contents[$i].'"'; 125 } 126 } 127 if(isset($this->contents[0])) 128 return '<'.$this->name.$attr.'>'.$this->contents[0].'</'.$this->name.'>'; 129 else 130 return '<'.$this->name.$attr.' />'; 131 } 132 else { 133 $fct=$this->builderFunction; 134 return $fct($this->contents, $this->attribute); 135 } 136 } 137 138 } 139 140 141 /** 142 * Moteur permettant de transformer les tags wiki inline 143 * d'une chaine en équivalent HTML 144 */ 145 class WikiInlineParser { 146 147 var $resultline=''; 148 var $error=false; 149 var $listTag=array(); 150 var $str=array(); 151 var $splitPattern=''; 152 var $checkWikiWord=false; 153 var $checkWikiWordFunction=null; 154 var $simpletags = null; 155 var $_separator; 156 var $escapeHtml=true; 157 var $end=0; 158 159 /** 160 * constructeur 161 * @param array $inlinetags liste des tags permis 162 * @param string caractère séparateur des différents composants 163 * d'un tag wiki 164 */ 165 166 function WikiInlineParser( 167 $inlinetags, 168 $simpletags, 169 $separator='|', 170 $checkWikiWord=false, 171 $funcCheckWikiWord=null, 172 $escapeHtml=true 173 ) { 174 175 foreach($inlinetags as $name=>$prop){ 176 $this->listTag[$prop[0]]=new WikiTag($name,$prop); 177 178 $this->splitPattern.=preg_replace ( '/([^\w\s\d])/', '\\\\\\1',$prop[0]).')|('; 179 if($prop[1] != $prop[0]) 180 $this->splitPattern.=preg_replace ( '/([^\w\s\d])/', '\\\\\\1',$prop[1]).')|('; 181 } 182 foreach($simpletags as $tag=>$html){ 183 $this->splitPattern.=preg_replace ( '/([^\w\s\d])/', '\\\\\\1',$tag).')|('; 184 } 185 186 $this->simpletags=$simpletags; 187 $this->_separator=$separator; 188 $this->checkWikiWord=$checkWikiWord; 189 $this->checkWikiWordFunction=$funcCheckWikiWord; 190 $this->escapeHtml=$escapeHtml; 191 } 192 193 /** 194 * fonction principale du parser. 195 * @param string $line avec des eventuels tag wiki 196 * @return string chaine $line avec les tags wiki transformé en HTML 197 */ 198 function parse($line) { 199 $this->error=false; 200 201 $this->str=preg_split('/('.$this->splitPattern.'\\'.$this->_separator.')|(\\\\)/',$line, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); 202 $this->end=count($this->str); 203 if($this->end > 1) { 204 $firsttag=new WikiTag('dummie',array('','', null,'wikibuilddummie')); 205 $pos=-1; 206 return $this->_parse($firsttag, $pos); 207 } 208 else { 209 if($this->escapeHtml) { 210 if($this->checkWikiWord && $this->checkWikiWordFunction !== null) 211 return $this->_doCheckWikiWord(htmlspecialchars($line)); 212 else 213 return htmlspecialchars($line); 214 } 215 else { 216 if($this->checkWikiWord && $this->checkWikiWordFunction !== null) 217 return $this->_doCheckWikiWord($line); 218 else 219 return $line; 220 } 221 222 } 223 } 224 225 /** 226 * coeur du parseur. Appelé récursivement 227 */ 228 229 function _parse($tag, &$posstart) { 230 231 $checkNextTag=true; 232 $checkBeginTag=true; 233 234 // on parcours la chaine, morceau aprés morceau 235 for($i=$posstart+1; $i < $this->end; $i++) { 236 237 $t=&$this->str[$i]; 238 // a t-on un antislash ? 239 if($t=='\\'){ 240 if($checkNextTag){ 241 $t=''; // oui -> on l'efface et on ignore le tag (on continue) 242 $checkNextTag=false; 243 } 244 else { 245 $tag->addContent('\\',false); 246 } 247 248 // est-ce un séparateur ? 249 } 250 elseif($t == $this->_separator) { 251 if($tag->isDummy() || !$checkNextTag) 252 $tag->addContent($this->_separator,false); 253 elseif($tag->useSeparator()) { 254 $checkBeginTag=false; 255 $tag->addSeparator(); 256 } 257 else { 258 $tag->addContent($this->_separator,false); 259 } 260 // a-t-on une balise de fin du tag ? 261 } 262 elseif($checkNextTag && $tag->getEndTag() == $t && !$tag->isDummy()) { 263 $posstart=$i; 264 return $tag->getHtmlContent(); 265 266 // a-t-on une balise de debut de tag quelconque ? 267 } 268 elseif($checkBeginTag && $checkNextTag && isset($this->listTag[$t]) ) { 269 270 $content = $this->_parse(clone($this->listTag[$t]),$i); // clone indispensable sinon plantage !!! 271 if($content) 272 $tag->addContent($content,false); 273 else { 274 if($tag->getNumberSeparator() == 0 && $this->checkWikiWord && $this->checkWikiWordFunction !== null) { 275 if($this->escapeHtml) 276 $tag->addContent($this->_doCheckWikiWord(htmlspecialchars($t)),false); 277 else 278 $tag->addContent($this->_doCheckWikiWord($t),false); 279 } 280 else 281 $tag->addContent($t,$this->escapeHtml); 282 } 283 284 // a-t-on un saut de ligne forcé ? 285 } 286 elseif($checkNextTag && $checkBeginTag && isset($this->simpletags[$t])) { 287 $tag->addContent($this->simpletags[$t],false); 288 } 289 else { 290 if($tag->getNumberSeparator() == 0 && $this->checkWikiWord && $this->checkWikiWordFunction !== null) { 291 if($this->escapeHtml) 292 $tag->addContent($this->_doCheckWikiWord(htmlspecialchars($t)),false); 293 else 294 $tag->addContent($this->_doCheckWikiWord($t),false); 295 } 296 else 297 $tag->addContent($t,$this->escapeHtml); 298 $checkNextTag=true; 299 } 300 } 301 if(!$tag->isDummy()) { 302 //--- on n'a pas trouvé le tag de fin 303 // on met en erreur 304 $this->error=true; 305 return false; 306 } 307 else 308 return $tag->getHtmlContent(); 309 } 310 311 function _doCheckWikiWord($string) { 312 if(preg_match_all("/(?<=\b)[A-Z][a-z]+[A-Z0-9]\w*/", $string, $matches)){ 313 $fct=$this->checkWikiWordFunction; 314 $match = array_unique($matches[0]); // il faut avoir une liste sans doublon, à cause du str_replace plus loin... 315 $string=str_replace($match, $fct($match), $string); 316 } 317 return $string; 318 } 319 320 function getError() { 321 return $this->error; 322 } 323 324 } 325 326 327 328 /** 329 * classe de base pour la transformation des élements de type bloc 330 * @abstract 331 */ 332 class WikiRendererBloc { 333 334 /** 335 * @var string code identifiant le type de bloc 336 * @access protected 337 */ 338 var $type=''; 339 340 /** 341 * @var string chaine contenant le tag XHTML d'ouverture du bloc 342 * @access protected 343 */ 344 var $_openTag=''; 345 346 /** 347 * @var string chaine contenant le tag XHTML de fermeture du bloc 348 * @access protected 349 */ 350 var $_closeTag=''; 351 352 /** 353 * @var boolean indique si le bloc doit être immediatement fermé aprés détection 354 * @access protected 355 */ 356 var $_closeNow=false; 357 358 /** 359 * @var WikiRenderer référence à la classe principale 360 * @access protected 361 */ 362 var $engine=null; 363 364 /** 365 * @var array liste des élements trouvés par l'expression régulière regexp 366 * @access protected 367 */ 368 var $_detectMatch=null; 369 370 /** 371 * @var string expression régulière permettant de reconnaitre le bloc 372 * @access protected 373 */ 374 var $regexp=''; 375 376 /** 377 * constructeur à surcharger pour définir les valeurs des différentes proprietés 378 * @param WikiRender $wr l'objet moteur wiki 379 */ 380 381 function WikiRendererBloc($wr) { 382 $this->engine = $wr; 383 } 384 385 /** 386 * renvoi une chaine correspondant à l'ouverture du bloc 387 * @return string 388 * @access public 389 */ 390 391 function open() { 392 return $this->_openTag; 393 } 394 395 /** 396 * renvoi une chaine correspondant à la fermeture du bloc 397 * @return string 398 * @access public 399 */ 400 401 function close() { 402 return $this->_closeTag; 403 } 404 405 /** 406 * indique si le bloc doit etre immédiatement fermé 407 * @return string 408 * @access public 409 */ 410 411 function closeNow() { 412 return $this->_closeNow; 413 } 414 415 /** 416 * test si la chaine correspond au debut ou au contenu d'un bloc 417 * @param string $string 418 * @return boolean true: appartient au bloc 419 * @access public 420 */ 421 422 function detect($string) { 423 return preg_match($this->regexp, $string, $this->_detectMatch); 424 } 425 426 /** 427 * renvoi la ligne, traitée pour le bloc. A surcharger éventuellement. 428 * @return string 429 * @access public 430 */ 431 432 function getRenderedLine() { 433 return $this->_renderInlineTag($this->_detectMatch[1]); 434 } 435 436 /** 437 * renvoi le type du bloc en cours de traitement 438 * @return string 439 * @access public 440 */ 441 442 function getType() { 443 return $this->type; 444 } 445 446 /** 447 * définit la liste des élements trouvés par l'expression régulière regexp 448 * @return array 449 * @access public 450 */ 451 452 function setMatch($match) { 453 $this->_detectMatch = $match; 454 } 455 456 /** 457 * renvoi la liste des élements trouvés par l'expression régulière regexp 458 * @return array 459 * @access public 460 */ 461 462 function getMatch() { 463 return $this->_detectMatch; 464 } 465 466 /** 467 * traite le rendu des signes de type inline (qui se trouvent necessairement dans des blocs 468 * @param string $string une chaine contenant une ou plusieurs balises wiki 469 * @return string la chaine transformée en XHTML 470 * @access protected 471 * @see WikiRendererInline 472 */ 473 474 function _renderInlineTag($string) { 475 $parser = $this->engine->getInlineParser(); 476 return $parser->parse($string); 477 } 478 479 /** 480 * détection d'attributs de bloc (ex: >°°attr1|attr2|attr3°° la citation ) 481 * @todo à terminer pour une version ulterieure 482 * @access protected 483 */ 484 485 function _checkAttributes(&$string) { 486 $bat=$this->engine->config->blocAttributeTag; 487 if(preg_match("/^$bat(.*)$bat(.*)$/",$string,$result)) { 488 $string=$result[2]; 489 return explode($this->engine->config->inlineTagSeparator,$result[1]); 490 } else 491 return false; 492 } 493 494 } 495 496 require (WIKIRENDERER_PATH . 'WikiRenderer.conf.php'); 497 498 499 500 /** 501 * Moteur de rendu. Classe principale à instancier pour transformer un texte wiki en texte XHTML. 502 * utilisation : 503 * $ctr = new WikiRenderer(); 504 * $monTexteXHTML = $ctr->render($montexte); 505 */ 506 507 class WikiRenderer { 508 509 /** 510 * @var string contient la version HTML du texte analysé 511 * @access private 512 */ 513 514 var $_newtext; 515 516 /** 517 * @var boolean 518 * @access private 519 */ 520 521 var $_isBlocOpen=false; 522 523 /** 524 * @var WikiRendererBloc element bloc ouvert en cours 525 * @access private 526 */ 527 528 var $_currentBloc; 529 530 /** 531 * @var array liste des differents types de blocs disponibles 532 * @access private 533 */ 534 535 var $_blocList= array(); 536 537 /** 538 * @var array liste de paramètres pour le moteur 539 * @access private 540 */ 541 542 var $params=array(); 543 544 /** 545 * @var WikiInlineParser analyseur pour les tags wiki inline 546 * @access private 547 */ 548 549 var $inlineParser=null; 550 551 /** 552 * liste des lignes où il y a une erreur wiki 553 * @access private 554 */ 555 556 var $errors; 557 558 /** 559 * @var WikiRendererConfig objet de configuration, permet de modifier 560 * @see WikiRendererConfig 561 * @access private 562 */ 563 564 var $config=null; 565 566 /** 567 * instancie les différents objets pour le rendu des elements inline et bloc. 568 */ 569 570 function WikiRenderer($config=null, $prefix='WRB_') { 571 if(is_null($config)) 572 $this->config = new WikiRendererConfig(); 573 else 574 $this->config=$config; 575 576 $this->_currentBloc = new WikiRendererBloc($this); // bloc 'fantome' 577 $this->inlineParser = new WikiInlineParser( 578 $this->config->inlinetags, 579 $this->config->simpletags, 580 $this->config->inlineTagSeparator, 581 $this->config->checkWikiWord, 582 $this->config->checkWikiWordFunction, 583 $this->config->escapeSpecialChars 584 ); 585 586 foreach($this->config->bloctags as $name=>$ok) { 587 $name=$prefix.$name; 588 if($ok) $this->_blocList[] = new $name($this); 589 } 590 } 591 592 /** 593 * Methode principale qui transforme les tags wiki en tag XHTML 594 * @param string $texte le texte à convertir 595 * @return string le texte converti en XHTML 596 * @access public 597 */ 598 function render($texte) { 599 600 // on remplace les \r (mac), les \n (unix) et les \r\n (windows) par un autre caractère pour découper proprement 601 $lignes=preg_split("/\015\012|\015|\012/",$texte); 602 603 $this->_newtext=array(); 604 $this->_isBlocOpen=false; 605 $this->errors=false; 606 $this->_currentBloc = new WikiRendererBloc($this); 607 608 // parcours de l'ensemble des lignes du texte 609 foreach($lignes as $num=>$ligne){ 610 611 if($ligne == '') { // pas de trim à cause des pre 612 // ligne vide 613 $this->_closeBloc(); 614 } 615 else { 616 617 // detection de debut de bloc (liste, tableau, hr, titre) 618 foreach($this->_blocList as $bloc) { 619 if($bloc->detect($ligne)) 620 break; 621 } 622 623 // c'est le debut d'un bloc (ou ligne d'un bloc en cours) 624 if($bloc->getType() != $this->_currentBloc->getType()) { 625 $this->_closeBloc(); // on ferme le precedent si c'etait un different 626 $this->_currentBloc= $bloc; 627 if($this->_openBloc()) { 628 $this->_newtext[]=$this->_currentBloc->getRenderedLine(); 629 } 630 else { 631 $this->_newtext[]=$this->_currentBloc->getRenderedLine(); 632 $this->_newtext[]=$this->_currentBloc->close(); 633 $this->_isBlocOpen = false; 634 $this->_currentBloc = new WikiRendererBloc($this); 635 } 636 637 } 638 else { 639 $this->_currentBloc->setMatch($bloc->getMatch()); 640 $this->_newtext[]=$this->_currentBloc->getRenderedLine(); 641 } 642 if($this->inlineParser->getError()) { 643 $this->errors[$num+1]=$ligne; 644 } 645 } 646 } 647 648 $this->_closeBloc(); 649 return implode("\n",$this->_newtext); 650 } 651 652 /** 653 * renvoi l'objet de configuration 654 * @access public 655 * @see WikiRendererConfig 656 * @return WikiRendererConfig 657 */ 658 659 function getConfig() { 660 return $this->config; 661 } 662 663 /** 664 * Retourne l'objet inlineParser (WikiInlineParser) utilisé dans le moteur 665 * @access public 666 * @see WikiInlineParser 667 * @return WikiInlineParser 668 */ 669 670 function getInlineParser() { 671 return $this->inlineParser; 672 } 673 674 /** 675 * renvoi la liste des erreurs detectées par le moteur 676 * @access public 677 * @return array 678 */ 679 680 function getErrors() { 681 return $this->errors; 682 } 683 684 /** 685 * renvoi la version de wikirenderer 686 * @access public 687 * @return string version 688 */ 689 function getVersion(){ 690 return WIKIRENDERER_VERSION; 691 } 692 693 /** 694 * ferme un bloc 695 * @access private 696 */ 697 698 function _closeBloc() { 699 if($this->_isBlocOpen) { 700 $this->_isBlocOpen=false; 701 $this->_newtext[]=$this->_currentBloc->close(); 702 $this->_currentBloc = new WikiRendererBloc($this); 703 } 704 } 705 706 /** 707 * ouvre un bloc et le referme eventuellement suivant sa nature 708 * @return boolean indique si le bloc reste ouvert ou pas 709 * @access private 710 */ 711 712 function _openBloc() { 713 if(!$this->_isBlocOpen) { 714 $this->_newtext[]=$this->_currentBloc->open(); 715 $this->_isBlocOpen=true; 716 return !$this->_currentBloc->closeNow(); 717 } 718 else 719 return true; 720 } 721 722 } 723 724 725 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Mon Nov 26 11:57:01 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |