[ Index ]
 

Code source de Dotclear 2.0-beta6

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/inc/clearbricks/text.wiki2xhtml/ -> class.wiki2xhtml.php (source)

   1  <?php
   2  ###########################################################
   3  #      /!\ /!\ /!\ EDIT THIS FILE IN UTF8 /!\ /!\ /!\     #
   4  ###########################################################
   5  
   6  # ***** BEGIN LICENSE BLOCK *****
   7  # This file is part of Clearbricks.
   8  # Copyright (c) 2006 Olivier Meunier and contributors. All rights
   9  # reserved.
  10  #
  11  # Clearbricks is free software; you can redistribute it and/or modify
  12  # it under the terms of the GNU General Public License as published by
  13  # the Free Software Foundation; either version 2 of the License, or
  14  # (at your option) any later version.
  15  # 
  16  # Clearbricks is distributed in the hope that it will be useful,
  17  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  18  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19  # GNU General Public License for more details.
  20  # 
  21  # You should have received a copy of the GNU General Public License
  22  # along with Clearbricks; if not, write to the Free Software
  23  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  24  #
  25  # ***** END LICENSE BLOCK *****
  26  #
  27  # Contributor(s):
  28  # Stephanie Booth
  29  # Mathieu Pillard
  30  # Christophe Bonijol
  31  # Jean-Charles Bagneris
  32  # Nicolas Chachereau
  33  # Jérôme Lipowicz
  34  #
  35  # Version : 3.1d
  36  # Release date : Monday 2004-06-06
  37  
  38  # History :
  39  #
  40  # 3.2.4
  41  #            => Auto links
  42  #            => Code cleanup
  43  #
  44  # 3.2.3
  45  # Olivier
  46  #             => PHP5 Strict
  47  #
  48  # 3.2.2
  49  # Olivier
  50  #            => Changement de la gestion des URL spéciales
  51  #
  52  # 3.2.1
  53  # Olivier
  54  #            => Changement syntaxe des macros
  55  #
  56  # 3.2
  57  # Olivier
  58  #            => Changement de fonctionnement des macros
  59  #            => Passage de fonctions externes pour les macros et les mots wiki
  60  #
  61  # 3.1d
  62  # Jérôme Lipowicz
  63  #            => antispam
  64  # Olivier
  65  #            => centrage d'image
  66  #
  67  # 3.1c
  68  # Olivier
  69  #            => Possibilité d'échaper les | dans les marqueurs avec \
  70  #
  71  # 3.1b
  72  # Nicolas Chachereau
  73  #            => Changement de regexp pour la correction syntaxique
  74  #
  75  # 3.1a
  76  # Olivier
  77  #            => Bug du Call-time pass-by-reference
  78  #
  79  # 3.1
  80  # Olivier
  81  #            => Ajout des macros «««..»»»
  82  #            => Ajout des blocs vides øøø
  83  #            => Ajout du niveau de titre paramétrable
  84  #            => Option de blocage du parseur dans les <pre>
  85  #            => Titres au format setext (experimental, désactivé)
  86  #
  87  # 3.0
  88  # Olivier        => Récriture du parseur inline, plus d'erreur XHTML
  89  #            => Ajout d'une vérification d'intégrité pour les listes
  90  #            => Les acronymes sont maintenant dans un fichier texte
  91  #            => Ajout d'un tag images ((..)), del --..-- et ins ++..++
  92  #            => Plus possible de faire des liens JS [lien|javascript:...]
  93  #            => Ajout des notes de bas de page §§...§§
  94  #            => Ajout des mots wiki
  95  #
  96  # 2.5
  97  # Olivier        => Récriture du code, plus besoin du saut de ligne entre blocs !=
  98  #
  99  # 2.0
 100  # Stephanie    => correction des PCRE et ajout de fonctionnalités
 101  # Mathieu     => ajout du strip-tags, implementation des options, reconnaissance automatique d'url, etc.
 102  # Olivier        => chagement de active_link en active_urls
 103  #            => ajout des options pour les blocs
 104  #            => intégration de l'aide dans le code, avec les options
 105  #            => début de quelque chose pour la reconnaissance auto d'url (avec Mat)
 106  
 107  # TODO :
 108  # Mathieu    => active_wiki_urls (modifier wikiParseUrl ?)
 109  #         => active_auto_urls
 110  #
 111  # *        => ajouter des options.
 112  #         => trouver un meilleur nom pour active_link ? (pour le jour ou ca sera tellement une usine
 113  #           a gaz que on generera des tags <link> :)
 114  #
 115  
 116  # Wiki2xhtml
 117  
 118  class wiki2xhtml
 119  {
 120      public $__version__ = '3.2.4';
 121      
 122      public $T;
 123      public $opt;
 124      public $line;
 125      public $acro_table;
 126      public $foot_notes;
 127      public $macros;
 128      public $functions;
 129      
 130      public $tags;
 131      public $open_tags;
 132      public $close_tags;
 133      public $custom_tags = array();
 134      public $all_tags;
 135      public $tag_pattern;
 136      public $escape_table;
 137      public $allowed_inline = array();
 138      
 139  	function __construct()
 140      {
 141          # Mise en place des options
 142          $this->setOpt('active_title',1);        # Activation des titres !!!
 143          $this->setOpt('active_setext_title',0);    # Activation des titres setext (EXPERIMENTAL)
 144          $this->setOpt('active_hr',1);            # Activation des <hr />
 145          $this->setOpt('active_lists',1);        # Activation des listes
 146          $this->setOpt('active_quote',1);        # Activation du <blockquote>
 147          $this->setOpt('active_pre',1);        # Activation du <pre>
 148          $this->setOpt('active_empty',1);        # Activation du bloc vide øøø
 149          $this->setOpt('active_auto_urls',0);    # Activation de la reconnaissance d'url
 150          $this->setOpt('active_auto_br',0);    # Activation du saut de ligne automatique (dans les paragraphes)
 151          $this->setOpt('active_antispam',1);    # Activation de l'antispam pour les emails
 152          $this->setOpt('active_urls',1);        # Activation des liens []
 153          $this->setOpt('active_auto_img',1);    # Activation des images automatiques dans les liens []
 154          $this->setOpt('active_img',1);        # Activation des images (())
 155          $this->setOpt('active_anchor',1);        # Activation des ancres ~...~
 156          $this->setOpt('active_em',1);            # Activation du <em> ''...''
 157          $this->setOpt('active_strong',1);        # Activation du <strong> __...__
 158          $this->setOpt('active_br',1);            # Activation du <br /> %%%
 159          $this->setOpt('active_q',1);            # Activation du <q> {{...}}
 160          $this->setOpt('active_code',1);        # Activation du <code> @@...@@
 161          $this->setOpt('active_acronym',1);     # Activation des acronymes
 162          $this->setOpt('active_ins',1);        # Activation des ins ++..++
 163          $this->setOpt('active_del',1);        # Activation des del --..--
 164          $this->setOpt('active_footnotes',1);    # Activation des notes de bas de page
 165          $this->setOpt('active_wikiwords',0);    # Activation des mots wiki
 166          $this->setOpt('active_macros',1);        # Activation des macros {{{ }}}
 167          
 168          $this->setOpt('parse_pre',1);            # Parser l'intérieur de blocs <pre> ?
 169          
 170          $this->setOpt('active_fr_syntax',1);    # Corrections syntaxe FR
 171          
 172          $this->setOpt('first_title_level',3);    # Premier niveau de titre <h..>
 173          
 174          $this->setOpt('note_prefix','wiki-footnote');
 175          $this->setOpt('note_str','<div class="footnotes"><h4>Notes</h4>%s</div>');
 176          $this->setOpt('words_pattern',
 177          '((?<![A-Za-z0-9])([A-Z][a-z]+){2,}(?![A-Za-z0-9]))');
 178          
 179          $this->setOpt('auto_url_pattern',
 180          '%(?<![\[\|])(http://|https://|ftp://|news:)([^"\s\)!]+)%msu');
 181          
 182          $this->setOpt('acronyms_file',dirname(__FILE__).'/acronyms.txt');
 183          
 184          $this->acro_table = $this->__getAcronyms();
 185          $this->foot_notes = array();
 186          $this->functions = array();
 187          $this->macros = array();
 188          
 189          $this->registerFunction('macro:html',array($this,'__macroHTML'));
 190      }
 191      
 192  	function setOpt($option, $value)
 193      {
 194          $this->opt[$option] = $value;
 195      }
 196      
 197  	function setOpts($options)
 198      {
 199          if (!is_array($options)) {
 200              return;
 201          }
 202          
 203          foreach ($options as $k => $v) {
 204              $this->opt[$k] = $v;
 205          }
 206      }
 207      
 208  	function getOpt($option)
 209      {
 210          return (!empty($this->opt[$option])) ? $this->opt[$option] : false;
 211      }
 212      
 213  	function registerFunction($type,$name)
 214      {
 215          if (is_callable($name)) {
 216              $this->functions[$type] = $name;
 217          }
 218      }
 219      
 220  	function transform($in)
 221      {
 222          # Initialisation des tags
 223          $this->__initTags();
 224          $this->foot_notes = array();
 225          
 226          # Récupération des macros
 227          if ($this->getOpt('active_macros')) {
 228              $in = preg_replace('#^///(.*?)///($|\r)#mse',"\\\$this->__getMacro('\\1')",$in);
 229          }
 230          
 231          # Vérification du niveau de titre
 232          if ($this->getOpt('first_title_level') > 4) {
 233              $this->setOpt('first_title_level',4);
 234          }
 235          
 236          $res = str_replace("\r", '', $in);
 237          
 238          $escape_pattern = array();
 239          
 240          # traitement des titres à la setext
 241          if ($this->getOpt('active_setext_title') && $this->getOpt('active_title')) {
 242              $res = preg_replace('/^(.*)\n[=]{5,}$/m','!!!$1',$res); 
 243              $res = preg_replace('/^(.*)\n[-]{5,}$/m','!!$1',$res);
 244          }
 245          
 246          # Transformation des mots Wiki
 247          if ($this->getOpt('active_wikiwords') && $this->getOpt('words_pattern')) {
 248              $res = preg_replace('/'.$this->getOpt('words_pattern').'/msu','¶¶¶$1¶¶¶',$res);
 249          }
 250          
 251          # Transformation des URLs automatiques
 252          if ($this->getOpt('active_auto_urls'))
 253          {
 254              $active_urls = $this->getOpt('active_urls');
 255              
 256              $this->setOpt('active_urls',1);
 257              $this->__initTags();
 258              
 259              # If urls are not active, escape URLs tags
 260              if (!$active_urls)
 261              {
 262                  $res = preg_replace(
 263                  '%(?<!\\\\)(['.preg_quote(implode('',$this->tags['a'])).'])%msU',
 264                  '\\\$1',$res
 265                  );
 266              }
 267              
 268              # Transforms urls
 269              $res = preg_replace($this->getOpt('auto_url_pattern'),'[$1$2]',$res);
 270              
 271          }
 272          
 273          $this->T = explode("\n",$res);
 274          $this->T[] = '';
 275          
 276          # Parse les blocs
 277          $res = $this->__parseBlocks();
 278          
 279          # Line break
 280          if ($this->getOpt('active_br')) {
 281              $res = preg_replace('/(?<!\\\)%%%/', '<br />', $res);
 282              $escape_pattern[] = '%%%';
 283          }
 284          
 285          # Nettoyage des \s en trop
 286          $res = preg_replace('/([\s]+)(<\/p>|<\/li>|<\/pre>)/', '$2', $res);
 287          $res = preg_replace('/(<li>)([\s]+)/', '$1', $res);
 288          
 289          # On vire les escapes
 290          if (!empty($escape_pattern)) {
 291              $res = preg_replace('/\\\('.implode('|',$escape_pattern).')/','$1',$res);
 292          }
 293          
 294          # On vire les ¶¶¶MotWiki¶¶¶ qui sont resté (dans les url...)
 295          if ($this->getOpt('active_wikiwords') && $this->getOpt('words_pattern')) {
 296              $res = preg_replace('/¶¶¶'.$this->getOpt('words_pattern').'¶¶¶/msu','$1',$res);
 297          }
 298          
 299          # On remet les macros
 300          if ($this->getOpt('active_macros')) {
 301              $res = preg_replace('/^##########MACRO#([0-9]+)#$/mse','\$this->__putMacro("$1")',$res);
 302          }
 303          
 304          # Auto line break dans les paragraphes
 305          if ($this->getOpt('active_auto_br')) {
 306              $res = preg_replace_callback('%(<p>)(.*?)(</p>)%msu',array($this,'__autoBR'),$res);
 307          }
 308          
 309          # On ajoute les notes
 310          if (count($this->foot_notes) > 0)
 311          {
 312              $res_notes = '';
 313              $i = 1;
 314              foreach ($this->foot_notes as $k => $v) {
 315                  $res_notes .= "\n".'<p>[<a href="#rev-'.$k.'" id="'.$k.'">'.$i.'</a>] '.$v.'</p>';
 316                  $i++;
 317              }
 318              $res .= sprintf("\n".$this->getOpt('note_str')."\n",$res_notes);
 319          }
 320          
 321          return $res;
 322      }
 323      
 324      /* PRIVATE
 325      --------------------------------------------------- */
 326      
 327  	function __initTags()
 328      {
 329          $tags = array(
 330              'em' => array("''","''"),
 331              'strong' => array('__','__'),
 332              'acronym' => array('??','??'),
 333              'a' => array('[',']'),
 334              'img' => array('((','))'),
 335              'q' => array('{{','}}'),
 336              'code' => array('@@','@@'),
 337              'anchor' => array('~','~'),
 338              'del' => array('--','--'),
 339              'ins' => array('++','++'),
 340              'note' => array('$$','$$'),
 341              'word' => array('¶¶¶','¶¶¶')
 342          );
 343          
 344          $this->tags = array_merge($tags,$this->custom_tags);
 345          
 346          # Suppression des tags selon les options
 347          if (!$this->getOpt('active_urls')) {
 348              unset($this->tags['a']);
 349          }
 350          if (!$this->getOpt('active_img')) {
 351              unset($this->tags['img']);
 352          }
 353          if (!$this->getOpt('active_anchor')) {
 354              unset($this->tags['anchor']);
 355          }
 356          if (!$this->getOpt('active_em')) {
 357              unset($this->tags['em']);
 358          }
 359          if (!$this->getOpt('active_strong')) {
 360              unset($this->tags['strong']);
 361          }
 362          if (!$this->getOpt('active_q')) {
 363              unset($this->tags['q']);
 364          }
 365          if (!$this->getOpt('active_code')) {
 366              unset($this->tags['code']);
 367          }
 368          if (!$this->getOpt('active_acronym')) {
 369              unset($this->tags['acronym']);
 370          }
 371          if (!$this->getOpt('active_ins')) {
 372              unset($this->tags['ins']);
 373          }
 374          if (!$this->getOpt('active_del')) {
 375              unset($this->tags['del']);
 376          }
 377          if (!$this->getOpt('active_footnotes')) {
 378              unset($this->tags['note']);
 379          }
 380          if (!$this->getOpt('active_wikiwords')) {
 381              unset($this->tags['word']);
 382          }
 383          
 384          $this->open_tags = $this->__getTags();
 385          $this->close_tags = $this->__getTags(false);
 386          $this->all_tags = $this->__getAllTags();
 387          $this->tag_pattern = $this->__getTagsPattern();
 388          
 389          $this->escape_table = $this->all_tags;
 390          array_walk($this->escape_table,create_function('&$a','$a = \'\\\\\'.$a;'));
 391      }
 392      
 393  	function __getTags($open=true)
 394      {
 395          $res = array();
 396          foreach ($this->tags as $k => $v) {
 397              $res[$k] = ($open) ? $v[0] : $v[1];
 398          }
 399          return $res;
 400      }
 401      
 402  	function __getAllTags()
 403      {
 404          $res = array();
 405          foreach ($this->tags as $v) {
 406              $res[] = $v[0];
 407              $res[] = $v[1];
 408          }
 409          return array_values(array_unique($res));
 410      }
 411      
 412  	function __getTagsPattern($escape=false)
 413      {
 414          $res = $this->all_tags;
 415          array_walk($res,create_function('&$a','$a = preg_quote($a,"/");'));
 416          
 417          if (!$escape) {
 418              return '/(?<!\\\)('.implode('|',$res).')/';
 419          } else {
 420              return '('.implode('|',$res).')';
 421          }
 422      }
 423      
 424      /* Blocs
 425      --------------------------------------------------- */
 426  	function __parseBlocks()
 427      {
 428          $mode = $type = NULL;
 429          $res = '';
 430          $max = count($this->T);
 431          
 432          for ($i=0; $i<$max; $i++)
 433          {
 434              $pre_mode = $mode;
 435              $pre_type = $type;
 436              $end = ($i+1 == $max);
 437              
 438              $line = $this->__getLine($i,$type,$mode);
 439              
 440              if ($type != 'pre' || $this->getOpt('parse_pre')) {
 441                  $line = $this->__inlineWalk($line);
 442              }
 443              
 444              $res .= $this->__closeLine($type,$mode,$pre_type,$pre_mode);
 445              $res .= $this->__openLine($type,$mode,$pre_type,$pre_mode);
 446              
 447              # P dans les blockquotes
 448              if ($type == 'blockquote' && trim($line) == '' && $pre_type == $type) {
 449                  $res .= "</p>\n<p>";
 450              }
 451              
 452              # Correction de la syntaxe FR dans tous sauf pre et hr
 453              # Sur idée de Christophe Bonijol
 454              # Changement de regex (Nicolas Chachereau)
 455              if ($this->getOpt('active_fr_syntax') && $type != NULL && $type != 'pre' && $type != 'hr') {
 456                  $line = preg_replace('%[ ]+([:?!;\x{00BB}](\s|$))%u','&nbsp;$1',$line);
 457                  $line = preg_replace('%(\x{00AB})[ ]+%u','$1&nbsp;',$line);
 458              }
 459              
 460              $res .= $line;
 461          }
 462          
 463          return trim($res);
 464      }
 465      
 466  	function __getLine($i,&$type,&$mode)
 467      {
 468          $pre_type = $type;
 469          $pre_mode = $mode;
 470          $type = $mode = NULL;
 471          
 472          if (empty($this->T[$i])) {
 473              return false;
 474          }
 475          
 476          $line = htmlspecialchars($this->T[$i],ENT_NOQUOTES);
 477          
 478          # Ligne vide
 479          if (empty($line))
 480          {
 481              $type = NULL;
 482          }
 483          elseif ($this->getOpt('active_empty') && preg_match('/^øøø(.*)$/',$line,$cap))
 484          {
 485              $type = NULL;
 486              $line = trim($cap[1]);
 487          }
 488          # Titre
 489          elseif ($this->getOpt('active_title') && preg_match('/^([!]{1,4})(.*)$/',$line,$cap))
 490          {
 491              $type = 'title';
 492              $mode = strlen($cap[1]);
 493              $line = trim($cap[2]);
 494          }
 495          # Ligne HR
 496          elseif ($this->getOpt('active_hr') && preg_match('/^[-]{4}[- ]*$/',$line))
 497          {
 498              $type = 'hr';
 499              $line = NULL;
 500          }
 501          # Blockquote
 502          elseif ($this->getOpt('active_quote') && preg_match('/^(&gt;|;:)(.*)$/',$line,$cap))
 503          {
 504              $type = 'blockquote';
 505              $line = trim($cap[2]);
 506          }
 507          # Liste
 508          elseif ($this->getOpt('active_lists') && preg_match('/^([*#]+)(.*)$/',$line,$cap))
 509          {
 510              $type = 'list';
 511              $mode = $cap[1];
 512              $valid = true;
 513              
 514              # Vérification d'intégrité
 515              $dl = ($type != $pre_type) ? 0 : strlen($pre_mode);
 516              $d = strlen($mode);
 517              $delta = $d-$dl;
 518              
 519              if ($delta < 0 && strpos($pre_mode,$mode) !== 0) {
 520                  $valid = false;
 521              }
 522              if ($delta > 0 && $type == $pre_type && strpos($mode,$pre_mode) !== 0) {
 523                  $valid = false;
 524              }
 525              if ($delta == 0 && $mode != $pre_mode) {
 526                  $valid = false;
 527              }
 528              if ($delta > 1) {
 529                  $valid = false;
 530              }
 531              
 532              if (!$valid) {
 533                  $type = 'p';
 534                  $mode = NULL;
 535                  $line = '<br />'.$line;
 536              } else {
 537                  $line = trim($cap[2]);
 538              }
 539          }
 540          # Préformaté
 541          elseif ($this->getOpt('active_pre') && preg_match('/^[ ]{1}(.*)$/',$line,$cap))
 542          {
 543              $type = 'pre';
 544              $line = $cap[1];
 545          }
 546          # Paragraphe
 547          else {
 548              $type = 'p';
 549              $line = trim($line);
 550          }
 551          
 552          return $line;
 553      }
 554      
 555  	function __openLine($type,$mode,$pre_type,$pre_mode)
 556      {
 557          $open = ($type != $pre_type);
 558          
 559          if ($open && $type == 'p')
 560          {
 561              return "\n<p>";
 562          }
 563          elseif ($open && $type == 'blockquote')
 564          {
 565              return "\n<blockquote><p>";
 566          }
 567          elseif (($open || $mode != $pre_mode) && $type == 'title')
 568          {
 569              $fl = $this->getOpt('first_title_level');
 570              $fl = $fl+3;
 571              $l = $fl-$mode;
 572              return "\n<h".($l).'>';
 573          }
 574          elseif ($open && $type == 'pre')
 575          {
 576              return "\n<pre>";
 577          }
 578          elseif ($open && $type == 'hr')
 579          {
 580              return "\n<hr />";
 581          }
 582          elseif ($type == 'list')
 583          {
 584              $dl = ($open) ? 0 : strlen($pre_mode);
 585              $d = strlen($mode);
 586              $delta = $d-$dl;
 587              $res = '';
 588              
 589              if($delta > 0) {
 590                  if(substr($mode, -1, 1) == '*') {
 591                      $res .= "<ul>\n";
 592                  } else {
 593                      $res .= "<ol>\n";
 594                  }
 595              } elseif ($delta < 0) {
 596                  $res .= "</li>\n";
 597                  for($j = 0; $j < abs($delta); $j++) {
 598                      if (substr($pre_mode,(0 - $j - 1), 1) == '*') {
 599                          $res .= "</ul>\n</li>\n";
 600                      } else {
 601                          $res .= "</ol>\n</li>\n";
 602                      }
 603                  }
 604              } else {
 605                  $res .= "</li>\n";
 606              }
 607              
 608              return $res."<li>";
 609          }
 610          else
 611          {
 612              return NULL;
 613          }
 614      }
 615      
 616  	function __closeLine($type,$mode,$pre_type,$pre_mode)
 617      {
 618          $close = ($type != $pre_type);
 619          
 620          if ($close && $pre_type == 'p')
 621          {
 622              return "</p>\n";
 623          }
 624          elseif ($close && $pre_type == 'blockquote')
 625          {
 626              return "</p></blockquote>\n";
 627          }
 628          elseif (($close || $mode != $pre_mode) && $pre_type == 'title')
 629          {
 630              $fl = $this->getOpt('first_title_level');
 631              $fl = $fl+3;
 632              $l = $fl-$pre_mode;
 633              return '</h'.($l).">\n";
 634          }
 635          elseif ($close && $pre_type == 'pre')
 636          {
 637              return "</pre>\n";
 638          }
 639          elseif ($close && $pre_type == 'list')
 640          {
 641              $res = '';
 642              for($j = 0; $j < strlen($pre_mode); $j++) {
 643                  if(substr($pre_mode,(0 - $j - 1), 1) == '*') {
 644                      $res .= "</li>\n</ul>";
 645                  } else {
 646                      $res .= "</li>\n</ol>";
 647                  }
 648              }
 649              return $res;
 650          }
 651          else
 652          {
 653              return "\n";
 654          }
 655      }
 656      
 657      
 658      /* Inline
 659      --------------------------------------------------- */
 660  	function __inlineWalk($str,$allow_only=NULL)
 661      {
 662          $tree = preg_split($this->tag_pattern,$str,-1,PREG_SPLIT_DELIM_CAPTURE);
 663          
 664          $res = '';
 665          for ($i=0; $i<count($tree); $i++)
 666          {
 667              $attr = '';
 668              
 669              if (in_array($tree[$i],array_values($this->open_tags)) &&
 670              ($allow_only == NULL || in_array(array_search($tree[$i],$this->open_tags),$allow_only)))
 671              {
 672                  $tag = array_search($tree[$i],$this->open_tags);
 673                  $tag_type = 'open';
 674                  
 675                  if (($tidy = $this->__makeTag($tree,$tag,$i,$i,$attr,$tag_type)) !== false)
 676                  {
 677                      if ($tag != '') {
 678                          $res .= '<'.$tag.$attr;
 679                          $res .= ($tag_type == 'open') ? '>' : ' />';
 680                      }
 681                      $res .= $tidy;
 682                  }
 683                  else
 684                  {
 685                      $res .= $tree[$i];
 686                  }
 687              }
 688              else
 689              {
 690                  $res .= $tree[$i];
 691              }
 692          }
 693          
 694          # Suppression des echappements
 695          $res = str_replace($this->escape_table,$this->all_tags,$res);
 696          
 697          return $res;
 698      }
 699      
 700  	function __makeTag(&$tree,&$tag,$position,&$j,&$attr,&$type)
 701      {
 702          $res = '';
 703          $closed = false;
 704          
 705          $itag = $this->close_tags[$tag];
 706          
 707          # Recherche fermeture
 708          for ($i=$position+1;$i<count($tree);$i++)
 709          {
 710              if ($tree[$i] == $itag)
 711              {
 712                  $closed = true;
 713                  break;
 714              }
 715          }
 716          
 717          # Résultat
 718          if ($closed)
 719          {
 720              for ($i=$position+1;$i<count($tree);$i++)
 721              {
 722                  if ($tree[$i] != $itag)
 723                  {
 724                      $res .= $tree[$i];
 725                  }
 726                  else
 727                  {
 728                      switch ($tag)
 729                      {
 730                          case 'a':
 731                              $res = $this->__parseLink($res,$tag,$attr,$type);
 732                              break;
 733                          case 'img':
 734                              $type = 'close';
 735                              $res = $this->__parseImg($res,$attr);
 736                              break;
 737                          case 'acronym':
 738                              $res = $this->__parseAcronym($res,$attr);
 739                              break;
 740                          case 'q':
 741                              $res = $this->__parseQ($res,$attr);
 742                              break;
 743                          case 'anchor':
 744                              $tag = 'a';
 745                              $res = $this->__parseAnchor($res,$attr);
 746                              break;
 747                          case 'note':
 748                              $tag = '';
 749                              $res = $this->__parseNote($res);
 750                              break;
 751                          case 'word':
 752                              $res = $this->parseWikiWord($res,$tag,$attr,$type);
 753                              break;
 754                          default :
 755                              $res = $this->__inlineWalk($res);
 756                              break;
 757                      }
 758                      
 759                      if ($type == 'open' && $tag != '') {
 760                          $res .= '</'.$tag.'>';
 761                      }
 762                      $j = $i;
 763                      break;
 764                  }
 765              }
 766              
 767              return $res;
 768          }
 769          else
 770          {
 771              return false;
 772          }
 773      }
 774      
 775  	function __splitTagsAttr($str)
 776      {
 777          $res = preg_split('/(?<!\\\)\|/',$str);
 778          
 779          foreach ($res as $k => $v) {
 780              $res[$k] = str_replace("\|",'|',$v);
 781          }
 782          
 783          return $res;
 784      }
 785      
 786      # Antispam (Jérôme Lipowicz)
 787  	function __antiSpam($str)
 788      {
 789          $encoded = bin2hex($str);
 790          $encoded = chunk_split($encoded, 2, '%');
 791          $encoded = '%'.substr($encoded, 0, strlen($encoded) - 1);
 792          return $encoded;
 793      }
 794      
 795  	function __parseLink($str,&$tag,&$attr,&$type)
 796      {
 797          $n_str = $this->__inlineWalk($str,array('acronym','img'));
 798          $data = $this->__splitTagsAttr($n_str);
 799          $no_image = false;
 800          
 801          # Only URL in data
 802          if (count($data) == 1)
 803          {
 804              $url = trim($str);
 805              $content = strlen($url) > 35 ? substr($url,0,35).'...' : $url;
 806              $lang = '';
 807              $title = $url;
 808          }
 809          elseif (count($data) > 1)
 810          {
 811              $url = trim($data[1]);
 812              $content = $data[0];
 813              $lang = (!empty($data[2])) ? $this->protectAttr($data[2],true) : '';
 814              $title = (!empty($data[3])) ? $data[3] : '';
 815              $no_image = (!empty($data[4])) ? (boolean) $data[4] : false;
 816          }
 817          
 818          # Remplacement si URL spéciale
 819          $this->__specialUrls($url,$content,$lang,$title);        
 820          
 821          # On vire les &nbsp; dans l'url
 822          $url = str_replace('&nbsp;',' ',$url);
 823          
 824          if (ereg('^(.+)[.](gif|jpg|jpeg|png)$', $url) && !$no_image && $this->getOpt('active_auto_img'))
 825          {
 826              # On ajoute les dimensions de l'image si locale
 827              # Idée de Stephanie
 828              $img_size = NULL;
 829              if (!ereg('[a-zA-Z]+://', $url)) {
 830                  if (ereg('^/',$url)) {
 831                      $path_img = $_SERVER['DOCUMENT_ROOT'] . $url;
 832                  } else {
 833                      $path_img = $url;
 834                  }
 835                  
 836                  $img_size = @getimagesize($path_img);
 837              }
 838              
 839              $attr = ' src="'.$this->protectAttr($this->protectUrls($url)).'"'.
 840              $attr .= (count($data) > 1) ? ' alt="'.$this->protectAttr($content).'"' : ' alt=""';
 841              $attr .= ($lang) ? ' lang="'.$lang.'"' : '';
 842              $attr .= ($title) ? ' title="'.$this->protectAttr($title).'"' : '';
 843              $attr .= (is_array($img_size)) ? ' '.$img_size[3] : '';
 844              
 845              $tag = 'img';
 846              $type = 'close';
 847              return NULL;
 848          }
 849          else
 850          {
 851              if ($this->getOpt('active_antispam') && preg_match('/^mailto:/',$url)) {
 852                  $content = $content == $url ? preg_replace('%^mailto:%','',$content) : $content;
 853                  $url = 'mailto:'.$this->__antiSpam(substr($url,7));
 854                  
 855              }
 856              
 857              $attr = ' href="'.$this->protectAttr($this->protectUrls($url)).'"';
 858              $attr .= ($lang) ? ' hreflang="'.$lang.'"' : '';
 859              $attr .= ($title) ? ' title="'.$this->protectAttr($title).'"' : '';
 860              
 861              return $content;
 862          }
 863      }
 864      
 865  	function __specialUrls(&$url,&$content,&$lang,&$title)
 866      {
 867          foreach ($this->functions as $k => $v)
 868          {
 869              if (strpos($k,'url:') === 0 && strpos($url,substr($k,4)) === 0)
 870              {
 871                  $res = call_user_func($v,$url,$content);
 872                  
 873                  $url = isset($res['url']) ? $res['url'] : $url;
 874                  $content = isset($res['content']) ? $res['content'] : $content;
 875                  $lang = isset($res['lang']) ? $res['lang'] : $lang;
 876                  $title = isset($res['title']) ? $res['title'] : $title;
 877                  
 878                  break;
 879              }
 880          }
 881      }
 882      
 883  	function __parseImg($str,&$attr)
 884      {
 885          $data = $this->__splitTagsAttr($str);
 886          
 887          $alt = '';
 888          $url = $data[0];
 889          if (!empty($data[1])) {
 890              $alt = $data[1];
 891          }
 892          
 893          $attr = ' src="'.$this->protectAttr($this->protectUrls($url)).'"';
 894          $attr .= ' alt="'.$this->protectAttr($alt).'"';
 895          
 896          if (!empty($data[2])) {
 897              $data[2] = strtoupper($data[2]);
 898              if ($data[2] == 'G' || $data[2] == 'L') {
 899                  $attr .= ' style="float:left; margin: 0 1em 1em 0;"';
 900              } elseif ($data[2] == 'D' || $data[2] == 'R') {
 901                  $attr .= ' style="float:right; margin: 0 0 1em 1em;"';
 902              } elseif ($data[2] == 'C') {
 903                  $attr .= ' style="display:block; margin:0 auto;"';
 904              }
 905          }
 906          
 907          if (!empty($data[3])) {
 908              $attr .= ' longdesc="'.$this->protectAttr($data[3]).'"';
 909          }
 910          
 911          return NULL;
 912      }
 913      
 914  	function __parseQ($str,&$attr)
 915      {
 916          $str = $this->__inlineWalk($str);
 917          $data = $this->__splitTagsAttr($str);
 918          
 919          $content = $data[0];
 920          $lang = (!empty($data[1])) ? $this->protectAttr($data[1],true) : '';
 921          
 922          $attr .= (!empty($lang)) ? ' lang="'.$lang.'"' : '';
 923          $attr .= (!empty($data[2])) ? ' cite="'.$this->protectAttr($this->protectUrls($data[2])).'"' : '';
 924          
 925          return $content;
 926      }
 927      
 928  	function __parseAnchor($str,&$attr)
 929      {
 930          $name = $this->protectAttr($str,true);
 931          
 932          if ($name != '') {
 933              $attr = ' name="'.$name.'"';
 934          }
 935          return null;
 936      }
 937      
 938  	function __parseNote($str)
 939      {
 940          $i = count($this->foot_notes)+1;
 941          $id = $this->getOpt('note_prefix').'-'.$i;
 942          $this->foot_notes[$id] = $this->__inlineWalk($str);
 943          return '<sup>\[<a href="#'.$id.'" id="rev-'.$id.'">'.$i.'</a>\]</sup>';
 944      }
 945      
 946      # Obtenir un acronyme
 947  	function __parseAcronym($str,&$attr)
 948      {
 949          $data = $this->__splitTagsAttr($str);
 950          
 951          $acronym = $data[0];
 952          $title = $lang = '';
 953          
 954          if (count($data) > 1)
 955          {
 956              $title = $data[1];
 957              $lang = (!empty($data[2])) ? $this->protectAttr($data[2],true) : '';
 958          }
 959          
 960          if ($title == '' && !empty($this->acro_table[$acronym])) {
 961              $title = $this->acro_table[$acronym];
 962          }
 963          
 964          $attr = ($title) ? ' title="'.$this->protectAttr($title).'"' : '';
 965          $attr .= ($lang) ? ' lang="'.$lang.'"' : '';
 966          
 967          return $acronym;
 968      }
 969      
 970      # Définition des acronymes, dans le fichier acronyms.txt
 971  	function __getAcronyms()
 972      {
 973          $file = $this->getOpt('acronyms_file');
 974          $res = array();
 975          
 976          if (file_exists($file))
 977          {
 978              if (($fc = @file($file)) !== false)
 979              {
 980                  foreach ($fc as $v)
 981                  {
 982                      $v = trim($v);
 983                      if ($v != '')
 984                      {
 985                          $p = strpos($v,':');
 986                          $K = (string) trim(substr($v,0,$p));
 987                          $V = (string) trim(substr($v,($p+1)));
 988                          
 989                          if ($K) {
 990                              $res[$K] = $V;
 991                          }
 992                      }
 993                  }
 994              }
 995          }
 996          
 997          return $res;
 998      }
 999      
1000      # Mots wiki (pour héritage)
1001  	function parseWikiWord($str,&$tag,&$attr,&$type)
1002      {
1003          $tag = $attr = '';
1004          
1005          if (isset($this->functions['wikiword'])) {
1006              return call_user_func($this->functions['wikiword'],$str);
1007          }
1008          
1009          return $str;
1010      }
1011      
1012      /* Protection des attributs */
1013  	function protectAttr($str,$name=false)
1014      {
1015          if ($name && !preg_match('/^[A-Za-z][A-Za-z0-9_:.-]*$/',$str)) {
1016              return '';
1017          }
1018          
1019          return str_replace(array("'",'"'),array('&#039;','&quot;'),$str);
1020      }
1021      
1022      /* Protection des urls */
1023  	function protectUrls($str)
1024      {
1025          if (preg_match('/^javascript:/',$str)) {
1026              $str = '#';
1027          }
1028          
1029          return $str;
1030      }
1031      
1032      /* Auto BR */
1033  	function __autoBR($m)
1034      {
1035          return $m[1].str_replace("\n","<br />\n",$m[2]).$m[3];
1036      }
1037      
1038      /* Macro
1039      --------------------------------------------------- */
1040  	function __getMacro($s)
1041      {
1042          $this->macros[] = str_replace('\"','"',$s);
1043          return 'øøø##########MACRO#'.(count($this->macros)-1).'#';
1044      }
1045      
1046  	function __putMacro($id)
1047      {
1048          $id = (integer) $id;
1049          if (isset($this->macros[$id]))
1050          {
1051              $content = str_replace("\r",'',$this->macros[$id]);
1052              
1053              $c = explode("\n",$content);
1054                          
1055              # première ligne, premier mot
1056              $fl = trim($c[0]);
1057              $fw = $fl;
1058              
1059              if ($fl) {
1060                  if (strpos($fl,' ') !== false) {
1061                      $fw = substr($fl,0,strpos($fl,' '));
1062                  }
1063                  $content = implode("\n",array_slice($c,1));
1064              }
1065              
1066              if ($c[0] == "\n") {
1067                  $content = implode("\n",array_slice($c,1));
1068              }
1069              
1070              if ($fw)
1071              {
1072                  if (isset($this->functions['macro:'.$fw]))
1073                  {
1074                      return call_user_func($this->functions['macro:'.$fw],$content,$fl);
1075                  }
1076              }
1077              
1078              # Si on n'a rien pu faire, on retourne le tout sous
1079              # forme de <pre>
1080              return '<pre>'.htmlspecialchars($this->macros[$id]).'</pre>';
1081          }
1082          
1083          return null;
1084      }
1085      
1086  	function __macroHTML($s)
1087      {
1088          return $s;
1089      }
1090      
1091      /* Aide et debug
1092      --------------------------------------------------- */
1093  	function help()
1094      {
1095          $help['b'] = array();
1096          $help['i'] = array();
1097          
1098          $help['b'][] = 'Laisser une ligne vide entre chaque bloc <em>de même nature</em>.';
1099          $help['b'][] = '<strong>Paragraphe</strong> : du texte et une ligne vide';
1100          
1101          if ($this->getOpt('active_title')) {
1102              $help['b'][] = '<strong>Titre</strong> : <code>!!!</code>, <code>!!</code>, '.
1103              '<code>!</code> pour des titres plus ou moins importants';
1104          }
1105          
1106          if ($this->getOpt('active_hr')) {
1107              $help['b'][] = '<strong>Trait horizontal</strong> : <code>----</code>';
1108          }
1109          
1110          if ($this->getOpt('active_lists')) {
1111              $help['b'][] = '<strong>Liste</strong> : ligne débutant par <code>*</code> ou '.
1112              '<code>#</code>. Il est possible de mélanger les listes '.
1113              '(<code>*#*</code>) pour faire des listes de plusieurs niveaux. '.
1114              'Respecter le style de chaque niveau';
1115          }
1116          
1117          if ($this->getOpt('active_pre')) {
1118              $help['b'][] = '<strong>Texte préformaté</strong> : espace devant chaque ligne de texte';
1119          }
1120          
1121          if ($this->getOpt('active_quote')) {
1122              $help['b'][] = '<strong>Bloc de citation</strong> : <code>&gt;</code> ou '.
1123              '<code>;:</code> devant chaque ligne de texte';
1124          }
1125          
1126          if ($this->getOpt('active_fr_syntax')) {
1127              $help['i'][] = 'La correction de ponctuation est active. Un espace '.
1128                          'insécable remplacera automatiquement tout espace '.
1129                          'précédant les marques ";","?",":" et "!".';
1130          }
1131          
1132          if ($this->getOpt('active_em')) {
1133              $help['i'][] = '<strong>Emphase</strong> : deux apostrophes <code>\'\'texte\'\'</code>';
1134          }
1135          
1136          if ($this->getOpt('active_strong')) {
1137              $help['i'][] = '<strong>Forte emphase</strong> : deux soulignés <code>__texte__</code>';
1138          }
1139          
1140          if ($this->getOpt('active_br')) {
1141              $help['i'][] = '<strong>Retour forcé à la ligne</strong> : <code>%%%</code>';
1142          }
1143          
1144          if ($this->getOpt('active_ins')) {
1145              $help['i'][] = '<strong>Insertion</strong> : deux plus <code>++texte++</code>';
1146          }
1147          
1148          if ($this->getOpt('active_del')) {
1149              $help['i'][] = '<strong>Suppression</strong> : deux moins <code>--texte--</code>';
1150          }
1151          
1152          if ($this->getOpt('active_urls')) {
1153              $help['i'][] = '<strong>Lien</strong> : <code>[url]</code>, <code>[nom|url]</code>, '.
1154              '<code>[nom|url|langue]</code> ou <code>[nom|url|langue|titre]</code>.';
1155              
1156              $help['i'][] = '<strong>Image</strong> : comme un lien mais avec une extension d\'image.'.
1157              '<br />Pour désactiver la reconnaissance d\'image mettez 0 dans un dernier '.
1158              'argument. Par exemple <code>[image|image.gif||0]</code> fera un lien vers l\'image au '.
1159              'lieu de l\'afficher.'.
1160              '<br />Il est conseillé d\'utiliser la nouvelle syntaxe.';
1161          }
1162          
1163          if ($this->getOpt('active_img')) {
1164              $help['i'][] = '<strong>Image</strong> (nouvelle syntaxe) : '.
1165              '<code>((url|texte alternatif))</code>, '.
1166              '<code>((url|texte alternatif|position))</code> ou '.
1167              '<code>((url|texte alternatif|position|description longue))</code>. '.
1168              '<br />La position peut prendre les valeur L ou G (gauche), R ou D (droite) ou C (centré).';
1169          }
1170          
1171          if ($this->getOpt('active_anchor')) {
1172              $help['i'][] = '<strong>Ancre</strong> : <code>~ancre~</code>';
1173          }
1174          
1175          if ($this->getOpt('active_acronym')) {
1176              $help['i'][] = '<strong>Acronyme</strong> : <code>??acronyme??</code> ou '.
1177              '<code>??acronyme|titre??</code>';
1178          }
1179          
1180          if ($this->getOpt('active_q')) {
1181              $help['i'][] = '<strong>Citation</strong> : <code>{{citation}}</code>, '.
1182              '<code>{{citation|langue}}</code> ou <code>{{citation|langue|url}}</code>';
1183          }
1184          
1185          if ($this->getOpt('active_code')) {
1186              $help['i'][] = '<strong>Code</strong> : <code>@@code ici@@</code>';
1187          }
1188          
1189          if ($this->getOpt('active_footnotes')) {
1190              $help['i'][] = '<strong>Note de bas de page</strong> : <code>$$Corps de la note$$</code>';
1191          }
1192          
1193          $res = '<dl class="wikiHelp">';
1194          
1195          $res .= '<dt>Blocs</dt><dd>';
1196          if (count($help['b']) > 0)
1197          {
1198              $res .= '<ul><li>';
1199              $res .= implode('&nbsp;;</li><li>', $help['b']);
1200              $res .= '.</li></ul>';
1201          }
1202          $res .= '</dd>';
1203          
1204          $res .= '<dt>Éléments en ligne</dt><dd>';
1205          if (count($help['i']) > 0)
1206          {
1207              $res .= '<ul><li>';
1208              $res .= implode('&nbsp;;</li><li>', $help['i']);
1209              $res .= '.</li></ul>';
1210          }
1211          $res .= '</dd>';
1212          
1213          $res .= '</dl>';
1214          
1215          return $res;    
1216      }
1217      
1218      /*
1219      function debug()
1220      {
1221          $mode = $type = NULL;
1222          $max = count($this->T);
1223          
1224          $res =
1225          '<table border="1">'.
1226          '<tr><th>p-mode</th><th>p-type</th><th>mode</th><th>type</th><th>chaine</th></tr>';
1227          
1228          for ($i=0; $i<$max; $i++)
1229          {
1230              $pre_mode = $mode;
1231              $pre_type = $type;
1232              
1233              $line = $this->__getLine($i,$type,$mode);
1234              
1235              $res .=
1236              '<tr><td>'.$pre_mode.'</td><td>'.$pre_type.'</td>'.
1237              '<td>'.$mode.'</td><td>'.$type.'</td><td>'.$line.'</td></tr>';
1238              
1239          }
1240          $res .= '</table>';
1241          
1242          return $res;
1243      }
1244      //*/
1245  }
1246  
1247  ?>


Généré le : Fri Feb 23 22:16:06 2007 par Balluche grâce à PHPXref 0.7