2 /////////////////////////////////////////////////
3 // PukiWiki - Yet another WikiWikiWeb clone.
5 // $Id: make_link.php,v 1.3 2004/10/13 15:08:35 henoheno Exp $
9 function make_link($string, $page = '')
14 if (! isset($converter)) $converter = new InlineConverter();
16 $clone = $converter->get_clone($converter);
18 return $clone->convert($string, ($page != '') ? $page : $vars['page']);
21 //¥¤¥ó¥é¥¤¥óÍ×ÁǤòÃÖ´¹¤¹¤ë
24 var $converters; // as array()
29 function get_clone($obj) {
32 if (! isset($clone_func)) {
33 if (version_compare(PHP_VERSION, '5.0.0', '<')) {
34 $clone_func = create_function('$a', 'return $a;');
36 $clone_func = create_function('$a', 'return clone $a;');
39 return $clone_func($obj);
43 $converters = array();
44 foreach ($this->converters as $key=>$converter) {
45 $converters[$key] = $this->get_clone($converter);
47 $this->converters = $converters;
50 function InlineConverter($converters = NULL, $excludes = NULL)
52 if ($converters === NULL) {
54 'plugin', // ¥¤¥ó¥é¥¤¥ó¥×¥é¥°¥¤¥ó
57 'url_interwiki', // URL (interwiki definition)
59 'interwikiname', // InterWikiName
60 'autolink', // AutoLink
61 'bracketname', // BracketName
62 'wikiname', // WikiName
63 'autolink_a', // AutoLink(¥¢¥ë¥Õ¥¡¥Ù¥Ã¥È)
67 if ($excludes !== NULL)
68 $converters = array_diff($converters, $excludes);
70 $this->converters = $patterns = array();
73 foreach ($converters as $name) {
74 $classname = "Link_$name";
75 $converter = new $classname($start);
76 $pattern = $converter->get_pattern();
77 if ($pattern === FALSE) continue;
79 $patterns[] = "(\n$pattern\n)";
80 $this->converters[$start] = $converter;
81 $start += $converter->get_count();
84 $this->pattern = join('|', $patterns);
87 function convert($string, $page)
90 $this->result = array();
92 $string = preg_replace_callback("/{$this->pattern}/x",
93 array(& $this, 'replace'), $string);
95 $arr = explode("\x08", make_line_rules(htmlspecialchars($string)));
97 while (! empty($arr)) {
98 $retval .= array_shift($arr) . array_shift($this->result);
103 function replace($arr)
105 $obj = $this->get_converter($arr);
107 $this->result[] = ($obj !== NULL && $obj->set($arr, $this->page) !== FALSE) ?
108 $obj->toString() : make_line_rules(htmlspecialchars($arr[0]));
110 return "\x08"; //½èÍýºÑ¤ß¤ÎÉôʬ¤Ë¥Þ¡¼¥¯¤òÆþ¤ì¤ë
113 function get_objects($string, $page)
115 preg_match_all("/{$this->pattern}/x", $string, $matches, PREG_SET_ORDER);
118 foreach ($matches as $match) {
119 $obj = $this->get_converter($match);
120 if ($obj->set($match, $page) !== FALSE) {
121 $arr[] = $this->get_clone($obj);
122 if ($obj->body != '')
123 $arr = array_merge($arr, $this->get_objects($obj->body, $page));
129 function & get_converter(& $arr)
131 foreach (array_keys($this->converters) as $start) {
132 if ($arr[$start] == $arr[0])
133 return $this->converters[$start];
139 //¥¤¥ó¥é¥¤¥óÍ×Áǽ¸¹ç¤Î¥Ù¡¼¥¹¥¯¥é¥¹
142 var $start; // ³ç¸Ì¤ÎÀèƬÈÖ¹æ(0¥ª¥ê¥¸¥ó)
143 var $text; // ¥Þ¥Ã¥Á¤·¤¿Ê¸»úÎóÁ´ÂÎ
152 function Link($start)
154 $this->start = $start;
157 // ¥Þ¥Ã¥Á¤Ë»ÈÍѤ¹¤ë¥Ñ¥¿¡¼¥ó¤òÊÖ¤¹
158 function get_pattern() {}
160 // »ÈÍѤ·¤Æ¤¤¤ë³ç¸Ì¤Î¿ô¤òÊÖ¤¹ ((?:...)¤ò½ü¤¯)
161 function get_count() {}
163 // ¥Þ¥Ã¥Á¤·¤¿¥Ñ¥¿¡¼¥ó¤òÀßÄꤹ¤ë
164 function set($arr,$page) {}
167 function toString() {}
170 // ¥Þ¥Ã¥Á¤·¤¿ÇÛÎ󤫤顢¼«Ê¬¤ËɬÍפÊÉôʬ¤À¤±¤ò¼è¤ê½Ð¤¹
171 function splice($arr) {
172 $count = $this->get_count() + 1;
173 $arr = array_pad(array_splice($arr, $this->start, $count), $count, '');
174 $this->text = $arr[0];
178 // ´ðËܥѥé¥á¡¼¥¿¤òÀßÄꤹ¤ë
179 function setParam($page, $name, $body, $type = '', $alias = '')
181 static $converter = NULL;
187 if ($type != 'InterWikiName' && preg_match('/\.(gif|png|jpe?g)$/i', $alias)) {
188 $alias = htmlspecialchars($alias);
189 $alias = "<img src=\"$alias\" alt=\"$name\" />";
190 } else if ($alias != '') {
191 if ($converter === NULL)
192 $converter = new InlineConverter(array('plugin'));
193 $alias = make_line_rules($converter->convert($alias, $page));
195 $this->alias = $alias;
201 // ¥¤¥ó¥é¥¤¥ó¥×¥é¥°¥¤¥ó
202 class Link_plugin extends Link
207 function Link_plugin($start)
209 parent::Link($start);
212 function get_pattern()
214 $this->pattern = <<<EOD
217 (\w+) # (2) plugin name
220 ((?:(?!\)[;{]).)*) # (3) parameter
229 ((?:(?R)|(?!};).)*) # (4) body
241 function set($arr, $page)
243 list($all, $this->plain, $name, $this->param, $body) = $this->splice($arr);
245 // ËÜÍè¤Î¥×¥é¥°¥¤¥ó̾¤ª¤è¤Ó¥Ñ¥é¥á¡¼¥¿¤ò¼èÆÀ¤·¤Ê¤ª¤¹ PHP4.1.2 (?R)Âкö
246 if (preg_match("/^{$this->pattern}/x", $all, $matches)
247 && $matches[1] != $this->plain)
249 list(, $this->plain, $name, $this->param) = $matches;
251 return parent::setParam($page, $name, $body, 'plugin');
256 $body = ($this->body == '') ? '' : make_link($this->body);
258 // ¥×¥é¥°¥¤¥ó¸Æ¤Ó½Ð¤·
259 if (exist_plugin_inline($this->name)) {
260 $str = do_plugin_inline($this->name, $this->param, $body);
261 if ($str !== FALSE) //À®¸ù
265 // ¥×¥é¥°¥¤¥ó¤¬Â¸ºß¤·¤Ê¤¤¤«¡¢ÊÑ´¹¤Ë¼ºÇÔ
266 $body = ($body == '') ? ';' : "\{$body};";
267 return make_line_rules(htmlspecialchars('&' . $this->plain) . $body);
272 class Link_note extends Link
274 function Link_note($start)
276 parent::Link($start);
279 function get_pattern()
283 ((?:(?R)|(?!\)\)).)*) # (1) note body
293 function set($arr, $page)
295 global $foot_explain;
298 list(, $body) = $this->splice($arr);
301 $note = make_link($body);
303 $foot_explain[$id] = <<<EOD
304 <a id="notefoot_$id" href="#notetext_$id" class="note_super">*$id</a>
305 <span class="small">$note</span>
308 $name = "<a id=\"notetext_$id\" href=\"#notefoot_$id\" class=\"note_super\">*$id</a>";
310 return parent::setParam($page, $name, $body);
320 class Link_url extends Link
322 function Link_url($start)
324 parent::Link($start);
327 function get_pattern()
329 $s1 = $this->start + 1;
331 (\[\[ # (1) open bracket
332 ((?:(?!\]\]).)+) # (2) alias
336 (?:https?|ftp|news):\/\/[!~*'();\/?:\@&=+\$,%#\w.-]+
338 (?($s1)\]\]) # close bracket
347 function set($arr, $page)
349 list(, , $alias, $name) = $this->splice($arr);
350 return parent::setParam($page, htmlspecialchars($name),
351 '', 'url', $alias == '' ? $name : $alias);
356 return "<a href=\"{$this->name}\">{$this->alias}</a>";
360 // url (InterWiki definition type)
361 class Link_url_interwiki extends Link
363 function Link_url_interwiki($start)
365 parent::Link($start);
368 function get_pattern()
373 (?:(?:https?|ftp|news):\/\/|\.\.?\/)[!~*'();\/?:\@&=+\$,%#\w.-]*
386 function set($arr, $page)
388 list(, $name, $alias) = $this->splice($arr);
389 return parent::setParam($page, htmlspecialchars($name), '', 'url', $alias);
394 return "<a href=\"{$this->name}\">{$this->alias}</a>";
399 class Link_mailto extends Link
401 var $is_image, $image;
403 function Link_mailto($start)
405 parent::Link($start);
408 function get_pattern()
410 $s1 = $this->start + 1;
414 ((?:(?!\]\]).)+)(?:>|:) # (1) alias
416 ([\w.-]+@[\w-]+\.[\w.-]+) # (2) mailto
417 (?($s1)\]\]) # close bracket if (1)
426 function set($arr, $page)
428 list(, $alias, $name) = $this->splice($arr);
429 return parent::setParam($page, $name, '', 'mailto', $alias == '' ? $name : $alias);
434 return "<a href=\"mailto:{$this->name}\">{$this->alias}</a>";
439 class Link_interwikiname extends Link
445 function Link_interwikiname($start)
447 parent::Link($start);
450 function get_pattern()
452 $s2 = $this->start + 2;
453 $s5 = $this->start + 5;
457 ((?:(?!\]\]).)+)> # (1) alias
459 (\[\[)? # (2) open bracket
460 ((?:(?!\s|:|\]\]).)+) # (3) InterWiki
461 (?<! > | >\[\[ ) # not '>' or '>[['
464 (\[\[)? # (5) open bracket
466 (?($s5)\]\]) # close bracket if (5)
468 (?($s2)\]\]) # close bracket if (2)
478 function set($arr, $page)
482 list(, $alias, , $name, $this->param) = $this->splice($arr);
484 if (preg_match('/^([^#]+)(#[A-Za-z][\w-]*)$/', $this->param, $matches))
485 list(, $this->param, $this->anchor) = $matches;
487 $url = get_interwiki_url($name, $this->param);
488 $this->url = ($url === FALSE) ?
489 $script . '?' . rawurlencode('[[' . $name . ':' . $this->param . ']]') :
490 htmlspecialchars($url);
492 return parent::setParam(
494 htmlspecialchars($name . ':' . $this->param),
497 $alias == '' ? $name . ':' . $this->param : $alias
503 return "<a href=\"{$this->url}{$this->anchor}\" title=\"{$this->name}\">{$this->alias}</a>";
508 class Link_bracketname extends Link
512 function Link_bracketname($start)
514 parent::Link($start);
517 function get_pattern()
519 global $WikiName, $BracketName;
521 $s2 = $this->start + 2;
524 (?:((?:(?!\]\]).)+)>)? # (1) alias
525 (\[\[)? # (2) open bracket
531 (\#(?:[a-zA-Z][\w-]*)?)? # (4) anchor
532 (?($s2)\]\]) # close bracket if (2)
542 function set($arr, $page)
546 list(, $alias, , $name, $this->anchor) = $this->splice($arr);
548 if ($name == '' && $this->anchor == '') return FALSE;
550 if ($name == '' || ! preg_match("/^$WikiName$/", $name)) {
552 if ($alias == '') $alias = $name . $this->anchor;
555 $name = get_fullname($name, $page);
556 if (! is_pagename($name)) return FALSE;
560 return parent::setParam($page, $name, '', 'pagename', $alias);
565 return make_pagelink(
575 class Link_wikiname extends Link
577 function Link_wikiname($start)
579 parent::Link($start);
582 function get_pattern()
584 global $WikiName, $nowikiname;
586 return $nowikiname ? FALSE : '(' . $WikiName . ')';
594 function set($arr, $page)
596 list($name) = $this->splice($arr);
597 return parent::setParam($page, $name, '', 'pagename', $name);
602 return make_pagelink(
612 class Link_autolink extends Link
614 var $forceignorepages = array();
616 var $auto_a; // alphabet only
618 function Link_autolink($start)
622 parent::Link($start);
624 if (! $autolink || ! file_exists(CACHE_DIR . 'autolink.dat'))
627 @list($auto, $auto_a, $forceignorepages) = file(CACHE_DIR . 'autolink.dat');
629 $this->auto_a = $auto_a;
630 $this->forceignorepages = explode("\t", trim($forceignorepages));
633 function get_pattern()
635 return isset($this->auto) ? "({$this->auto})" : FALSE;
643 function set($arr, $page)
647 list($name) = $this->splice($arr);
649 // ̵»ë¥ê¥¹¥È¤Ë´Þ¤Þ¤ì¤Æ¤¤¤ë¡¢¤¢¤ë¤¤¤Ï¸ºß¤·¤Ê¤¤¥Ú¡¼¥¸¤ò¼Î¤Æ¤ë
650 if (in_array($name, $this->forceignorepages) || ! is_page($name))
653 return parent::setParam($page, $name, '', 'pagename', $name);
658 return make_pagelink(
667 class Link_autolink_a extends Link_autolink
669 function Link_autolink_a($start)
671 parent::Link_autolink($start);
674 function get_pattern()
676 return isset($this->auto_a) ? '(' . $this->auto_a . ')' : FALSE;
680 // ¥Ú¡¼¥¸Ì¾¤Î¥ê¥ó¥¯¤òºîÀ®
681 function make_pagelink($page, $alias = '', $anchor = '', $refer = '')
683 global $script, $vars, $show_title, $show_passage, $link_compact, $related;
684 global $_symbol_noexists;
686 $s_page = htmlspecialchars(strip_bracket($page));
687 $s_alias = ($alias == '') ? $s_page : $alias;
689 if ($page == '') return "<a href=\"$anchor\">$s_alias</a>";
691 $r_page = rawurlencode($page);
692 $r_refer = ($refer == '') ? '' : '&refer=' . rawurlencode($refer);
694 if (! isset($related[$page]) && $page != $vars['page'] && is_page($page))
695 $related[$page] = get_filetime($page);
697 if (is_page($page)) {
698 $passage = get_pg_passage($page, FALSE);
699 $title = $link_compact ? '' : " title=\"$s_page$passage\"";
700 return "<a href=\"$script?$r_page$anchor\"$title>$s_alias</a>";
702 $retval = "$s_alias<a href=\"$script?cmd=edit&page=$r_page$r_refer\">$_symbol_noexists</a>";
704 $retval = "<span class=\"noexists\">$retval</span>";
710 function get_fullname($name, $refer)
714 if ($name == '') return $refer;
716 if ($name{0} == '/') {
717 $name = substr($name, 1);
718 return ($name == '') ? $defaultpage : $name;
721 if ($name == './') return $refer;
722 if (substr($name, 0, 2) == './') {
723 $arrn = preg_split('/\//', $name, -1, PREG_SPLIT_NO_EMPTY);
725 return join('/', $arrn);
728 if (substr($name, 0, 3) == '../') {
729 $arrn = preg_split('/\//', $name, -1, PREG_SPLIT_NO_EMPTY);
730 $arrp = preg_split('/\//', $refer, -1, PREG_SPLIT_NO_EMPTY);
732 while (! empty($arrn) && $arrn[0] == '..') {
736 $name = ! empty($arrp) ? join('/', array_merge($arrp, $arrn)) :
737 (! empty($arrn) ? "$defaultpage/" . join('/', $arrn) : $defaultpage);
743 // InterWikiName¤òŸ³«
744 function get_interwiki_url($name, $param)
746 global $WikiName, $interwiki;
747 static $interwikinames;
748 static $encode_aliases = array('sjis'=>'SJIS', 'euc'=>'EUC-JP', 'utf8'=>'UTF-8');
750 if (! isset($interwikinames)) {
751 $interwikinames = array();
752 foreach (get_source($interwiki) as $line) {
753 if (preg_match('/\[((?:(?:https?|ftp|news):\/\/|\.\.?\/)[!~*\'();\/?:\@&=+\$,%#\w.-]*)\s([^\]]+)\]\s?([^\s]*)/', $line, $matches))
754 $interwikinames[$matches[2]] = array($matches[1], $matches[3]);
758 if (! isset($interwikinames[$name])) return FALSE;
760 list($url,$opt) = $interwikinames[$name];
762 // ʸ»ú¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°
766 case 'std': // ÆâÉôʸ»ú¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤Î¤Þ¤ÞURL¥¨¥ó¥³¡¼¥É
767 $param = rawurlencode($param);
772 // $param = htmlspecialchars($param);
775 case 'yw': // YukiWiki
776 if (! preg_match("/$WikiName/", $param))
777 $param = '[[' . mb_convert_encoding($param, 'SJIS', SOURCE_ENCODING) . ']]';
778 // $param = htmlspecialchars($param);
781 case 'moin': // MoinMoin
782 $param = str_replace('%', '_', rawurlencode($param));
787 if (isset($encode_aliases[$opt])) $opt = $encode_aliases[$opt];
788 // »ØÄꤵ¤ì¤¿Ê¸»ú¥³¡¼¥É¤Ø¥¨¥ó¥³¡¼¥É¤·¤ÆURL¥¨¥ó¥³¡¼¥É
789 $param = rawurlencode(mb_convert_encoding($param, $opt, 'auto'));
793 if (strpos($url, '$1') !== FALSE) {
794 $url = str_replace('$1', $param, $url);