<?php
// PukiWiki - Yet another WikiWikiWeb clone.
-// $Id: make_link.php,v 1.27 2005/06/16 15:04:07 henoheno Exp $
-// Copyright (C)
-// 2003-2005 PukiWiki Developers Team
+// make_link.php
+// Copyright
+// 2003-2021 PukiWiki Development Team
// 2001-2002 Originally written by yu-ji
// License: GPL v2 or (at your option) any later version
//
// Hyperlink-related functions
+// To get page exists or filetimes without accessing filesystem
+// Type: array (page => filetime)
+$_cached_page_filetime = null;
+
+// Get filetime from cache
+function fast_get_filetime($page)
+{
+ global $_cached_page_filetime;
+ if (is_null($_cached_page_filetime)) {
+ return get_filetime($page);
+ }
+ if (isset($_cached_page_filetime[$page])) {
+ return $_cached_page_filetime[$page];
+ }
+ return get_filetime($page);
+}
+
// Hyperlink decoration
function make_link($string, $page = '')
{
var $result;
function get_clone($obj) {
- static $clone_func;
-
- if (! isset($clone_func)) {
+ static $clone_exists;
+ if (! isset($clone_exists)) {
if (version_compare(PHP_VERSION, '5.0.0', '<')) {
- $clone_func = create_function('$a', 'return $a;');
+ $clone_exists = false;
} else {
- $clone_func = create_function('$a', 'return clone $a;');
+ $clone_exists = true;
}
}
- return $clone_func($obj);
+ if ($clone_exists) {
+ return clone ($obj);
+ }
+ return $obj;
}
function __clone() {
function InlineConverter($converters = NULL, $excludes = NULL)
{
+ $this->__construct($converters, $excludes);
+ }
+ function __construct($converters = NULL, $excludes = NULL)
+ {
if ($converters === NULL) {
$converters = array(
'plugin', // Inline plugins
'url_interwiki', // URLs (interwiki definition)
'mailto', // mailto: URL schemes
'interwikiname', // InterWikiNames
+ 'autoalias', // AutoAlias
'autolink', // AutoLinks
'bracketname', // BracketNames
'wikiname', // WikiNames
+ 'autoalias_a', // AutoAlias(alphabet)
'autolink_a', // AutoLinks(alphabet)
);
}
$this->page = $page;
$this->result = array();
- $string = preg_replace_callback('/' . $this->pattern . '/x',
+ $string = preg_replace_callback('/' . $this->pattern . '/x' . get_preg_u(),
array(& $this, 'replace'), $string);
- $arr = explode("\x08", make_line_rules(htmlspecialchars($string)));
+ $arr = explode("\x08", make_line_rules(htmlsc($string)));
$retval = '';
while (! empty($arr)) {
$retval .= array_shift($arr) . array_shift($this->result);
$obj = $this->get_converter($arr);
$this->result[] = ($obj !== NULL && $obj->set($arr, $this->page) !== FALSE) ?
- $obj->toString() : make_line_rules(htmlspecialchars($arr[0]));
+ $obj->toString() : make_line_rules(htmlsc($arr[0]));
return "\x08"; // Add a mark into latest processed part
}
function get_objects($string, $page)
{
$matches = $arr = array();
- preg_match_all('/' . $this->pattern . '/x', $string, $matches, PREG_SET_ORDER);
+ preg_match_all('/' . $this->pattern . '/x' . get_preg_u(),
+ $string, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
$obj = $this->get_converter($match);
if ($obj->set($match, $page) !== FALSE) {
var $body;
var $alias;
- // Constructor
function Link($start)
{
+ $this->__construct($start);
+ }
+ function __construct($start)
+ {
$this->start = $start;
}
$this->type = $type;
if (! PKWK_DISABLE_INLINE_IMAGE_FROM_URI &&
is_url($alias) && preg_match('/\.(gif|png|jpe?g)$/i', $alias)) {
- $alias = '<img src="' . htmlspecialchars($alias) . '" alt="' . $name . '" />';
+ $alias = '<img src="' . htmlsc($alias) . '" alt="' . $name . '" />';
} else if ($alias != '') {
if ($converter === NULL)
$converter = new InlineConverter(array('plugin'));
function Link_plugin($start)
{
- parent::Link($start);
+ $this->__construct($start);
+ }
+ function __construct($start)
+ {
+ parent::__construct($start);
}
function get_pattern()
// Re-get true plugin name and patameters (for PHP 4.1.2)
$matches = array();
- if (preg_match('/^' . $this->pattern . '/x', $all, $matches)
+ if (preg_match('/^' . $this->pattern . '/x' . get_preg_u(), $all, $matches)
&& $matches[1] != $this->plain)
list(, $this->plain, $name, $this->param) = $matches;
} else {
// No such plugin, or Failed
$body = (($body == '') ? '' : '{' . $body . '}') . ';';
- return make_line_rules(htmlspecialchars('&' . $this->plain) . $body);
+ return make_line_rules(htmlsc('&' . $this->plain) . $body);
}
}
}
{
function Link_note($start)
{
- parent::Link($start);
+ $this->__construct($start);
+ }
+ function __construct($start)
+ {
+ parent::__construct($start);
}
function get_pattern()
{
return <<<EOD
\(\(
- ((?:(?R)|(?!\)\)).)*) # (1) note body
+ ((?>(?=\(\()(?R)|(?!\)\)).)*) # (1) note body
\)\)
EOD;
}
list(, $body) = $this->splice($arr);
- $script = '';
- if (! PKWK_ALLOW_RELATIVE_FOOTNOTE_ANCHOR)
- $script = get_script_uri() . '?' . $page;
-
+ if (PKWK_ALLOW_RELATIVE_FOOTNOTE_ANCHOR) {
+ $script = '';
+ } else {
+ $script = get_page_uri($page);
+ }
$id = ++$note_id;
$note = make_link($body);
- $page = isset($vars['page']) ? rawurlencode($vars['page']) : '';
// Footnote
$foot_explain[$id] = '<a id="notefoot_' . $id . '" href="' .
'<span class="small">' . $note . '</span><br />';
// A hyperlink, content-body to footnote
+ if (! is_numeric(PKWK_FOOTNOTE_TITLE_MAX) || PKWK_FOOTNOTE_TITLE_MAX <= 0) {
+ $title = '';
+ } else {
+ $title = strip_tags($note);
+ $count = mb_strlen($title, SOURCE_ENCODING);
+ $title = mb_substr($title, 0, PKWK_FOOTNOTE_TITLE_MAX, SOURCE_ENCODING);
+ $abbr = (PKWK_FOOTNOTE_TITLE_MAX < $count) ? '...' : '';
+ $title = ' title="' . $title . $abbr . '"';
+ }
$name = '<a id="notetext_' . $id . '" href="' . $script .
- '#notefoot_' . $id . '" class="note_super" title="' .
- htmlspecialchars(strip_tags($note)) . '">*' . $id . '</a>';
+ '#notefoot_' . $id . '" class="note_super"' . $title .
+ '>*' . $id . '</a>';
return parent::setParam($page, $name, $body);
}
{
function Link_url($start)
{
- parent::Link($start);
+ $this->__construct($start);
+ }
+ function __construct($start)
+ {
+ parent::__construct($start);
}
function get_pattern()
{
$s1 = $this->start + 1;
return <<<EOD
-(\[\[ # (1) open bracket
- ((?:(?!\]\]).)+) # (2) alias
+((?:\[\[))? # (1) open bracket
+((?($s1) # (2) alias
+((?:(?!\]\]).)+) # (3) alias name
(?:>|:)
-)?
-( # (3) url
+))?
+( # (4) url
(?:(?:https?|ftp|news):\/\/|mailto:)[\w\/\@\$()!?&%#:;.,~'=*+-]+
)
(?($s1)\]\]) # close bracket
function get_count()
{
- return 3;
+ return 4;
}
function set($arr, $page)
{
- list(, , $alias, $name) = $this->splice($arr);
- return parent::setParam($page, htmlspecialchars($name),
+ list(, , , $alias, $name) = $this->splice($arr);
+ return parent::setParam($page, htmlsc($name),
'', 'url', $alias == '' ? $name : $alias);
}
{
function Link_url_interwiki($start)
{
- parent::Link($start);
+ $this->__construct($start);
+ }
+ function __construct($start)
+ {
+ parent::__construct($start);
}
function get_pattern()
function set($arr, $page)
{
list(, $name, $alias) = $this->splice($arr);
- return parent::setParam($page, htmlspecialchars($name), '', 'url', $alias);
+ return parent::setParam($page, htmlsc($name), '', 'url', $alias);
}
function toString()
function Link_mailto($start)
{
- parent::Link($start);
+ $this->__construct($start);
+ }
+ function __construct($start)
+ {
+ parent::__construct($start);
}
function get_pattern()
function Link_interwikiname($start)
{
- parent::Link($start);
+ $this->__construct($start);
+ }
+ function __construct($start)
+ {
+ parent::__construct($start);
}
function get_pattern()
function set($arr, $page)
{
- global $script;
-
list(, $alias, , $name, $this->param) = $this->splice($arr);
$matches = array();
$url = get_interwiki_url($name, $this->param);
$this->url = ($url === FALSE) ?
- $script . '?' . rawurlencode('[[' . $name . ':' . $this->param . ']]') :
- htmlspecialchars($url);
+ get_base_uri() . '?' . pagename_urlencode('[[' . $name . ':' . $this->param . ']]') :
+ htmlsc($url);
return parent::setParam(
$page,
- htmlspecialchars($name . ':' . $this->param),
+ htmlsc($name . ':' . $this->param),
'',
'InterWikiName',
$alias == '' ? $name . ':' . $this->param : $alias
function Link_bracketname($start)
{
- parent::Link($start);
+ $this->__construct($start);
+ }
+ function __construct($start)
+ {
+ parent::__construct($start);
}
function get_pattern()
{
function Link_wikiname($start)
{
- parent::Link($start);
+ $this->__construct($start);
+ }
+ function __construct($start)
+ {
+ parent::__construct($start);
}
function get_pattern()
function Link_autolink($start)
{
+ $this->__construct($start);
+ }
+ function __construct($start)
+ {
global $autolink;
- parent::Link($start);
+ parent::__construct($start);
if (! $autolink || ! file_exists(CACHE_DIR . 'autolink.dat'))
return;
{
function Link_autolink_a($start)
{
- parent::Link_autolink($start);
+ $this->__construct($start);
+ }
+ function __construct($start)
+ {
+ parent::__construct($start);
+ }
+
+ function get_pattern()
+ {
+ return isset($this->auto_a) ? '(' . $this->auto_a . ')' : FALSE;
+ }
+}
+
+// AutoAlias
+class Link_autoalias extends Link
+{
+ var $forceignorepages = array();
+ var $auto;
+ var $auto_a; // alphabet only
+ var $alias;
+
+ function Link_autoalias($start)
+ {
+ $this->__construct($start);
+ }
+ function __construct($start)
+ {
+ global $autoalias, $aliaspage;
+
+ parent::__construct($start);
+
+ if (! $autoalias || ! file_exists(CACHE_DIR . PKWK_AUTOALIAS_REGEX_CACHE) || $this->page == $aliaspage)
+ {
+ return;
+ }
+
+ @list($auto, $auto_a, $forceignorepages) = file(CACHE_DIR . PKWK_AUTOALIAS_REGEX_CACHE);
+ $this->auto = $auto;
+ $this->auto_a = $auto_a;
+ $this->forceignorepages = explode("\t", trim($forceignorepages));
+ $this->alias = '';
+ }
+ function get_pattern()
+ {
+ return isset($this->auto) ? '(' . $this->auto . ')' : FALSE;
+ }
+ function get_count()
+ {
+ return 1;
+ }
+ function set($arr,$page)
+ {
+ list($name) = $this->splice($arr);
+ // Ignore pages listed
+ if (in_array($name, $this->forceignorepages) || get_autoalias_right_link($name) == '') {
+ return FALSE;
+ }
+ return parent::setParam($page,$name,'','pagename',$name);
}
+ function toString()
+ {
+ $this->alias = get_autoalias_right_link($this->name);
+ if ($this->alias != '') {
+ $link = '[[' . $this->name . '>' . $this->alias . ']]';
+ return make_link($link);
+ }
+ return '';
+ }
+}
+
+class Link_autoalias_a extends Link_autoalias
+{
+ function Link_autoalias_a($start)
+ {
+ $this->__construct($start);
+ }
+ function __construct($start)
+ {
+ parent::__construct($start);
+ }
function get_pattern()
{
return isset($this->auto_a) ? '(' . $this->auto_a . ')' : FALSE;
// Make hyperlink for the page
function make_pagelink($page, $alias = '', $anchor = '', $refer = '', $isautolink = FALSE)
{
- global $script, $vars, $link_compact, $related, $_symbol_noexists;
+ global $vars, $link_compact, $related, $_symbol_noexists;
- $s_page = htmlspecialchars(strip_bracket($page));
+ $script = get_base_uri();
+ $s_page = htmlsc(strip_bracket($page));
$s_alias = ($alias == '') ? $s_page : $alias;
if ($page == '') return '<a href="' . $anchor . '">' . $s_alias . '</a>';
- $r_page = rawurlencode($page);
- $r_refer = ($refer == '') ? '' : '&refer=' . rawurlencode($refer);
-
- if (! isset($related[$page]) && $page != $vars['page'] && is_page($page))
- $related[$page] = get_filetime($page);
+ $page_filetime = fast_get_filetime($page);
+ $is_page = $page_filetime !== 0;
+ if (! isset($related[$page]) && $page !== $vars['page'] && $is_page) {
+ $related[$page] = $page_filetime;
+ }
- if ($isautolink || is_page($page)) {
+ if ($isautolink || $is_page) {
// Hyperlink to the page
- if ($link_compact) {
- $title = '';
- } else {
- $title = ' title="' . $s_page . get_pg_passage($page, FALSE) . '"';
- }
-
+ $attrs = get_filetime_a_attrs($page_filetime);
// AutoLink marker
if ($isautolink) {
$al_left = '<!--autolink-->';
} else {
$al_left = $al_right = '';
}
-
- return $al_left . '<a ' . 'href="' . $script . '?' . $r_page . $anchor .
- '"' . $title . '>' . $s_alias . '</a>' . $al_right;
+ $title_attr_html = '';
+ if ($s_page !== $s_alias) {
+ $title_attr_html = ' title="' . $s_page . '"';
+ }
+ return $al_left . '<a ' . 'href="' . get_page_uri($page) . $anchor .
+ '"' . $title_attr_html . ' class="' .
+ $attrs['class'] . '" data-mtime="' . $attrs['data_mtime'] .
+ '">' . $s_alias . '</a>' . $al_right;
} else {
+ // Support Page redirection
+ $r_page = rawurlencode($page);
+ $r_refer = ($refer == '') ? '' : '&refer=' . rawurlencode($refer);
+ $redirect_page = get_pagename_on_redirect($page);
+ if ($redirect_page !== false) {
+ return make_pagelink($redirect_page, $s_alias);
+ }
// Dangling link
if (PKWK_READONLY) return $s_alias; // No dacorations
-
- $retval = $s_alias . '<a href="' .
- $script . '?cmd=edit&page=' . $r_page . $r_refer . '">' .
- $_symbol_noexists . '</a>';
-
- if ($link_compact) {
+ $symbol_html = '';
+ if ($_symbol_noexists !== '') {
+ $symbol_html = '<span style="user-select:none;">' .
+ htmlsc($_symbol_noexists) . '</span>';
+ }
+ $href = $script . '?cmd=edit&page=' . $r_page . $r_refer;
+ if ($link_compact && $_symbol_noexists != '') {
+ $retval = '<a href="' . $href . '">' . $_symbol_noexists . '</a>';
return $retval;
} else {
- return '<span class="noexists">' . $retval . '</span>';
+ $retval = '<a href="' . $href . '">' . $s_alias . '</a>';
+ return '<span class="noexists">' . $retval . $symbol_html . '</span>';
}
}
}
if ($name == '' || $name == './') return $refer;
// Absolute path
- if ($name{0} == '/') {
+ if ($name[0] == '/') {
$name = substr($name, 1);
return ($name == '') ? $defaultpage : $name;
}
if (isset($encode_aliases[$opt])) $opt = & $encode_aliases[$opt];
// Encoding conversion into specified encode, and URLencode
- $param = rawurlencode(mb_convert_encoding($param, $opt, SOURCE_ENCODING));
+ if (strpos($url, '$1') === FALSE && substr($url, -1) === '?') {
+ // PukiWiki site
+ $param = pagename_urlencode(mb_convert_encoding($param, $opt, SOURCE_ENCODING));
+ } else {
+ $param = rawurlencode(mb_convert_encoding($param, $opt, SOURCE_ENCODING));
+ }
}
// Replace or Add the parameter
return $url;
}
-?>
+
+function get_autoticketlink_def_page()
+{
+ return 'AutoTicketLinkName';
+}
+
+/**
+ * Get AutoTicketLink - JIRA projects from AutoTiketLinkName page
+ */
+function get_ticketlink_jira_projects()
+{
+ $autoticketlink_def_page = get_autoticketlink_def_page();
+ $active_jira_base_url = null;
+ $jira_projects = array();
+ foreach (get_source($autoticketlink_def_page) as $line) {
+ if (substr($line, 0, 1) !== '-') {
+ $active_jira_base_url = null;
+ continue;
+ }
+ $m = null;
+ if (preg_match('/^-\s*(jira)\s+(https?:\/\/[!~*\'();\/?:\@&=+\$,%#\w.-]+)\s*$/', $line, $m)) {
+ $active_jira_base_url = $m[2];
+ } else if (preg_match('/^--\s*([A-Z][A-Z0-9]{1,10}(?:_[A-Z0-9]{1,10}){0,2})(\s+(.+?))?\s*$/', $line, $m)) {
+ if ($active_jira_base_url) {
+ $project_key = $m[1];
+ $title = isset($m[2]) ? $m[2] : '';
+ array_push($jira_projects, array(
+ 'key' => $m[1],
+ 'title' => $title,
+ 'base_url' => $active_jira_base_url,
+ ));
+ }
+ } else {
+ $active_jira_base_url = null;
+ }
+ }
+ return $jira_projects;
+}
+
+function init_autoticketlink_def_page()
+{
+ $autoticketlink_def_page = get_autoticketlink_def_page();
+ if (is_page($autoticketlink_def_page)) {
+ return;
+ }
+ $body = <<<EOS
+#freeze
+* AutoTicketLink definition [#def]
+
+Reference: https://pukiwiki.osdn.jp/?AutoTicketLink
+
+ - jira https://site1.example.com/jira/browse/
+ -- AAA Project title \$1
+ -- BBB Project title \$1
+ - jira https://site2.example.com/jira/browse/
+ -- PROJECTA Site2 \$1
+
+ (Default definition) pukiwiki.ini.php
+ $ticket_jira_default_site = array(
+ 'title' => 'My JIRA - \$1',
+ 'base_url' => 'https://issues.example.com/jira/browse/',
+ );
+EOS;
+ page_write($autoticketlink_def_page, $body);
+}
+
+function init_autoalias_def_page()
+{
+ global $aliaspage; // 'AutoAliasName'
+ $autoticketlink_def_page = get_autoticketlink_def_page();
+ if (is_page($aliaspage)) {
+ return;
+ }
+ $body = <<<EOS
+#freeze
+*AutoAliasName [#qf9311bb]
+AutoAlias definition
+
+Reference: https://pukiwiki.osdn.jp/?AutoAlias
+
+* PukiWiki [#ee87d39e]
+-[[pukiwiki.official>https://pukiwiki.osdn.jp/]]
+-[[pukiwiki.dev>https://pukiwiki.osdn.jp/dev/]]
+EOS;
+ page_write($aliaspage, $body);
+ update_autoalias_cache_file();
+}