first commit

This commit is contained in:
/usr/bin/nano
2017-04-15 01:34:36 +03:00
commit c715e2a604
5325 changed files with 329700 additions and 0 deletions

12
wiki/scripts/.htaccess Executable file
View File

@@ -0,0 +1,12 @@
# This file is script/.htaccess -- the default distribution contains this
# file to prevent script/ files from being accessed directly by browsers
# (this is a potential, albeit very unlikely, security hole).
#
# If you alter or replace this file, it will likely be overwritten when
# you upgrade from one version of PmWiki to another. Be sure to save
# a copy of your alterations in another location so you can restore them,
# and you might try changing this file to be read-only to prevent a PmWiki
# upgrade from overwriting your altered version.
Order Deny,Allow
Deny from all

54
wiki/scripts/author.php Executable file
View File

@@ -0,0 +1,54 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2013 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script handles author tracking.
*/
SDV($AuthorNameChars, "- '\\w\\x80-\\xff");
SDV($AuthorCookie, $CookiePrefix.'author');
SDV($AuthorCookieExpires,$Now+60*60*24*30);
SDV($AuthorCookieDir,'/');
SDV($AuthorGroup,'Profiles');
SDV($AuthorRequiredFmt,
"<h3 class='wikimessage'>$[An author name is required.]</h3>");
Markup('[[~','<links','/\\[\\[~(.*?)\\]\\]/',"[[$AuthorGroup/$1]]");
$LogoutCookies[] = $AuthorCookie;
if (!isset($Author)) {
if (isset($_POST['author'])) {
$x = stripmagic($_POST['author']);
setcookie($AuthorCookie, $x, $AuthorCookieExpires, $AuthorCookieDir);
} elseif (@$_COOKIE[$AuthorCookie]) {
$x = stripmagic(@$_COOKIE[$AuthorCookie]);
} else $x = @$AuthId;
$Author = PHSC(preg_replace("/[^$AuthorNameChars]/", '', $x),
ENT_COMPAT);
}
if (!isset($AuthorPage)) $AuthorPage =
FmtPageName('$AuthorGroup/$Name', MakePageName("$AuthorGroup.$AuthorGroup", $Author));
SDV($AuthorLink,($Author) ? "[[~$Author]]" : '?');
if (IsEnabled($EnableAuthorSignature,1)) {
SDVA($ROSPatterns, array(
'/(?<!~)~~~~(?!~)/' => "[[~$Author]] $CurrentTime",
'/(?<!~)~~~(?!~)/' => "[[~$Author]]",
));
Markup('~~~~','<[[~','/(?<!~)~~~~(?!~)/',"[[~$Author]] $CurrentTime");
Markup('~~~','>~~~~','/(?<!~)~~~(?!~)/',"[[~$Author]]");
}
if (IsEnabled($EnablePostAuthorRequired,0))
array_unshift($EditFunctions,'RequireAuthor');
## RequireAuthor forces an author to enter a name before posting.
function RequireAuthor($pagename, &$page, &$new) {
global $Author, $MessagesFmt, $AuthorRequiredFmt, $EnablePost;
if (!$Author) {
$MessagesFmt[] = $AuthorRequiredFmt;
$EnablePost = 0;
}
}

213
wiki/scripts/authuser.php Executable file
View File

@@ -0,0 +1,213 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2005-2015 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
The APR compatible MD5 encryption algorithm in _crypt() below is
based on code Copyright 2005 by D. Faure and the File::Passwd
PEAR library module by Mike Wallner <mike@php.net>.
This script enables simple authentication based on username and
password combinations. At present this script can authenticate
from passwords held in arrays or in .htpasswd-formatted files,
but eventually it will support authentication via sources such
as LDAP and Active Directory.
To configure a .htpasswd-formatted file for authentication, do
$AuthUser['htpasswd'] = '/path/to/.htpasswd';
prior to including this script.
Individual username/password combinations can also be placed
directly in the $AuthUser array, such as:
$AuthUser['pmichaud'] = pmcrypt('secret');
To authenticate against an LDAP server, put the url for
the server in $AuthUser['ldap'], as in:
$AuthUser['ldap'] = 'ldap://ldap.example.com/ou=People,o=example?uid';
*/
# let Site.AuthForm know that we're doing user-based authorization
$EnableAuthUser = 1;
if (@$_POST['authid'])
AuthUserId($pagename, stripmagic(@$_POST['authid']),
stripmagic(@$_POST['authpw']));
else SessionAuth($pagename);
function AuthUserId($pagename, $id, $pw=NULL) {
global $AuthUser, $AuthUserPageFmt, $AuthUserFunctions,
$AuthId, $MessagesFmt, $AuthUserPat;
$auth = array();
foreach((array)$AuthUser as $k=>$v) $auth[$k] = (array)$v;
$authid = '';
# load information from SiteAdmin.AuthUser (or page in $AuthUserPageFmt)
SDV($AuthUserPageFmt, '$SiteAdminGroup.AuthUser');
SDVA($AuthUserFunctions, array(
'htpasswd' => 'AuthUserHtPasswd',
'ldap' => 'AuthUserLDAP',
# 'mysql' => 'AuthUserMySQL',
$id => 'AuthUserConfig'));
SDV($AuthUserPat, "/^\\s*([@\\w][^\\s:]*):(.*)/m");
$pn = FmtPageName($AuthUserPageFmt, $pagename);
$apage = ReadPage($pn, READPAGE_CURRENT);
if ($apage && preg_match_all($AuthUserPat,
$apage['text'], $matches, PREG_SET_ORDER)) {
foreach($matches as $m) {
if (!preg_match_all('/\\bldaps?:\\S+|[^\\s,]+/', $m[2], $v))
continue;
if ($m[1]{0} == '@')
foreach($v[0] as $g) $auth[$g][] = $m[1];
else $auth[$m[1]] = array_merge((array)@$auth[$m[1]], $v[0]);
}
}
if (func_num_args()==2) $authid = $id;
else
foreach($AuthUserFunctions as $k => $fn)
if (@$auth[$k] && $fn($pagename, $id, $pw, $auth[$k], $authlist))
{ $authid = $id; break; }
if (!$authid) { $GLOBALS['InvalidLogin'] = 1; return; }
if (!isset($AuthId)) $AuthId = $authid;
$authlist["id:$authid"] = 1;
$authlist["id:-$authid"] = -1;
foreach(preg_grep('/^@/', (array)@$auth[$authid]) as $g)
$authlist[$g] = 1;
foreach(preg_grep('/^@/', (array)@$auth['*']) as $g)
$authlist[$g] = 1;
foreach(preg_grep('/^@/', array_keys($auth)) as $g) # useless? PITS:01201
if (in_array($authid, $auth[$g])) $authlist[$g] = 1;
if ($auth['htgroup']) {
foreach(AuthUserHtGroup($pagename, $id, $pw, $auth['htgroup']) as $g)
$authlist["@$g"] = 1;
}
foreach(preg_grep('/^@/', (array)@$auth["-$authid"]) as $g)
unset($authlist[$g]);
SessionAuth($pagename, array('authid' => $authid, 'authlist' => $authlist));
}
function AuthUserConfig($pagename, $id, $pw, $pwlist) {
foreach ((array)$pwlist as $chal)
if (_crypt($pw, $chal) == $chal) return true;
return false;
}
function AuthUserHtPasswd($pagename, $id, $pw, $pwlist) {
foreach ((array)$pwlist as $f) {
$fp = fopen($f, "r"); if (!$fp) continue;
while ($x = fgets($fp, 1024)) {
$x = rtrim($x);
@list($i, $c, $r) = explode(':', $x, 3);
if ($i == $id && _crypt($pw, $c) == $c) { fclose($fp); return true; }
}
fclose($fp);
}
return false;
}
function AuthUserHtGroup($pagename, $id, $pw, $pwlist) {
$groups = array();
foreach ((array)$pwlist as $f) {
$fp = fopen($f, 'r'); if (!$fp) continue;
while ($x = fgets($fp, 4096)) {
if (preg_match('/^(\\w[^\\s:]+)\\s*:(.*)$/', trim($x), $match)) {
$glist = preg_split('/[\\s,]+/', $match[2], -1, PREG_SPLIT_NO_EMPTY);
if (in_array($id, $glist)) $groups[$match[1]] = 1;
}
}
fclose($fp);
}
return array_keys($groups);
}
function AuthUserLDAP($pagename, $id, $pw, $pwlist) {
global $AuthLDAPBindDN, $AuthLDAPBindPassword;
if (!$pw) return false;
if (!function_exists('ldap_connect'))
Abort('authuser: LDAP authentication requires PHP ldap functions','ldapfn');
foreach ((array)$pwlist as $ldap) {
if (!preg_match('!(ldaps?://[^/]+)/(.*)$!', $ldap, $match))
continue;
## connect to the LDAP server
list($z, $url, $path) = $match;
$ds = ldap_connect($url);
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
## For Active Directory, don't specify a path and we simply
## attempt to bind with the username and password directly
if (!$path && @ldap_bind($ds, $id, $pw)) { ldap_close($ds); return true; }
## Otherwise, we use Apache-style urls for LDAP authentication
## Split the path into its search components
list($basedn, $attr, $sub, $filter) = explode('?', $path);
if (!$attr) $attr = 'uid';
if (!$sub) $sub = 'one';
if (!$filter) $filter = '(objectClass=*)';
$binddn = @$AuthLDAPBindDN;
$bindpw = @$AuthLDAPBindPassword;
if (ldap_bind($ds, $binddn, $bindpw)) {
## Search for the appropriate uid
$fn = ($sub == 'sub') ? 'ldap_search' : 'ldap_list';
$sr = $fn($ds, $basedn, "(&$filter($attr=$id))", array($attr));
$x = ldap_get_entries($ds, $sr);
## If we find a unique id, bind to it for success
if ($x['count'] == 1) {
$dn = $x[0]['dn'];
if (@ldap_bind($ds, $dn, $pw)) { ldap_close($ds); return true; }
}
}
ldap_close($ds);
}
return false;
}
# The _crypt function provides support for SHA1 encrypted passwords
# (keyed by '{SHA}') and Apache MD5 encrypted passwords (keyed by
# '$apr1$'); otherwise it just calls PHP's crypt() for the rest.
# The APR MD5 encryption code was contributed by D. Faure.
function _crypt($plain, $salt=null) {
if (strncmp($salt, '{SHA}', 5) == 0)
return '{SHA}'.base64_encode(pack('H*', sha1($plain)));
if (strncmp($salt, '$apr1$', 6) == 0) {
preg_match('/^\\$apr1\\$([^$]+)/', $salt, $match);
$salt = $match[1];
$length = strlen($plain);
$context = $plain . '$apr1$' . $salt;
$binary = pack('H32', md5($plain . $salt . $plain));
for($i = $length; $i > 0; $i -= 16)
$context .= substr($binary, 0, min(16, $i));
for($i = $length; $i > 0; $i >>= 1)
$context .= ($i & 1) ? chr(0) : $plain{0};
$binary = pack('H32', md5($context));
for($i = 0; $i < 1000; $i++) {
$new = ($i & 1) ? $plain : $binary;
if ($i % 3) $new .= $salt;
if ($i % 7) $new .= $plain;
$new .= ($i & 1) ? $binary : $plain;
$binary = pack('H32', md5($new));
}
$q = '';
for ($i = 0; $i < 5; $i++) {
$k = $i + 6;
$j = $i + 12;
if ($j == 16) $j = 5;
$q = $binary{$i}.$binary{$k}.$binary{$j} . $q;
}
$q = chr(0).chr(0).$binary{11} . $q;
$q = strtr(strrev(substr(base64_encode($q), 2)),
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
'./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
return "\$apr1\$$salt\$$q";
}
if (md5($plain) == $salt) return $salt;
return pmcrypt($plain, $salt);
}

240
wiki/scripts/blocklist.php Executable file
View File

@@ -0,0 +1,240 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2006-2013 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script adds blocklisting capabilities to PmWiki, and can
be enabled by simply setting the following in local/config.php:
$EnableBlocklist = 1;
With $EnableBlocklist set to 1, this module will search through
the SiteAdmin.Blocklist page, as well as any other pages given by
the $Blocklist pages variable, looking for lines of the
form "block:some phrase" or "block:/regex/", with "some phrase"
and "/regex/" indicating things to be excluded from any
posting to the site.
In addition, if a page contains IP addresses of the form
"a.b.c.d" or "a.b.c.*", then any posts coming from hosts
matching the address will be blocked.
There is also an "unblock:..." form, which removes an entry
from the blocklist. This is useful for removing specific
block items in wikifarms and with automatically downloaded
blocklists (below).
The script also has the capability of automatically downloading
blocklists from other sources, such as chongqed.org and
and the MoinMaster blocklist. These are configured using
the $BlocklistDownload array. An $EnableBlocklist value
of at least 10 configures PmWiki to automatically download
these external blocklists and refresh them daily.
More information about blocklists is available in the
PmWiki.Blocklist page.
*/
## Some recipes do page updates outside of the built-in posting
## cycle, so $EnableBlocklistImmediate is used to determine if
## we need to catch these. Currently this defaults to enabled,
## but at some point we may change the default to disabled.
if (IsEnabled($EnableBlocklistImmediate, 1)) {
SDVA($BlocklistActions, array('comment' => 1));
$ptext = implode(' ', @$_POST);
if ($ptext && @$BlocklistActions[$action]) {
Blocklist($pagename, $ptext);
if (!$EnablePost) {
unset($_POST['post']);
unset($_POST['postattr']);
unset($_POST['postedit']);
}
}
}
## If $EnableBlocklist is set to 10 or higher, then arrange to
## periodically download the "chongqed" and "moinmaster" blacklists.
if ($EnableBlocklist >= 10) {
# SDVA($BlocklistDownload['SiteAdmin.Blocklist-Chongqed'], array(
# 'url' => 'http://blacklist.chongqed.org/',
# 'format' => 'regex'));
SDVA($BlocklistDownload['SiteAdmin.Blocklist-MoinMaster'], array(
'url' => 'http://moinmo.in/BadContent?action=raw',
'format' => 'regex'));
}
## CheckBlocklist is inserted into $EditFunctions, to automatically
## check for blocks on anything being posted through the normal
## "update a page cycle"
array_unshift($EditFunctions, 'CheckBlocklist');
function CheckBlocklist($pagename, &$page, &$new) {
StopWatch("CheckBlocklist: begin $pagename");
$ptext = implode(' ', @$_POST);
if (@$ptext) Blocklist($pagename, $ptext);
StopWatch("CheckBlocklist: end $pagename");
}
## Blocklist is the function that does all of the work of
## checking for reasons to block a posting. It reads
## the available blocklist pages ($BlocklistPages) and
## builds an array of strings and regular expressiongs to
## be checked against the page; if any are found, then
## posting is blocked (via $EnablePost=0). The function
## also checks the REMOTE_ADDR against any blocked IP addresses.
function Blocklist($pagename, $text) {
global $BlocklistPages, $BlockedMessagesFmt, $BlocklistDownload,
$BlocklistDownloadRefresh, $Now, $EnablePost, $WhyBlockedFmt,
$MessagesFmt, $BlocklistMessageFmt, $EnableWhyBlocked, $IsBlocked;
StopWatch("Blocklist: begin $pagename");
$BlocklistDownload = (array)@$BlocklistDownload;
SDV($BlocklistPages,
array_merge(array('$SiteAdminGroup.Blocklist',
'$SiteAdminGroup.Blocklist-Farm'),
array_keys($BlocklistDownload)));
SDV($BlocklistMessageFmt, "<h3 class='wikimessage'>$[This post has been blocked by the administrator]</h3>");
SDVA($BlockedMessagesFmt, array(
'ip' => '$[Address blocked from posting]: ',
'text' => '$[Text blocked from posting]: '));
SDV($BlocklistDownloadRefresh, 86400);
## Loop over all blocklist pages
foreach((array)$BlocklistPages as $b) {
## load the current blocklist page
$pn = FmtPageName($b, $pagename);
$page = ReadPage($pn, READPAGE_CURRENT);
if (!$page) continue;
## if the page being checked is a blocklist page, stop blocking
if ($pagename == $pn) return;
## If the blocklist page is managed by automatic download,
## schedule any new downloads here
if (@$BlocklistDownload[$pn]) {
$bd = &$BlocklistDownload[$pn];
SDVA($bd, array(
'refresh' => $BlocklistDownloadRefresh,
'url' => "http://www.pmwiki.org/blocklists/$pn" ));
if (!@$page['text'] || $page['time'] < $Now - $bd['refresh'])
register_shutdown_function('BlocklistDownload', $pn, getcwd());
}
## If the blocklist is simply a list of regexes to be matched, load
## them into $terms['block'] and continue to the next blocklist page.
## Some regexes from remote sites aren't well-formed, so we have
## to escape any slashes that aren't already escaped.
if (strpos(@$page['text'], 'blocklist-format: regex') !==false) {
if (preg_match_all('/^([^\\s#].+)/m', $page['text'], $match))
foreach($match[0] as $m) {
$m = preg_replace('#(?<!\\\\)/#', '\\/', trim($m));
$terms['block'][] = "/$m/";
}
continue;
}
## Treat the page as a pmwiki-format blocklist page, with
## IP addresses and "block:"-style declarations. First, see
## if we need to block the author based on a.b.c.d or a.b.c.*
## IP addresses.
$ip = preg_quote($_SERVER['REMOTE_ADDR']);
$ip = preg_replace('/\\d+$/', '($0\\b|\\*)', $ip);
if (preg_match("/\\b$ip/", @$page['text'], $match)) {
$EnablePost = 0;
$IsBlocked = 1;
$WhyBlockedFmt[] = $BlockedMessagesFmt['ip'] . $match[0];
}
## Now we'll load any "block:" or "unblock:" specifications
## from the page text.
if (preg_match_all('/(un)?(?:block|regex):(.*)/', @$page['text'],
$match, PREG_SET_ORDER))
foreach($match as $m) $terms[$m[1].'block'][] = trim($m[2]);
}
## okay, we've loaded all of the terms, now subtract any 'unblock'
## terms from the block set.
StopWatch("Blocklist: diff unblock");
$blockterms = array_diff((array)@$terms['block'], (array)@$terms['unblock']);
## go through each of the remaining blockterms and see if it matches the
## text -- if so, disable posting and add a message to $WhyBlockedFmt.
StopWatch('Blocklist: blockterms (count='.count($blockterms).')');
$itext = strtolower($text);
foreach($blockterms as $b) {
if ($b{0} == '/') {
if (!preg_match($b, $text)) continue;
} else if (strpos($itext, strtolower($b)) === false) continue;
$EnablePost = 0;
$IsBlocked = 1;
$WhyBlockedFmt[] = $BlockedMessagesFmt['text'] . $b;
}
StopWatch('Blocklist: blockterms done');
## If we came across any reasons to block, let's provide a message
## to the author that it was blocked. If $EnableWhyBlocked is set,
## we'll even tell the author why. :-)
if (@$WhyBlockedFmt) {
$MessagesFmt[] = $BlocklistMessageFmt;
if (IsEnabled($EnableWhyBlocked, 0))
foreach((array)$WhyBlockedFmt as $why)
$MessagesFmt[] = "<pre class='blocklistmessage'>$why</pre>\n";
}
StopWatch("Blocklist: end $pagename");
}
## BlocklistDownload() handles retrieving blocklists from
## external sources into PmWiki pages. If it's able to
## download an updated list, it uses that; otherwise it leaves
## any existing list alone.
function BlocklistDownload($pagename, $dir = '') {
global $BlocklistDownloadFmt, $BlocklistDownload, $FmtV;
if ($dir) { flush(); chdir($dir); }
SDV($BlocklistDownloadFmt, "
[@
## blocklist-note: NOTE: This page is automatically generated by blocklist.php
## blocklist-note: NOTE: Any edits to this page may be lost!
## blocklist-url: \$BlocklistDownloadUrl
## blocklist-when: \$CurrentTimeISO
# blocklist-format: \$BlocklistFormat
\$BlocklistData
@]
");
## get the existing blocklist page
$bd = &$BlocklistDownload[$pagename];
$page = ReadPage($pagename, READPAGE_CURRENT);
## try to retrieve the remote data
$blocklistdata = @file($bd['url']);
## if we didn't get it, and we don't already have text, save a
## note in the page so we know what happened
if (!$blocklistdata && !@$page['text']) {
$auf = ini_get('allow_url_fopen');
$blocklistdata = "#### Unable to download blocklist (allow_url_fopen=$auf)";
}
## if we have some new text to save, let's format it and save it
if ($blocklistdata) {
$blocklistdata = implode('', (array)$blocklistdata);
$blocklistdata = preg_replace('/^##blocklist.*/m', '', $blocklistdata);
$FmtV['$BlocklistData'] = $blocklistdata;
$FmtV['$BlocklistDownloadUrl'] = $bd['url'];
$FmtV['$BlocklistFormat'] = $bd['format'];
$page['text'] = FmtPageName($BlocklistDownloadFmt, $pagename);
SDV($page['passwdread'], '@lock');
}
## save our updated(?) blocklist page
WritePage($pagename, $page);
}

63
wiki/scripts/caches.php Executable file
View File

@@ -0,0 +1,63 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2006-2014 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
*/
## Browser cache-control. If this is a cacheable action (e.g., browse,
## diff), then set the Last-Modified header to the time the site was
## last modified. If the browser has provided us with a matching
## If-Modified-Since request header, we can return 304 Not Modified.
SDV($LastModFile,"$WorkDir/.lastmod");
if (!$LastModFile) return;
$LastModTime = @filemtime($LastModFile);
foreach(get_included_files() as $f)
{ $v = @filemtime($f); if ($v > $LastModTime) $LastModTime = $v; }
if (@$EnableIMSCaching) {
SDV($IMSCookie, $CookiePrefix.'imstime');
SDV($IMSCookieExpires, $Now + 60*60*24*30);
SDV($IMSInvalidators, array('authpw', 'author'));
$LogoutCookies[] = $IMSCookie;
if ($IMSCookie) {
$IMSTime = @$_COOKIE[$IMSCookie];
if ($IMSTime < $LastModTime
|| array_intersect($IMSInvalidators, array_keys($_POST))) {
$IMSTime = $Now;
setcookie($IMSCookie, $IMSTime, $IMSCookieExpires, '/');
}
} else $IMSTime = $LastModTime;
if (in_array($action, (array)$CacheActions)) {
$HTTPLastMod = gmdate('D, d M Y H:i:s \G\M\T',$IMSTime);
$HTTPHeaders[] = "Cache-Control: no-cache";
$HTTPHeaders[] = "Last-Modified: $HTTPLastMod";
if (@$_SERVER['HTTP_IF_MODIFIED_SINCE']==$HTTPLastMod) {
header("HTTP/1.0 304 Not Modified");
header("Cache-Control: no-cache");
header("Expires: ");
header("Last-Modified: $HTTPLastMod");
exit();
}
}
}
if ($NoHTMLCache
|| !@$PageCacheDir
|| count($_POST) > 0
|| count($_GET) > 1
|| (count($_GET) == 1 && !@$_GET['n'])) { $NoHTMLCache |= 1; return; }
mkdirp($PageCacheDir);
if (!file_exists("$PageCacheDir/.htaccess")
&& $fp = @fopen("$PageCacheDir/.htaccess", "w"))
{ fwrite($fp, "Order Deny,Allow\nDeny from all\n"); fclose($fp); }
$PageCacheFile = "$PageCacheDir/$pagename,cache";
if (file_exists($PageCacheFile) && @filemtime($PageCacheFile) < $LastModTime)
@unlink($PageCacheFile);

66
wiki/scripts/creole.php Executable file
View File

@@ -0,0 +1,66 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2007-2014 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script adds Creole v0.4 markup (http://www.wikicreole.org/)
to PmWiki. To activate this script, simply add the following into
a local customization file:
include_once('scripts/creole.php');
*/
## **strong**
Markup('**', 'inline',
'/^\\*\\*(?>(.+?)\\*\\*)(?!\\S)|(?<!^)\\*\\*(.+?)\\*\\*/',
'<strong>$1$2</strong>');
## //emphasized//
Markup('//', 'inline',
'/(?<!http:|https:|ftp:)\\/\\/(.*?)\\/\\//',
'<em>$1</em>');
## == Headings ==
Markup_e('^=', 'block',
'/^(={1,6})\\s?(.*?)(\\s*=*\\s*)$/',
"'<:block,1><h'.strlen(\$m[1]).'>'.\$m[2].'</h'.strlen(\$m[1]).'>'");
## Line breaks
Markup('\\\\', 'inline', '/\\\\\\\\/', '<br />');
## Preformatted
Markup_e('^{{{', '[=',
"/^\\{\\{\\{\n(.*?\n)\\}\\}\\}[^\\S\n]*\n/sm",
"Keep('<pre class=\"escaped\">'.\$m[1].'</pre>')");
Markup_e('{{{', '>{{{',
'/\\{\\{\\{(.*?)\\}\\}\\}/s',
"Keep('<code class=\"escaped\">'.\$m[1].'</code>')");
## Tables
Markup_e('|-table', '>^||',
'/^\\|(.*)$/',
"FormatTableRow(\$m[0], '\\|')");
## Images
Markup_e('{{', 'inline',
'/\\{\\{(?>(\\L))([^|\\]]*)(?:\\|\\s*(.*?)\\s*)?\\}\\}/',
"Keep(\$GLOBALS['LinkFunctions'][\$m[1]](\$pagename, \$m[1], \$m[2], \$m[3],
\$m[1].\$m[2], \$GLOBALS['ImgTagFmt']),'L')");
## GUIButtons
SDVA($GUIButtons, array(
'em' => array(100, "//", "//", '$[Emphasized]',
'$GUIButtonDirUrlFmt/em.gif"$[Emphasized (italic)]"',
'$[ak_em]'),
'strong' => array(110, "**", "**", '$[Strong]',
'$GUIButtonDirUrlFmt/strong.gif"$[Strong (bold)]"',
'$[ak_strong]'),
'h2' => array(400, '\\n== ', ' ==\\n', '$[Heading]',
'$GUIButtonDirUrlFmt/h.gif"$[Heading]"'),
));

41
wiki/scripts/crypt.php Executable file
View File

@@ -0,0 +1,41 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2002-2015 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script defines ?action=crypt, providing help for WikiAdministrators
to set up site-wide passwords in the installation.
*/
SDV($HandleActions['crypt'],'HandleCrypt');
SDV($ActionTitleFmt['crypt'],'| $[Password encryption]');
function HandleCrypt($pagename, $auth='read') {
global $ScriptUrl,$HTMLStartFmt,$HTMLEndFmt;
PrintFmt($pagename,$HTMLStartFmt);
$passwd = stripmagic(@$_POST["passwd"]);
echo FmtPageName(
"<form action='{\$ScriptUrl}' method='POST'><p>
Enter password to encrypt:
<input type='text' name='passwd' value='"
. PHSC($passwd, ENT_QUOTES) ."' />
<input type='submit' />
<input type='hidden' name='n' value='{\$FullName}' />
<input type='hidden' name='action' value='crypt' /></p></form>",
$pagename);
if ($passwd) {
$crypt = pmcrypt($passwd);
echo "<p class='vspace'>Encrypted password = $crypt</p>";
echo "<p class='vspace'>To set a site-wide password, insert the line below
in your <i>config.php</i> file, <br />replacing <tt>'type'</tt> with
one of <tt>'admin'</tt>, <tt>'read'</tt>, <tt>'edit'</tt>,
or <tt>'attr'</tt>. <br />See <a
href='$ScriptUrl?n=PmWiki.PasswordsAdmin'>PasswordsAdmin</a> for more
details.</p>
<pre class='vspace'> \$DefaultPasswords['type']='$crypt';</pre>";
}
PrintFmt($pagename,$HTMLEndFmt);
}

60
wiki/scripts/diag.php Executable file
View File

@@ -0,0 +1,60 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2003-2005, 2007 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This file adds "?action=diag" and "?action=phpinfo" actions to PmWiki.
This produces lots of diagnostic output that may be helpful to the
software authors when debugging PmWiki or other scripts.
*/
@ini_set('display_errors', '1');
@ini_set('track_errors','1');
if ($action=='diag') {
@session_start();
header('Content-type: text/plain');
print_r($GLOBALS);
exit();
}
if ($action=='phpinfo') { phpinfo(); exit(); }
function Ruleset() {
global $MarkupTable;
$out = '';
$dbg = 0;
BuildMarkupRules();
foreach($MarkupTable as $id=>$m) {
$out .= sprintf("%-16s %-16s %-16s %s\n",$id,@$m['cmd'],@$m['seq'], @$m['dbg']);
if(@$m['dbg']) $dbg++;
}
if($dbg) $out .= "
[!] Markup rules possibly incompatible with PHP 5.5 or newer.
Please contact the recipe maintainer for update
or see www.pmwiki.org/wiki/PmWiki/CustomMarkup";
return $out;
}
$HandleActions['ruleset'] = 'HandleRuleset';
function HandleRuleset($pagename) {
header("Content-type: text/plain");
print Ruleset();
}
function StopWatchHTML($pagename, $print = 0) {
global $StopWatch;
StopWatch('now');
$l = strlen(count($StopWatch));
$out = '<pre>';
foreach((array)$StopWatch as $i => $x)
$out .= sprintf("%{$l}d: %s\n", $i, $x);
$out .= '</pre>';
if (is_array($StopWatch)) array_pop($StopWatch);
if ($print) print $out;
return $out;
}

73
wiki/scripts/draft.php Executable file
View File

@@ -0,0 +1,73 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2006-2014 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
*/
SDV($DraftSuffix, '-Draft');
if ($DraftSuffix)
SDV($SearchPatterns['normal']['draft'], "!$DraftSuffix\$!");
## set up a 'publish' authorization level, defaulting to 'edit' authorization
SDV($DefaultPasswords['publish'], '');
SDV($AuthCascade['publish'], 'edit');
SDV($FmtPV['$PasswdPublish'], 'PasswdVar($pn, "publish")');
if ($AuthCascade['attr'] == 'edit') $AuthCascade['attr'] = 'publish';
## Add a 'publish' page attribute if desired
if (IsEnabled($EnablePublishAttr, 0))
SDV($PageAttributes['passwdpublish'], '$[Set new publish password:]');
$basename = preg_replace("/$DraftSuffix\$/", '', $pagename);
## if no -Draft page, switch to $basename
if (!PageExists($pagename) && PageExists($basename)) $pagename = $basename;
## The section below handles specialized EditForm pages and handler.
## We don't bother to load it if we're not editing.
SDV($DraftActionsPattern, 'edit');
if (! preg_match("/($DraftActionsPattern)/", $action)) return;
## set edit form button labels to reflect draft prompts
SDVA($InputTags['e_savebutton'], array('value' => ' '.XL('Publish').' '));
SDVA($InputTags['e_saveeditbutton'], array('value' => ' '.XL('Save draft and edit').' '));
SDVA($InputTags['e_savedraftbutton'], array(
':html' => "<input type='submit' \$InputFormArgs />",
'name' => 'postdraft', 'value' => ' '.XL('Save draft').' ',
'accesskey' => XL('ak_savedraft')));
## with drafts enabled, the 'post' operation requires 'publish' permissions
if ($_POST['post'] && $HandleAuth['edit'] == 'edit')
$HandleAuth['edit'] = 'publish';
## disable the 'publish' button if not authorized to publish
if (!CondAuth($basename, 'publish'))
SDVA($InputTags['e_savebutton'], array('disabled' => 'disabled'));
## add the draft handler into $EditFunctions
array_unshift($EditFunctions, 'EditDraft');
function EditDraft(&$pagename, &$page, &$new) {
global $WikiDir, $DraftSuffix, $DeleteKeyPattern, $EnableDraftAtomicDiff,
$DraftRecentChangesFmt, $RecentChangesFmt, $Now;
SDV($DeleteKeyPattern, "^\\s*delete\\s*$");
$basename = preg_replace("/$DraftSuffix\$/", '', $pagename);
$draftname = $basename . $DraftSuffix;
if ($_POST['postdraft'] || $_POST['postedit']) $pagename = $draftname;
else if ($_POST['post'] && !preg_match("/$DeleteKeyPattern/", $new['text'])) {
$pagename = $basename;
if(IsEnabled($EnableDraftAtomicDiff, 0)) {
$page = ReadPage($basename);
foreach($new as $k=>$v) # delete draft history
if(preg_match('/:\\d+(:\\d+:)?$/', $k) && ! preg_match("/:$Now(:\\d+:)?$/", $k)) unset($new[$k]);
unset($new['rev']);
SDVA($new, $page);
}
$WikiDir->delete($draftname);
}
else if (PageExists($draftname) && $pagename != $draftname)
{ Redirect($draftname, '$PageUrl?action=edit'); exit(); }
if ($pagename == $draftname && isset($DraftRecentChangesFmt))
$RecentChangesFmt = $DraftRecentChangesFmt;
}

544
wiki/scripts/feeds.php Executable file
View File

@@ -0,0 +1,544 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2005-2010 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script provides a number of syndication feed and xml-based
metadata options to PmWiki, including Atom, RSS 2.0, RSS 1.0 (RDF),
and the Dublin Core Metadata extensions. This module is typically
activated from a local configuration file via a line such as
if ($action == 'atom') include_once("$FarmD/scripts/feeds.php");
if ($action == 'dc') include_once("$FarmD/scripts/feeds.php");
When enabled, ?action=atom, ?action=rss, and ?action=rdf produce
syndication feeds based on any wikitrail contained in the page,
or, for Category pages, on the pages in the category. The feeds
are generated using pagelist, thus one can include parameters such
as count=, list=, order=, etc. in the url to adjust the feed output.
?action=dc will normally generate Dublin Core Metadata for the
current page only, but placing a group=, trail=, or link= argument
in the url causes it to generate metadata for all pages in the
associated group, trail, or backlink.
There are a large number of customizations available, most of which
are controlled by the $FeedFmt array. Elements $FeedFmt look like
$FeedFmt['atom']['feed']['rights'] = 'All Rights Reserved';
where the first index corresponds to the action (?action=atom),
the second index indicates a per-feed or per-item element, and
the third index is the name of the element being generated.
The above setting would therefore generate a
"<rights>All Rights Reserved</rights>" in the feed for
?action=atom. If the value of an entry begins with a '<',
then feeds.php doesn't automatically add the tag around it.
Elements can also be callable functions which are called to
generate the appropriate output.
For example, to set the RSS 2.0 <author> element to the
value of the last author to modify a page, one can set
(in local/config.php):
$FeedFmt['rss']['item']['author'] = '$LastModifiedBy';
To use the RSS 2.0 <description> element to contain the
change summary of the most recent edit, set
$FeedFmt['rss']['item']['description'] = '$LastModifiedSummary';
Feeds.php can also be combined with attachments to support
podcasting via ?action=rss. Any page such as "PageName"
that has an mp3 attachment with the same name as the page
("PageName.mp3") will have an appropriate <enclosure> element
in the feed output. The set of allowed attachments can be
extended using the $RSSEnclosureFmt array:
$RSSEnclosureFmt = array('{$Name}.mp3', '{$Name}.mp4');
References:
http://www.atomenabled.org/developers/syndication/
http://dublincore.org/documents/dcmes-xml/
http://en.wikipedia.org/wiki/Podcasting
*/
## Settings for ?action=atom
SDVA($FeedFmt['atom']['feed'], array(
'_header' => 'Content-type: text/xml; charset="$Charset"',
'_start' => '<?xml version="1.0" encoding="$Charset"?'.'>
<feed xmlns="http://www.w3.org/2005/Atom">'."\n",
'_end' => "</feed>\n",
'title' => '$WikiTitle',
'link' => '<link rel="self" href="{$PageUrl}?action=atom" />',
'id' => '{$PageUrl}?action=atom',
'updated' => '$FeedISOTime',
'author' => "<author><name>$WikiTitle</name></author>\n",
'generator' => '$Version',
'logo' => '$PageLogoUrl'));
SDVA($FeedFmt['atom']['item'], array(
'_start' => "<entry>\n",
'id' => '{$PageUrl}',
'title' => '{$Title}',
'updated' => '$ItemISOTime',
'link' => "<link rel=\"alternate\" href=\"{\$PageUrl}\" />\n",
'author' => "<author><name>{\$LastModifiedBy}</name></author>\n",
'summary' => '{$Description}',
'category' => "<category term=\"\$Category\" />\n",
'_end' => "</entry>\n"));
## Settings for ?action=dc
SDVA($FeedFmt['dc']['feed'], array(
'_header' => 'Content-type: text/xml; charset="$Charset"',
'_start' => '<?xml version="1.0" encoding="$Charset"?'.'>
<!DOCTYPE rdf:RDF PUBLIC "-//DUBLIN CORE//DCMES DTD 2002/07/31//EN"
"http://dublincore.org/documents/2002/07/31/dcmes-xml/dcmes-xml-dtd.dtd">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">'."\n",
'_end' => "</rdf:RDF>\n"));
SDVA($FeedFmt['dc']['item'], array(
'_start' => "<rdf:Description rdf:about=\"{\$PageUrl}\">\n",
'dc:title' => '{$Title}',
'dc:identifier' => '{$PageUrl}',
'dc:date' => '$ItemISOTime',
'dc:type' => 'Text',
'dc:format' => 'text/html',
'dc:description' => '{$Description}',
'dc:subject' => "<dc:subject>\$Category</dc:subject>\n",
'dc:publisher' => '$WikiTitle',
'dc:author' => '{$LastModifiedBy}',
'_end' => "</rdf:Description>\n"));
## RSS 2.0 settings for ?action=rss
SDVA($FeedFmt['rss']['feed'], array(
'_header' => 'Content-type: text/xml; charset="$Charset"',
'_start' => '<?xml version="1.0" encoding="$Charset"?'.'>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>'."\n",
'_end' => "</channel>\n</rss>\n",
'title' => '$WikiTitle | {$Group} / {$Title}',
'link' => '{$PageUrl}?action=rss',
'description' => '{$Group}.{$Title}',
'lastBuildDate' => '$FeedRSSTime'));
SDVA($FeedFmt['rss']['item'], array(
'_start' => "<item>\n",
'_end' => "</item>\n",
'title' => '{$Group} / {$Title}',
'link' => '{$PageUrl}',
'description' => '{$Description}',
'dc:contributor' => '{$LastModifiedBy}',
'dc:date' => '$ItemISOTime',
'pubDate' => '$ItemRSSTime',
'enclosure' => 'RSSEnclosure'));
## RDF 1.0, for ?action=rdf
SDVA($FeedFmt['rdf']['feed'], array(
'_header' => 'Content-type: text/xml; charset="$Charset"',
'_start' => '<?xml version="1.0" encoding="$Charset"?'.'>
<rdf:RDF xmlns="http://purl.org/rss/1.0/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel rdf:about="{$PageUrl}?action=rdf">'."\n",
'title' => '$WikiTitle | {$Group} / {$Title}',
'link' => '{$PageUrl}?action=rdf',
'description' => '{$Group}.{$Title}',
'dc:date' => '$FeedISOTime',
'items' => "<items>\n<rdf:Seq>\n\$FeedRDFSeq</rdf:Seq>\n</items>\n",
'_items' => "</channel>\n",
'_end' => "</rdf:RDF>\n"));
SDVA($FeedFmt['rdf']['item'], array(
'_start' => "<item rdf:about=\"{\$PageUrl}\">\n",
'_end' => "</item>\n",
'title' => '$WikiTitle | {$Group} / {$Title}',
'link' => '{$PageUrl}',
'description' => '{$Description}',
'dc:date' => '$ItemISOTime'));
foreach(array_keys($FeedFmt) as $k) {
SDV($HandleActions[$k], 'HandleFeed');
SDV($HandleAuth[$k], 'read');
}
function HandleFeed($pagename, $auth = 'read') {
global $FeedFmt, $action, $PCache, $FmtV, $TimeISOZFmt, $RSSTimeFmt,
$FeedPageListOpt, $FeedCategoryOpt, $FeedTrailOpt,
$FeedDescPatterns, $CategoryGroup, $EntitiesTable;
SDV($RSSTimeFmt, 'D, d M Y H:i:s \G\M\T');
SDV($FeedDescPatterns,
array('/<[^>]*$/' => ' ', '/\\w+$/' => '', '/<[^>]+>/' => ''));
$FeedPageListOpt = (array)@$FeedPageListOpt;
SDVA($FeedCategoryOpt, array('link' => $pagename));
SDVA($FeedTrailOpt, array('trail' => $pagename, 'count' => 10));
$f = $FeedFmt[$action];
$page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT);
if (!$page) Abort("?cannot generate feed");
$feedtime = $page['time'];
# determine list of pages to display
if (@($_REQUEST['trail'] || $_REQUEST['group'] || $_REQUEST['link']
|| $_REQUEST['name']))
$opt = $FeedPageListOpt;
else if (preg_match("/^$CategoryGroup\\./", $pagename))
$opt = $FeedCategoryOpt;
else if ($action != 'dc') $opt = $FeedTrailOpt;
else {
PCache($pagename, $page);
$pagelist = array($pagename);
}
if (!@$pagelist) {
$opt = array_merge($opt, @$_REQUEST);
$pagelist = MakePageList($pagename, $opt, 0);
}
# process list of pages in feed
$rdfseq = '';
$pl = array();
foreach($pagelist as $pn) {
if (!PageExists($pn)) continue;
if (!isset($PCache[$pn]['time']))
{ $page = ReadPage($pn, READPAGE_CURRENT); PCache($pn, $page); }
$pc = & $PCache[$pn];
$pl[] = $pn;
$rdfseq .= FmtPageName("<rdf:li resource=\"{\$PageUrl}\" />\n", $pn);
if ($pc['time'] > $feedtime) $feedtime = $pc['time'];
if (@$opt['count'] && count($pl) >= $opt['count']) break;
}
$pagelist = $pl;
$FmtV['$FeedRDFSeq'] = $rdfseq;
$FmtV['$FeedISOTime'] = gmstrftime($TimeISOZFmt, $feedtime);
$FmtV['$FeedRSSTime'] = gmdate($RSSTimeFmt, $feedtime);
# format start of feed
$out = FmtPageName($f['feed']['_start'], $pagename);
# format feed elements
foreach($f['feed'] as $k => $v) {
if ($k{0} == '_' || !$v) continue;
$x = FmtPageName($v, $pagename);
if (!$x) continue;
$out .= ($v{0} == '<') ? $x : "<$k>$x</$k>\n";
}
# format items in feed
if (@$f['feed']['_items'])
$out .= FmtPageName($f['feed']['_items'], $pagename);
foreach($pagelist as $pn) {
$page = &$PCache[$pn];
$FmtV['$ItemDesc'] = @$page['description'];
$FmtV['$ItemISOTime'] = gmstrftime($TimeISOZFmt, $page['time']);
$FmtV['$ItemRSSTime'] = gmdate($RSSTimeFmt, $page['time']);
$out .= FmtPageName($f['item']['_start'], $pn);
foreach((array)@$f['item'] as $k => $v) {
if ($k{0} == '_' || !$v) continue;
if (is_callable($v)) { $out .= $v($pn, $page, $k); continue; }
if (strpos($v, '$LastModifiedBy') !== false && !@$page['author'])
continue;
if (strpos($v, '$Category') !== false) {
if (preg_match_all("/(?<=^|,)$CategoryGroup\\.([^,]+)/",
@$page['targets'], $match)) {
foreach($match[1] as $c) {
$FmtV['$Category'] = $c;
$out .= FmtPageName($v, $pn);
}
}
continue;
}
$x = FmtPageName($v, $pn);
if (!$x) continue;
$out .= ($v{0} == '<') ? $x : "<$k>$x</$k>\n";
}
$out .= FmtPageName($f['item']['_end'], $pn);
}
$out .= FmtPageName($f['feed']['_end'], $pagename);
foreach((array)@$f['feed']['_header'] as $fmt)
header(FmtPageName($fmt, $pagename));
print str_replace(array_keys($EntitiesTable),
array_values($EntitiesTable), $out);
}
## RSSEnclosure is called in ?action=rss to generate <enclosure>
## tags for any pages that have an attached "PageName.mp3" file.
## The set of attachments to enclose is given by $RSSEnclosureFmt.
function RSSEnclosure($pagename, &$page, $k) {
global $RSSEnclosureFmt, $UploadFileFmt, $UploadExts;
if (!function_exists('MakeUploadName')) return '';
SDV($RSSEnclosureFmt, array('{$Name}.mp3'));
$encl = '';
foreach((array)$RSSEnclosureFmt as $fmt) {
$path = FmtPageName($fmt, $pagename);
$upname = MakeUploadName($pagename, $path);
$filepath = FmtPageName("$UploadFileFmt/$upname", $pagename);
if (file_exists($filepath)) {
$length = filesize($filepath);
$type = @$UploadExts[preg_replace('/.*\\./', '', $filepath)];
$url = LinkUpload($pagename, 'Attach:', $path, '', '', '$LinkUrl');
$encl .= "<$k url='$url' length='$length' type='$type' />";
}
}
return $encl;
}
## Since most feeds don't understand html character entities, we
## convert the common ones to their numeric form here.
SDVA($EntitiesTable, array(
# entities defined in "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent"
'&nbsp;' => '&#160;',
'&iexcl;' => '&#161;',
'&cent;' => '&#162;',
'&pound;' => '&#163;',
'&curren;' => '&#164;',
'&yen;' => '&#165;',
'&brvbar;' => '&#166;',
'&sect;' => '&#167;',
'&uml;' => '&#168;',
'&copy;' => '&#169;',
'&ordf;' => '&#170;',
'&laquo;' => '&#171;',
'&not;' => '&#172;',
'&shy;' => '&#173;',
'&reg;' => '&#174;',
'&macr;' => '&#175;',
'&deg;' => '&#176;',
'&plusmn;' => '&#177;',
'&sup2;' => '&#178;',
'&sup3;' => '&#179;',
'&acute;' => '&#180;',
'&micro;' => '&#181;',
'&para;' => '&#182;',
'&middot;' => '&#183;',
'&cedil;' => '&#184;',
'&sup1;' => '&#185;',
'&ordm;' => '&#186;',
'&raquo;' => '&#187;',
'&frac14;' => '&#188;',
'&frac12;' => '&#189;',
'&frac34;' => '&#190;',
'&iquest;' => '&#191;',
'&Agrave;' => '&#192;',
'&Aacute;' => '&#193;',
'&Acirc;' => '&#194;',
'&Atilde;' => '&#195;',
'&Auml;' => '&#196;',
'&Aring;' => '&#197;',
'&AElig;' => '&#198;',
'&Ccedil;' => '&#199;',
'&Egrave;' => '&#200;',
'&Eacute;' => '&#201;',
'&Ecirc;' => '&#202;',
'&Euml;' => '&#203;',
'&Igrave;' => '&#204;',
'&Iacute;' => '&#205;',
'&Icirc;' => '&#206;',
'&Iuml;' => '&#207;',
'&ETH;' => '&#208;',
'&Ntilde;' => '&#209;',
'&Ograve;' => '&#210;',
'&Oacute;' => '&#211;',
'&Ocirc;' => '&#212;',
'&Otilde;' => '&#213;',
'&Ouml;' => '&#214;',
'&times;' => '&#215;',
'&Oslash;' => '&#216;',
'&Ugrave;' => '&#217;',
'&Uacute;' => '&#218;',
'&Ucirc;' => '&#219;',
'&Uuml;' => '&#220;',
'&Yacute;' => '&#221;',
'&THORN;' => '&#222;',
'&szlig;' => '&#223;',
'&agrave;' => '&#224;',
'&aacute;' => '&#225;',
'&acirc;' => '&#226;',
'&atilde;' => '&#227;',
'&auml;' => '&#228;',
'&aring;' => '&#229;',
'&aelig;' => '&#230;',
'&ccedil;' => '&#231;',
'&egrave;' => '&#232;',
'&eacute;' => '&#233;',
'&ecirc;' => '&#234;',
'&euml;' => '&#235;',
'&igrave;' => '&#236;',
'&iacute;' => '&#237;',
'&icirc;' => '&#238;',
'&iuml;' => '&#239;',
'&eth;' => '&#240;',
'&ntilde;' => '&#241;',
'&ograve;' => '&#242;',
'&oacute;' => '&#243;',
'&ocirc;' => '&#244;',
'&otilde;' => '&#245;',
'&ouml;' => '&#246;',
'&divide;' => '&#247;',
'&oslash;' => '&#248;',
'&ugrave;' => '&#249;',
'&uacute;' => '&#250;',
'&ucirc;' => '&#251;',
'&uuml;' => '&#252;',
'&yacute;' => '&#253;',
'&thorn;' => '&#254;',
'&yuml;' => '&#255;',
# entities defined in "http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent"
'&quot;' => '&#34;',
#'&amp;' => '&#38;#38;',
#'&lt;' => '&#38;#60;',
#'&gt;' => '&#62;',
'&apos;' => '&#39;',
'&OElig;' => '&#338;',
'&oelig;' => '&#339;',
'&Scaron;' => '&#352;',
'&scaron;' => '&#353;',
'&Yuml;' => '&#376;',
'&circ;' => '&#710;',
'&tilde;' => '&#732;',
'&ensp;' => '&#8194;',
'&emsp;' => '&#8195;',
'&thinsp;' => '&#8201;',
'&zwnj;' => '&#8204;',
'&zwj;' => '&#8205;',
'&lrm;' => '&#8206;',
'&rlm;' => '&#8207;',
'&ndash;' => '&#8211;',
'&mdash;' => '&#8212;',
'&lsquo;' => '&#8216;',
'&rsquo;' => '&#8217;',
'&sbquo;' => '&#8218;',
'&ldquo;' => '&#8220;',
'&rdquo;' => '&#8221;',
'&bdquo;' => '&#8222;',
'&dagger;' => '&#8224;',
'&Dagger;' => '&#8225;',
'&permil;' => '&#8240;',
'&lsaquo;' => '&#8249;',
'&rsaquo;' => '&#8250;',
'&euro;' => '&#8364;',
# entities defined in "http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent"
'&fnof;' => '&#402;',
'&Alpha;' => '&#913;',
'&Beta;' => '&#914;',
'&Gamma;' => '&#915;',
'&Delta;' => '&#916;',
'&Epsilon;' => '&#917;',
'&Zeta;' => '&#918;',
'&Eta;' => '&#919;',
'&Theta;' => '&#920;',
'&Iota;' => '&#921;',
'&Kappa;' => '&#922;',
'&Lambda;' => '&#923;',
'&Mu;' => '&#924;',
'&Nu;' => '&#925;',
'&Xi;' => '&#926;',
'&Omicron;' => '&#927;',
'&Pi;' => '&#928;',
'&Rho;' => '&#929;',
'&Sigma;' => '&#931;',
'&Tau;' => '&#932;',
'&Upsilon;' => '&#933;',
'&Phi;' => '&#934;',
'&Chi;' => '&#935;',
'&Psi;' => '&#936;',
'&Omega;' => '&#937;',
'&alpha;' => '&#945;',
'&beta;' => '&#946;',
'&gamma;' => '&#947;',
'&delta;' => '&#948;',
'&epsilon;' => '&#949;',
'&zeta;' => '&#950;',
'&eta;' => '&#951;',
'&theta;' => '&#952;',
'&iota;' => '&#953;',
'&kappa;' => '&#954;',
'&lambda;' => '&#955;',
'&mu;' => '&#956;',
'&nu;' => '&#957;',
'&xi;' => '&#958;',
'&omicron;' => '&#959;',
'&pi;' => '&#960;',
'&rho;' => '&#961;',
'&sigmaf;' => '&#962;',
'&sigma;' => '&#963;',
'&tau;' => '&#964;',
'&upsilon;' => '&#965;',
'&phi;' => '&#966;',
'&chi;' => '&#967;',
'&psi;' => '&#968;',
'&omega;' => '&#969;',
'&thetasym;' => '&#977;',
'&upsih;' => '&#978;',
'&piv;' => '&#982;',
'&bull;' => '&#8226;',
'&hellip;' => '&#8230;',
'&prime;' => '&#8242;',
'&Prime;' => '&#8243;',
'&oline;' => '&#8254;',
'&frasl;' => '&#8260;',
'&weierp;' => '&#8472;',
'&image;' => '&#8465;',
'&real;' => '&#8476;',
'&trade;' => '&#8482;',
'&alefsym;' => '&#8501;',
'&larr;' => '&#8592;',
'&uarr;' => '&#8593;',
'&rarr;' => '&#8594;',
'&darr;' => '&#8595;',
'&harr;' => '&#8596;',
'&crarr;' => '&#8629;',
'&lArr;' => '&#8656;',
'&uArr;' => '&#8657;',
'&rArr;' => '&#8658;',
'&dArr;' => '&#8659;',
'&hArr;' => '&#8660;',
'&forall;' => '&#8704;',
'&part;' => '&#8706;',
'&exist;' => '&#8707;',
'&empty;' => '&#8709;',
'&nabla;' => '&#8711;',
'&isin;' => '&#8712;',
'&notin;' => '&#8713;',
'&ni;' => '&#8715;',
'&prod;' => '&#8719;',
'&sum;' => '&#8721;',
'&minus;' => '&#8722;',
'&lowast;' => '&#8727;',
'&radic;' => '&#8730;',
'&prop;' => '&#8733;',
'&infin;' => '&#8734;',
'&ang;' => '&#8736;',
'&and;' => '&#8743;',
'&or;' => '&#8744;',
'&cap;' => '&#8745;',
'&cup;' => '&#8746;',
'&int;' => '&#8747;',
'&there4;' => '&#8756;',
'&sim;' => '&#8764;',
'&cong;' => '&#8773;',
'&asymp;' => '&#8776;',
'&ne;' => '&#8800;',
'&equiv;' => '&#8801;',
'&le;' => '&#8804;',
'&ge;' => '&#8805;',
'&sub;' => '&#8834;',
'&sup;' => '&#8835;',
'&nsub;' => '&#8836;',
'&sube;' => '&#8838;',
'&supe;' => '&#8839;',
'&oplus;' => '&#8853;',
'&otimes;' => '&#8855;',
'&perp;' => '&#8869;',
'&sdot;' => '&#8901;',
'&lceil;' => '&#8968;',
'&rceil;' => '&#8969;',
'&lfloor;' => '&#8970;',
'&rfloor;' => '&#8971;',
'&lang;' => '&#9001;',
'&rang;' => '&#9002;',
'&loz;' => '&#9674;',
'&spades;' => '&#9824;',
'&clubs;' => '&#9827;',
'&hearts;' => '&#9829;',
'&diams;' => '&#9830;'));

339
wiki/scripts/forms.php Executable file
View File

@@ -0,0 +1,339 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2005-2014 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
*/
# $InputAttrs are the attributes we allow in output tags
SDV($InputAttrs, array('name', 'value', 'id', 'class', 'rows', 'cols',
'size', 'maxlength', 'action', 'method', 'accesskey', 'tabindex', 'multiple',
'checked', 'disabled', 'readonly', 'enctype', 'src', 'alt',
'required', 'placeholder', 'autocomplete'
));
# Set up formatting for text, submit, hidden, radio, etc. types
foreach(array('text', 'submit', 'hidden', 'password', 'radio', 'checkbox',
'reset', 'file', 'image') as $t)
SDV($InputTags[$t][':html'], "<input type='$t' \$InputFormArgs />");
SDV($InputTags['text']['class'], 'inputbox');
SDV($InputTags['password']['class'], 'inputbox');
SDV($InputTags['submit']['class'], 'inputbutton');
SDV($InputTags['reset']['class'], 'inputbutton');
SDV($InputTags['radio'][':checked'], 'checked');
SDV($InputTags['checkbox'][':checked'], 'checked');
# (:input form:)
SDVA($InputTags['form'], array(
':args' => array('action', 'method'),
':html' => "<form \$InputFormArgs>",
'method' => 'post'));
# (:input end:)
SDV($InputTags['end'][':html'], '</form>');
# (:input textarea:)
SDVA($InputTags['textarea'], array(
':content' => array('value'),
':attr' => array_diff($InputAttrs, array('value')),
':html' => "<textarea \$InputFormArgs>\$InputFormContent</textarea>"));
# (:input image:)
SDV($InputTags['image'][':args'], array('name', 'src', 'alt'));
# (:input select:)
SDVA($InputTags['select-option'], array(
':args' => array('name', 'value', 'label'),
':content' => array('label', 'value', 'name'),
':attr' => array('value', 'selected'),
':checked' => 'selected',
':html' => "<option \$InputFormArgs>\$InputFormContent</option>"));
SDVA($InputTags['select'], array(
'class' => 'inputbox',
':html' => "<select \$InputSelectArgs>\$InputSelectOptions</select>"));
# (:input defaults?:)
SDVA($InputTags['default'], array(':fn' => 'InputDefault'));
SDVA($InputTags['defaults'], array(':fn' => 'InputDefault'));
## (:input ...:) directives
Markup_e('input', 'directives',
'/\\(:input\\s+(\\w+)(.*?):\\)/i',
"InputMarkup(\$pagename, \$m[1], \$m[2])");
## (:input select:) has its own markup processing
Markup_e('input-select', '<input',
'/\\(:input\\s+select\\s.*?:\\)(?:\\s*\\(:input\\s+select\\s.*?:\\))*/i',
"InputSelect(\$pagename, 'select', \$m[0])");
## The 'input+sp' rule combines multiple (:input select ... :)
## into a single markup line (to avoid split line effects)
Markup('input+sp', '<split',
'/(\\(:input\\s+select\\s(?>.*?:\\)))\\s+(?=\\(:input\\s)/', '$1');
SDV($InputFocusFmt,
"<script language='javascript' type='text/javascript'><!--
document.getElementById('\$InputFocusId').focus();//--></script>");
## InputToHTML performs standard processing on (:input ...:) arguments,
## and returns the formatted HTML string.
function InputToHTML($pagename, $type, $args, &$opt) {
global $InputTags, $InputAttrs, $InputValues, $FmtV, $KeepToken,
$InputFocusLevel, $InputFocusId, $InputFocusFmt, $HTMLFooterFmt;
if (!@$InputTags[$type]) return "(:input $type $args:)";
## get input arguments
if (!is_array($args)) $args = ParseArgs($args, '(?>([\\w-]+)[:=])');
## convert any positional arguments to named arguments
$posnames = @$InputTags[$type][':args'];
if (!$posnames) $posnames = array('name', 'value');
while (count($posnames) > 0 && count(@$args['']) > 0) {
$n = array_shift($posnames);
if (!isset($args[$n])) $args[$n] = array_shift($args['']);
}
## merge defaults for input type with arguments
$opt = array_merge($InputTags[$type], $args);
## www.w3.org/TR/html4/types
if(isset($opt['id'])) $opt['id'] = preg_replace('/[^-A-Za-z0-9:_.]+/', '_', $opt['id']);
## convert any remaining positional args to flags
foreach ((array)@$opt[''] as $a)
{ $a = strtolower($a); if (!isset($opt[$a])) $opt[$a] = $a; }
if (isset($opt['name'])) {
$opt['name'] = preg_replace('/^\\$:/', 'ptv_', @$opt['name']);
$opt['name'] = preg_replace('/[^-A-Za-z0-9:_.\\[\\]]+/', '_', $opt['name']);
$name = $opt['name'];
## set control values from $InputValues array
## radio, checkbox, select, etc. require a flag of some sort,
## others just set 'value'
if (isset($InputValues[$name])) {
$checked = @$opt[':checked'];
if ($checked) {
$opt[$checked] = in_array(@$opt['value'], (array)$InputValues[$name])
? $checked : false;
} else if (!isset($opt['value'])) $opt['value'] = $InputValues[$name];
}
}
## build $InputFormContent
$FmtV['$InputFormContent'] = '';
foreach((array)@$opt[':content'] as $a)
if (isset($opt[$a])) { $FmtV['$InputFormContent'] = $opt[$a]; break; }
## hash and store any "secure" values
if (@$opt['secure'] == '#') $opt['secure'] = rand();
if (@$opt['secure'] > '') {
$md5 = md5($opt['secure'] . $opt['value']);
@session_start();
$_SESSION['forms'][$md5] = $opt['value'];
$opt['value'] = $md5;
}
## handle focus=# option
$focus = @$opt['focus'];
if (isset($focus)
&& (!isset($InputFocusLevel) || $focus < $InputFocusLevel)) {
if (!isset($opt['id'])) $opt['id'] = "wikifocus$focus";
$InputFocusLevel = $focus;
$InputFocusId = $opt['id'];
$HTMLFooterFmt['inputfocus'] = $InputFocusFmt;
}
## build $InputFormArgs from $opt
$attrlist = (isset($opt[':attr'])) ? $opt[':attr'] : $InputAttrs;
$attr = array();
foreach ($attrlist as $a) {
if (!isset($opt[$a]) || $opt[$a]===false) continue;
if(strpos($opt[$a], $KeepToken)!== false) # multiline textarea/hidden fields
$opt[$a] = Keep(str_replace("'", '&#39;', MarkupRestore($opt[$a]) ));
$attr[] = "$a='".str_replace("'", '&#39;', $opt[$a])."'";
}
$FmtV['$InputFormArgs'] = implode(' ', $attr);
return FmtPageName($opt[':html'], $pagename);
}
## InputMarkup handles the (:input ...:) directive. It either
## calls any function given by the :fn element of the corresponding
## tag, or else just returns the result of InputToHTML().
function InputMarkup($pagename, $type, $args) {
global $InputTags;
$fn = @$InputTags[$type][':fn'];
if ($fn) return $fn($pagename, $type, $args);
return Keep(InputToHTML($pagename, $type, $args, $opt));
}
## (:input default:) directive.
function InputDefault($pagename, $type, $args) {
global $InputValues, $PageTextVarPatterns, $PCache;
$args = ParseArgs($args);
$args[''] = (array)@$args[''];
$name = (isset($args['name'])) ? $args['name'] : array_shift($args['']);
$name = preg_replace('/^\\$:/', 'ptv_', $name);
$value = (isset($args['value'])) ? $args['value'] : array_shift($args['']);
if (!isset($InputValues[$name])) $InputValues[$name] = $value;
if (@$args['request']) {
$req = array_merge($_GET, $_POST);
foreach($req as $k => $v)
if (!isset($InputValues[$k]))
$InputValues[$k] = PHSC(stripmagic($v), ENT_NOQUOTES);
}
$sources = @$args['source'];
if ($sources) {
foreach(explode(',', $sources) as $source) {
$source = MakePageName($pagename, $source);
if (!PageExists($source)) continue;
$page = RetrieveAuthPage($source, 'read', false, READPAGE_CURRENT);
if (! $page || ! isset($page['text'])) continue;
foreach((array)$PageTextVarPatterns as $pat)
if (preg_match_all($pat, IsEnabled($PCache[$source]['=preview'], $page['text']),
$match, PREG_SET_ORDER))
foreach($match as $m)
# if (!isset($InputValues['ptv_'.$m[2]])) PITS:01337
$InputValues['ptv_'.$m[2]] =
PHSC(Qualify($source, $m[3]), ENT_NOQUOTES);
break;
}
}
return '';
}
## (:input select ...:) is special, because we need to process a bunch of
## them as a single unit.
function InputSelect($pagename, $type, $markup) {
global $InputTags, $InputAttrs, $FmtV;
preg_match_all('/\\(:input\\s+\\S+\\s+(.*?):\\)/', $markup, $match);
$selectopt = (array)$InputTags[$type];
$opt = $selectopt;
$optionshtml = '';
$optiontype = isset($InputTags["$type-option"])
? "$type-option" : "select-option";
foreach($match[1] as $args) {
$optionshtml .= InputToHTML($pagename, $optiontype, $args, $oo);
$opt = array_merge($opt, $oo);
}
$attrlist = array_diff($InputAttrs, array('value'));
$attr = array();
foreach($attrlist as $a) {
if (!isset($opt[$a]) || $opt[$a]===false) continue;
$attr[] = "$a='".str_replace("'", '&#39;', $opt[$a])."'";
}
$FmtV['$InputSelectArgs'] = implode(' ', $attr);
$FmtV['$InputSelectOptions'] = $optionshtml;
return Keep(FmtPageName($selectopt[':html'], $pagename));
}
function InputActionForm($pagename, $type, $args) {
global $InputAttrs;
$args = ParseArgs($args);
if (@$args['pagename']) $pagename = $args['pagename'];
$opt = NULL;
$html = InputToHTML($pagename, $type, $args, $opt);
foreach(preg_grep('/^[\\w$]/', array_keys($args)) as $k) {
if (is_array($args[$k]) || in_array($k, $InputAttrs)) continue;
if ($k == 'n' || $k == 'pagename') continue;
$html .= "<input type='hidden' name='$k' value='{$args[$k]}' />";
}
return Keep($html);
}
## RequestArgs is used to extract values from controls (typically
## in $_GET and $_POST).
function RequestArgs($req = NULL) {
if (is_null($req)) $req = array_merge($_GET, $_POST);
foreach ($req as $k => $v) $req[$k] = stripmagic($req[$k]);
return $req;
}
## Form-based authorization prompts (for use with PmWikiAuth)
SDVA($InputTags['auth_form'], array(
':html' => "<form \$InputFormArgs>\$PostVars",
'action' => str_replace("'", '%37', stripmagic($_SERVER['REQUEST_URI'])),
'method' => 'post',
'name' => 'authform'));
SDV($AuthPromptFmt, array(&$PageStartFmt, 'page:$SiteGroup.AuthForm',
"<script language='javascript' type='text/javascript'><!--
try { document.authform.authid.focus(); }
catch(e) { document.authform.authpw.focus(); } //--></script>",
&$PageEndFmt));
## PITS:01188, these should exist in "browse" mode
## NOTE: also defined in prefs.php
XLSDV('en', array(
'ak_save' => 's',
'ak_saveedit' => 'u',
'ak_preview' => 'p',
'ak_textedit' => ',',
'e_rows' => '23',
'e_cols' => '60'));
## The section below handles specialized EditForm pages.
## We don't bother to load it if we're not editing.
if ($action != 'edit') return;
SDV($PageEditForm, '$SiteGroup.EditForm');
SDV($PageEditFmt, '$EditForm');
if (@$_REQUEST['editform']) {
$PageEditForm=$_REQUEST['editform'];
$PageEditFmt='$EditForm';
}
$Conditions['e_preview'] = '(boolean)$_REQUEST["preview"]';
# (:e_preview:) displays the preview of formatted text.
Markup_e('e_preview', 'directives',
'/^\\(:e_preview:\\)/',
"isset(\$GLOBALS['FmtV']['\$PreviewText']) ? Keep(\$GLOBALS['FmtV']['\$PreviewText']): ''");
# If we didn't load guiedit.php, then set (:e_guibuttons:) to
# simply be empty.
Markup('e_guibuttons', 'directives', '/\\(:e_guibuttons:\\)/', '');
# Prevent (:e_preview:) and (:e_guibuttons:) from
# participating in text rendering step.
SDV($SaveAttrPatterns['/\\(:e_(preview|guibuttons):\\)/'], ' ');
SDVA($InputTags['e_form'], array(
':html' => "<form action='{\$PageUrl}?action=edit' method='post'
\$InputFormArgs><input type='hidden' name='action' value='edit'
/><input type='hidden' name='n' value='{\$FullName}'
/><input type='hidden' name='basetime' value='\$EditBaseTime'
/>"));
SDVA($InputTags['e_textarea'], array(
':html' => "<textarea \$InputFormArgs
onkeydown='if (event.keyCode==27) event.returnValue=false;'
>\$EditText</textarea>",
'name' => 'text', 'id' => 'text', 'accesskey' => XL('ak_textedit'),
'rows' => XL('e_rows'), 'cols' => XL('e_cols')));
SDVA($InputTags['e_author'], array(
':html' => "<input type='text' \$InputFormArgs />",
'name' => 'author', 'value' => $Author));
SDVA($InputTags['e_changesummary'], array(
':html' => "<input type='text' \$InputFormArgs />",
'name' => 'csum', 'size' => '60', 'maxlength' => '100',
'value' => PHSC(stripmagic(@$_POST['csum']), ENT_QUOTES)));
SDVA($InputTags['e_minorcheckbox'], array(
':html' => "<input type='checkbox' \$InputFormArgs />",
'name' => 'diffclass', 'value' => 'minor'));
if (@$_POST['diffclass']=='minor')
SDV($InputTags['e_minorcheckbox']['checked'], 'checked');
SDVA($InputTags['e_savebutton'], array(
':html' => "<input type='submit' \$InputFormArgs />",
'name' => 'post', 'value' => ' '.XL('Save').' ',
'accesskey' => XL('ak_save')));
SDVA($InputTags['e_saveeditbutton'], array(
':html' => "<input type='submit' \$InputFormArgs />",
'name' => 'postedit', 'value' => ' '.XL('Save and edit').' ',
'accesskey' => XL('ak_saveedit')));
SDVA($InputTags['e_savedraftbutton'], array(':html' => ''));
SDVA($InputTags['e_previewbutton'], array(
':html' => "<input type='submit' \$InputFormArgs />",
'name' => 'preview', 'value' => ' '.XL('Preview').' ',
'accesskey' => XL('ak_preview')));
SDVA($InputTags['e_cancelbutton'], array(
':html' => "<input type='submit' \$InputFormArgs />",
'name' => 'cancel', 'value' => ' '.XL('Cancel').' ' ));
SDVA($InputTags['e_resetbutton'], array(
':html' => "<input type='reset' \$InputFormArgs />",
'value' => ' '.XL('Reset').' '));

82
wiki/scripts/guiedit.php Executable file
View File

@@ -0,0 +1,82 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2013 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script adds a graphical button bar to the edit page form.
The buttons are placed in the $GUIButtons array; each button
is specified by an array of five values:
- the position of the button relative to others (a number)
- the opening markup sequence
- the closing markup sequence
- the default text if none was highlighted
- the text of the button, either (a) HTML markup or (b) the
url of a gif/jpg/png image to be used for the button
(along with optional "title" text in quotes).
The buttons specified in this file are the default buttons
for the standard markups. Some buttons (e.g., the attach/upload
button) are specified in their respective cookbook module.
*/
SDVA($HTMLHeaderFmt, array('guiedit' => "<script type='text/javascript'
src='\$FarmPubDirUrl/guiedit/guiedit.js'></script>\n"));
SDV($GUIButtonDirUrlFmt,'$FarmPubDirUrl/guiedit');
SDVA($GUIButtons, array(
'em' => array(100, "''", "''", '$[Emphasized]',
'$GUIButtonDirUrlFmt/em.gif"$[Emphasized (italic)]"',
'$[ak_em]'),
'strong' => array(110, "'''", "'''", '$[Strong]',
'$GUIButtonDirUrlFmt/strong.gif"$[Strong (bold)]"',
'$[ak_strong]'),
'pagelink' => array(200, '[[', ']]', '$[Page link]',
'$GUIButtonDirUrlFmt/pagelink.gif"$[Link to internal page]"'),
'extlink' => array(210, '[[', ']]', 'http:// | $[link text]',
'$GUIButtonDirUrlFmt/extlink.gif"$[Link to external page]"'),
'big' => array(300, "'+", "+'", '$[Big text]',
'$GUIButtonDirUrlFmt/big.gif"$[Big text]"'),
'small' => array(310, "'-", "-'", '$[Small text]',
'$GUIButtonDirUrlFmt/small.gif"$[Small text]"'),
'sup' => array(320, "'^", "^'", '$[Superscript]',
'$GUIButtonDirUrlFmt/sup.gif"$[Superscript]"'),
'sub' => array(330, "'_", "_'", '$[Subscript]',
'$GUIButtonDirUrlFmt/sub.gif"$[Subscript]"'),
'h2' => array(400, '\\n!! ', '\\n', '$[Heading]',
'$GUIButtonDirUrlFmt/h.gif"$[Heading]"'),
'center' => array(410, '%center%', '', '',
'$GUIButtonDirUrlFmt/center.gif"$[Center]"')));
Markup_e('e_guibuttons', 'directives',
'/\\(:e_guibuttons:\\)/',
"Keep(FmtPageName(GUIButtonCode(\$pagename), \$pagename))");
function GUIButtonCode($pagename) {
global $GUIButtons;
$cmpfn = create_function('$a,$b', 'return $a[0]-$b[0];');
usort($GUIButtons, $cmpfn);
$out = "<script type='text/javascript'><!--\n";
foreach ($GUIButtons as $k => $g) {
if (!$g) continue;
@list($when, $mopen, $mclose, $mtext, $tag, $mkey) = $g;
if ($tag{0} == '<') {
$out .= "document.write(\"$tag\");\n";
continue;
}
if (preg_match('/^(.*\\.(gif|jpg|png))("([^"]+)")?$/', $tag, $m)) {
$title = (@$m[4] > '') ? "title='{$m[4]}'" : '';
$tag = "<img src='{$m[1]}' $title style='border:0px;' />";
}
$mopen = str_replace(array('\\', "'"), array('\\\\', "\\\\'"), $mopen);
$mclose = str_replace(array('\\', "'"), array('\\\\', "\\\\'"), $mclose);
$mtext = str_replace(array('\\', "'"), array('\\\\', "\\\\'"), $mtext);
$out .=
"insButton(\"$mopen\", \"$mclose\", '$mtext', \"$tag\", \"$mkey\");\n";
}
$out .= '//--></script>';
return $out;
}

46
wiki/scripts/httpauth.php Executable file
View File

@@ -0,0 +1,46 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2005 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This file defines an alternate authentication scheme based on the
HTTP Basic authentication protocol (i.e., the scheme used by default
in PmWiki 1).
*/
## If the webserver has already authenticated someone, then use
## that identifier for our authorization id. We also disable
## the use of the browser's Basic Auth form later, since it tends
## to confuse webservers.
if (IsEnabled($EnableRemoteUserAuth, 1) && @$_SERVER['REMOTE_USER']) {
SDV($EnableHTTPBasicAuth, 0);
SDV($AuthId, $_SERVER['REMOTE_USER']);
}
## If the browser supplied a password, add that password to the
## list of passwords used for authentication
if (@$_SERVER['PHP_AUTH_PW'])
SessionAuth($pagename, array('authpw'=>array($_SERVER['PHP_AUTH_PW'] => 1)));
## $EnableHTTPBasicAuth tells PmWikiAuth to use the browser's
## HTTP Basic protocol prompt instead of a form-based prompt.
if (IsEnabled($EnableHTTPBasicAuth, 1))
SDV($AuthPromptFmt, 'function:HTTPBasicAuthPrompt');
## HTTPBasicAuthPrompt replaces PmWikiAuth's form-based password
## prompt with the browser-based HTTP Basic prompt.
function HTTPBasicAuthPrompt($pagename) {
global $AuthRealmFmt, $AuthDeniedFmt;
SDV($AuthRealmFmt,$GLOBALS['WikiTitle']);
SDV($AuthDeniedFmt,'A valid password is required to access this feature.');
$realm=FmtPageName($AuthRealmFmt,$pagename);
header("WWW-Authenticate: Basic realm=\"$realm\"");
header("Status: 401 Unauthorized");
header("HTTP-Status: 401 Unauthorized");
PrintFmt($pagename,$AuthDeniedFmt);
exit;
}

10
wiki/scripts/intermap.txt Executable file
View File

@@ -0,0 +1,10 @@
PmWiki: http://www.pmwiki.org/wiki/PmWiki/
Cookbook: http://www.pmwiki.org/wiki/Cookbook/
Skins: http://www.pmwiki.org/wiki/Skins/
Wiki: http://www.c2.com/cgi/wiki?
UseMod: http://www.usemod.com/cgi-bin/wiki.pl?
Meatball: http://www.usemod.com/cgi-bin/mb.pl?
Wikipedia: http://en.wikipedia.org/wiki/
PITS: http://www.pmwiki.org/wiki/PITS/
PmL10n: http://www.pmwiki.org/wiki/Localization/
Path:

124
wiki/scripts/markupexpr.php Executable file
View File

@@ -0,0 +1,124 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2007-2014 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script implements "markup expressions" -- a method to
do simple computations and manipulations from markup. The
generic form of a markup expression is "{(func arg1 arg2)}",
where the named function (held in the $MarkupExpr array)
is called with arg1 and arg2 as arguments.
Markup expressions can be nested. For example, to strip
off the first five characters and convert the remainder to
lowercase, an author can write:
{(tolower (substr "HELLOWORLD" 5))} # produces "world"
Some "built-in" expressions defined by this recipe include:
substr - extract a portion of a string
ftime - date/time formatting
strlen - length of a string
rand - generate a random number
pagename - build a pagename from a string
toupper - convert string to uppercase
tolower - convert string to lowercase
ucfirst - convert first character to uppercase
ucwords - convert first character of each word to uppercase
asspaced - spaceformatting of wikiwords
Custom expressions may be added by other recipes by adding
entries into the $MarkupExpr array. Each entry's key is
the name of the function, the value is the code to be evaluated
for that function (similar to the way $FmtPV works). By default,
any arguments for the expression are placed into the $args array:
## expressions like {(myfunc foo bar)}
$MarkupExpr['myfunc'] = 'myfunc($args[0], $args[1])';
The expression arguments are parsed using ParseArgs(), and the
result of this parsing is available through the $argp array:
## expressions like {(myfunc fmt=foo output=bar)}
$MarkupExpr['myfunc'] = 'myfunc($argp["fmt"], $argp["output"])';
Finally, if the code in $MarkupExpr contains '$params', then
it is executed directly without any preprocessing into arguments,
and $params contains the entire argument string. Note that $params
may contain escaped values representing quoted arguments and
results of other expressions; these values may be un-escaped
by using "preg_replace($rpat, $rrep, $params)".
*/
Markup_e('{(', '>{$var}',
'/\\{(\\(\\w+\\b.*?\\))\\}/',
"MarkupExpression(\$pagename, \$m[1])");
SDVA($MarkupExpr, array(
'substr' => 'call_user_func_array("substr", $args)',
'strlen' => 'strlen($args[0])',
'ftime' => 'ME_ftime(@$args[0], @$args[1], $argp)',
'rand' => '($args) ? rand($args[0], $args[1]) : rand()',
'ucfirst' => 'ucfirst($args[0])',
'ucwords' => 'ucwords($args[0])',
'tolower' => 'strtolower($args[0])',
'toupper' => 'strtoupper($args[0])',
'mod' => '0 + ($args[0] % $args[1])',
'asspaced' => '$GLOBALS["AsSpacedFunction"]($args[0])',
'pagename' => 'MakePageName($pagename, PPRE($rpat, $rrep, $params))',
));
function MarkupExpression($pagename, $expr) {
global $KeepToken, $KPV, $MarkupExpr;
$rpat = "/$KeepToken(\\d+P)$KeepToken/";
$rrep = '$GLOBALS["KPV"][$m[1]]';
$expr = PPRE('/([\'"])(.*?)\\1/', "Keep(\$m[2],'P')", $expr);
$expr = PPRE('/\\(\\W/', "Keep(\$m[0],'P')", $expr);
while (preg_match('/\\((\\w+)(\\s[^()]*)?\\)/', $expr, $match)) {
list($repl, $func, $params) = $match;
$code = @$MarkupExpr[$func];
## if not a valid function, save this string as-is and exit
if (!$code) break;
## if the code uses '$params', we just evaluate directly
if (strpos($code, '$params') !== false) {
$out = eval("return ({$code});");
if ($expr == $repl) { $expr = $out; break; }
$expr = str_replace($repl, $out, $expr);
continue;
}
## otherwise, we parse arguments into $args before evaluating
$argp = ParseArgs($params);
$x = $argp['#']; $args = array();
while ($x) {
list($k, $v) = array_splice($x, 0, 2);
if ($k == '' || $k == '+' || $k == '-')
$args[] = $k.PPRE($rpat, $rrep, $v);
}
## fix any quoted arguments
foreach ($argp as $k => $v)
if (!is_array($v)) $argp[$k] = PPRE($rpat, $rrep, $v);
$out = eval("return ({$code});");
if ($expr == $repl) { $expr = $out; break; }
$expr = str_replace($repl, Keep($out, 'P'), $expr);
}
return PPRE($rpat, $rrep, $expr);
}
## ME_ftime handles {(ftime ...)} expressions.
##
function ME_ftime($arg0 = '', $arg1 = '', $argp = NULL) {
global $TimeFmt, $Now, $FTimeFmt;
if (@$argp['fmt']) $fmt = $argp['fmt'];
else if (strpos($arg0, '%') !== false) { $fmt = $arg0; $arg0 = $arg1; }
else if (strpos($arg1, '%') !== false) $fmt = $arg1;
## determine the timestamp
if (isset($argp['when'])) list($time, $x) = DRange($argp['when']);
else if ($arg0 > '') list($time, $x) = DRange($arg0);
else $time = $Now;
if (@$fmt == '') { SDV($FTimeFmt, $TimeFmt); $fmt = $FTimeFmt; }
## make sure we have %F available for ISO dates
$fmt = str_replace(array('%F', '%s'), array('%Y-%m-%d', $time), $fmt);
return strftime($fmt, $time);
}

197
wiki/scripts/notify.php Executable file
View File

@@ -0,0 +1,197 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2006-2011 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script enables email notifications to be sent when posts
are made. It is included by default from the stdconfig.php
script if $EnableNotify is set to non-zero.
Once enabled, the addresses to receive messages are configured
via the Site.NotifyList page. A simple line in that page
such as
notify=somebody@example.com
will cause messages to be periodically sent to "somebody@example.com"
listing the pages that have changed on the site since the previous
message was sent. Multiple notify lines can be placed in the page,
and there are options to restrict the types of notifications
desired. For more details, see the PmWiki.Notify page in
the documentation.
Several variables set defaults for this script:
$NotifyFrom - return email address to use in message.
$NotifyDelay - number of seconds to wait before sending mail
after the first post.
$NotifySquelch - minimum number of seconds between sending email
messages to each address. Individual "notify=" lines in
Site.NotifyList can override this value via a custom "squelch="
parameter.
$NotifyFile - scratchpad file used to keep track of pending emails.
$NotifyListPageFmt - name of the NotifyList configuration page.
$NotifySubjectFmt - subject line for sent messages.
$NotifyBodyFmt - body of message to be sent. The string '$NotifyItems'
is replaced with the list of posts in the email.
$NotifyItemFmt - the format for each post to be included in a notification.
$NotifyTimeFmt - the format for dates and times ($PostTime)
in notification messages.
$NotifyHeaders - any additional message headers to be sent.
$NotifyParameters - any additional parameters to be passed to PHP's
mail() function.
*/
SDV($NotifyDelay, 0);
SDV($NotifySquelch, 10800);
SDV($NotifyFile, "$WorkDir/.notifylist");
SDV($NotifyListPageFmt, '$SiteAdminGroup.NotifyList');
SDV($NotifySubjectFmt, '[$WikiTitle] recent notify posts');
SDV($NotifyBodyFmt,
"Recent \$WikiTitle posts:\n"
. " \$ScriptUrl/$[{\$SiteGroup}/AllRecentChanges]\n\n\$NotifyItems\n");
SDV($NotifyTimeFmt, $TimeFmt);
SDV($NotifyItemFmt,
' * {$FullName} . . . $PostTime by {$Author}');
SDV($NotifyHeaders, '');
SDV($NotifyParameters, '');
if (@$NotifyFrom)
$NotifyHeaders = "From: $NotifyFrom\r\n$NotifyHeaders";
$EditFunctions[] = 'PostNotify';
## check if we need to do notifications
if ($action != 'edit' && $action != 'postupload') NotifyCheck($pagename);
function NotifyCheck($pagename) {
global $NotifyFile, $Now, $LastModTime;
$nfp = @fopen($NotifyFile, 'r');
if (!$nfp) return;
$nextevent = fgets($nfp);
fclose($nfp);
if ($Now < $nextevent && $LastModTime < filemtime($NotifyFile)) return;
register_shutdown_function('NotifyUpdate', $pagename, getcwd());
}
function PostNotify($pagename, &$page, &$new) {
global $IsPagePosted;
if ($IsPagePosted)
register_shutdown_function('NotifyUpdate', $pagename, getcwd());
}
function NotifyUpdate($pagename, $dir='') {
global $NotifyList, $NotifyListPageFmt, $NotifyFile, $IsPagePosted, $IsUploadPosted,
$FmtV, $NotifyTimeFmt, $NotifyItemFmt, $SearchPatterns,
$NotifySquelch, $NotifyDelay, $Now, $Charset, $EnableNotifySubjectEncode,
$NotifySubjectFmt, $NotifyBodyFmt, $NotifyHeaders, $NotifyParameters;
$abort = ignore_user_abort(true);
if ($dir) { flush(); chdir($dir); }
$GLOBALS['EnableRedirect'] = 0;
## Read in the current notify configuration
$pn = FmtPageName($NotifyListPageFmt, $pagename);
$npage = ReadPage($pn, READPAGE_CURRENT);
preg_match_all('/^[\s*:#->]*(notify[:=].*)/m', $npage['text'], $nlist);
$nlist = array_merge((array)@$NotifyList, (array)@$nlist[1]);
if (!$nlist) return;
## make sure other processes are locked out
Lock(2);
## let's load the current .notifylist table
$nfile = FmtPageName($NotifyFile, $pagename);
$nfp = @fopen($nfile, 'r');
if ($nfp) {
## get our current squelch and delay timestamps
clearstatcache();
$sz = filesize($nfile);
list($nextevent, $firstpost) = explode(' ', rtrim(fgets($nfp, $sz)));
## restore our notify array
$notify = unserialize(fgets($nfp, $sz));
fclose($nfp);
}
if (!is_array($notify)) $notify = array();
## if this is for a newly posted page, get its information
if ($IsPagePosted || $IsUploadPosted) {
$page = ReadPage($pagename, READPAGE_CURRENT);
$FmtV['$PostTime'] = strftime($NotifyTimeFmt, $Now);
$item = urlencode(FmtPageName($NotifyItemFmt, $pagename));
if ($firstpost < 1) $firstpost = $Now;
}
foreach($nlist as $n) {
$opt = ParseArgs($n);
$mailto = preg_split('/[\s,]+/', $opt['notify']);
if (!$mailto) continue;
if ($opt['squelch'])
foreach($mailto as $m) $squelch[$m] = $opt['squelch'];
if (!$IsPagePosted) continue;
if ($opt['link']) {
$link = MakePageName($pagename, $opt['link']);
if (!preg_match("/(^|,)$link(,|$)/i", $page['targets'])) continue;
}
$pats = @(array)$SearchPatterns[$opt['list']];
if ($opt['group']) $pats[] = FixGlob($opt['group'], '$1$2.*');
if ($opt['name']) $pats[] = FixGlob($opt['name'], '$1*.$2');
if ($pats && !MatchPageNames($pagename, $pats)) continue;
if ($opt['trail']) {
$trail = ReadTrail($pagename, $opt['trail']);
for ($i=0; $i<count($trail); $i++)
if ($trail[$i]['pagename'] == $pagename) break;
if ($i >= count($trail)) continue;
}
foreach($mailto as $m) { $notify[$m][] = $item; }
}
$nnow = time();
if ($nnow < $firstpost + $NotifyDelay)
$nextevent = $firstpost + $NotifyDelay;
else {
$firstpost = 0;
$nextevent = $nnow + 86400;
$mailto = array_keys($notify);
$subject = FmtPageName($NotifySubjectFmt, $pagename);
if(IsEnabled($EnableNotifySubjectEncode, 0)
&& preg_match("/[^\x20-\x7E]/", $subject))
$subject = strtoupper("=?$Charset?B?"). base64_encode($subject)."?=";
$body = FmtPageName($NotifyBodyFmt, $pagename);
foreach ($mailto as $m) {
$msquelch = @$notify[$m]['lastmail'] +
((@$squelch[$m]) ? $squelch[$m] : $NotifySquelch);
if ($nnow < $msquelch) {
if ($msquelch < $nextevent && count($notify[$m])>1)
$nextevent = $msquelch;
continue;
}
unset($notify[$m]['lastmail']);
if (!$notify[$m]) { unset($notify[$m]); continue; }
$mbody = str_replace('$NotifyItems',
urldecode(implode("\n", $notify[$m])), $body);
if ($NotifyParameters && !@ini_get('safe_mode'))
mail($m, $subject, $mbody, $NotifyHeaders, $NotifyParameters);
else
mail($m, $subject, $mbody, $NotifyHeaders);
$notify[$m] = array('lastmail' => $nnow);
}
}
## save the updated notify status
$nfp = @fopen($nfile, "w");
if ($nfp) {
fputs($nfp, "$nextevent $firstpost\n");
fputs($nfp, serialize($notify) . "\n");
fclose($nfp);
}
Lock(0);
return true;
}

856
wiki/scripts/pagelist.php Executable file
View File

@@ -0,0 +1,856 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2014 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script implements (:pagelist:) and friends -- it's one
of the nastiest scripts you'll ever encounter. Part of the reason
for this is that page listings are so powerful and flexible, so
that adds complexity. They're also expensive, so we have to
optimize them wherever we can.
The core function is FmtPageList(), which will generate a
listing according to a wide variety of options. FmtPageList takes
care of initial option processing, and then calls a "FPL"
(format page list) function to obtain the formatted output.
The FPL function is chosen by the 'fmt=' option to (:pagelist:).
Each FPL function calls MakePageList() to obtain the list
of pages, formats the list somehow, and returns the results
to FmtPageList. FmtPageList then returns the output to
the caller, and calls Keep() (preserves HTML) or PRR() (re-evaluate
as markup) as appropriate for the output being returned.
*/
## $PageIndexFile is the index file for term searches and link= option
if (IsEnabled($EnablePageIndex, 1)) {
SDV($PageIndexFile, "$WorkDir/.pageindex");
$EditFunctions[] = 'PostPageIndex';
}
SDV($StrFoldFunction, 'strtolower');
## $SearchPatterns holds patterns for list= option
SDV($SearchPatterns['all'], array());
SDVA($SearchPatterns['normal'], array(
'recent' => '!\.(All)?Recent(Changes|Uploads)$!',
'group' => '!\.Group(Print)?(Header|Footer|Attributes)$!',
'self' => str_replace('.', '\\.', "!^$pagename$!")));
## $FPLFormatOpt is a list of options associated with fmt=
## values. 'default' is used for any undefined values of fmt=.
SDVA($FPLFormatOpt, array(
'default' => array('fn' => 'FPLTemplate', 'fmt' => '#default'),
'bygroup' => array('fn' => 'FPLTemplate', 'template' => '#bygroup',
'class' => 'fplbygroup'),
'simple' => array('fn' => 'FPLTemplate', 'template' => '#simple',
'class' => 'fplsimple'),
'group' => array('fn' => 'FPLTemplate', 'template' => '#group',
'class' => 'fplgroup'),
'title' => array('fn' => 'FPLTemplate', 'template' => '#title',
'class' => 'fpltitle', 'order' => 'title'),
'count' => array('fn' => 'FPLCountA'),
));
SDV($SearchResultsFmt, "<div class='wikisearch'>\$[SearchFor]
<div class='vspace'></div>\$MatchList
<div class='vspace'></div>\$[SearchFound]</div>");
SDV($SearchQuery, str_replace('$', '&#036;',
PHSC(stripmagic(@$_REQUEST['q']), ENT_NOQUOTES)));
XLSDV('en', array(
'SearchFor' => 'Results of search for <em>$Needle</em>:',
'SearchFound' =>
'$MatchCount pages found out of $MatchSearched pages searched.'));
SDV($PageListArgPattern, '((?:\\$:?)?\\w+)[:=]');
Markup_e('pagelist', 'directives',
'/\\(:pagelist(\\s+.*?)?:\\)/i',
"FmtPageList('\$MatchList', \$pagename, array('o' => \$m[1].' '))");
Markup_e('searchbox', 'directives',
'/\\(:searchbox(\\s.*?)?:\\)/',
"SearchBox(\$pagename, ParseArgs(\$m[1], '$PageListArgPattern'))");
Markup_e('searchresults', 'directives',
'/\\(:searchresults(\\s+.*?)?:\\)/i',
"FmtPageList(\$GLOBALS['SearchResultsFmt'], \$pagename,
array('req' => 1, 'request'=>1, 'o' => \$m[1]))");
SDV($SaveAttrPatterns['/\\(:(searchresults|pagelist)(\\s+.*?)?:\\)/i'], ' ');
SDV($HandleActions['search'], 'HandleSearchA');
SDV($HandleAuth['search'], 'read');
SDV($ActionTitleFmt['search'], '| $[Search Results]');
SDVA($PageListFilters, array(
'PageListCache' => 80,
'PageListProtect' => 90,
'PageListSources' => 100,
'PageListPasswords' => 120,
'PageListIf' => 140,
'PageListTermsTargets' => 160,
'PageListVariables' => 180,
'PageListSort' => 900,
));
foreach(array('random', 'size', 'time', 'ctime') as $o)
SDV($PageListSortCmp[$o], "@(\$PCache[\$x]['$o']-\$PCache[\$y]['$o'])");
SDV($PageListSortCmp['title'],
'@strcasecmp($PCache[$x][\'=title\'], $PCache[$y][\'=title\'])');
define('PAGELIST_PRE' , 1);
define('PAGELIST_ITEM', 2);
define('PAGELIST_POST', 4);
## SearchBox generates the output of the (:searchbox:) markup.
## If $SearchBoxFmt is defined, that is used, otherwise a searchbox
## is generated. Options include group=, size=, label=.
function SearchBox($pagename, $opt) {
global $SearchBoxFmt, $SearchBoxOpt, $SearchQuery, $EnablePathInfo;
if (isset($SearchBoxFmt)) return Keep(FmtPageName($SearchBoxFmt, $pagename));
SDVA($SearchBoxOpt, array('size' => '40',
'label' => FmtPageName('$[Search]', $pagename),
'value' => str_replace("'", "&#039;", $SearchQuery)));
$opt = array_merge((array)$SearchBoxOpt, @$_GET, (array)$opt);
$opt['action'] = 'search';
$target = (@$opt['target'])
? MakePageName($pagename, $opt['target']) : $pagename;
$opt['n'] = IsEnabled($EnablePathInfo, 0) ? '' : $target;
$out = FmtPageName(" class='wikisearch' action='\$PageUrl' method='get'>",
$target);
foreach($opt as $k => $v) {
if ($v == '' || is_array($v)) continue;
$v = str_replace("'", "&#039;", $v);
$opt[$k] = $v;
if ($k == 'q' || $k == 'label' || $k == 'value' || $k == 'size') continue;
$k = str_replace("'", "&#039;", $k);
$out .= "<input type='hidden' name='$k' value='$v' />";
}
$out .= "<input type='text' name='q' value='{$opt['value']}'
class='inputbox searchbox' size='{$opt['size']}' /><input type='submit'
class='inputbutton searchbutton' value='{$opt['label']}' />";
return '<form '.Keep($out).'</form>';
}
## FmtPageList combines options from markup, request form, and url,
## calls the appropriate formatting function, and returns the string.
function FmtPageList($outfmt, $pagename, $opt) {
global $GroupPattern, $FmtV, $PageListArgPattern,
$FPLFormatOpt, $FPLFunctions;
# get any form or url-submitted request
$rq = PHSC(stripmagic(@$_REQUEST['q']), ENT_NOQUOTES);
# build the search string
$FmtV['$Needle'] = $opt['o'] . ' ' . $rq;
# Handle "group/" at the beginning of the form-submitted request
if (preg_match("!^($GroupPattern(\\|$GroupPattern)*)?/!i", $rq, $match)) {
$opt['group'] = @$match[1];
$rq = substr($rq, strlen(@$match[1])+1);
}
$opt = array_merge($opt, ParseArgs($opt['o'], $PageListArgPattern));
# merge markup options with form and url
if (@$opt['request'] && @$_REQUEST) {
$rkeys = preg_grep('/^=/', array_keys($_REQUEST), PREG_GREP_INVERT);
if ($opt['request'] != '1') {
list($incl, $excl) = GlobToPCRE($opt['request']);
if ($excl) $rkeys = array_diff($rkeys, preg_grep("/$excl/", $rkeys));
if ($incl) $rkeys = preg_grep("/$incl/", $rkeys);
}
$cleanrequest = array();
foreach($rkeys as $k) {
$cleanrequest[$k] = stripmagic($_REQUEST[$k]);
}
$opt = array_merge($opt, ParseArgs($rq, $PageListArgPattern), $cleanrequest);
}
# non-posted blank search requests return nothing
if (@($opt['req'] && !$opt['-'] && !$opt[''] && !$opt['+'] && !$opt['q']))
return '';
# terms and group to be included and excluded
$GLOBALS['SearchIncl'] = array_merge((array)@$opt[''], (array)@$opt['+']);
$GLOBALS['SearchExcl'] = (array)@$opt['-'];
$GLOBALS['SearchGroup'] = @$opt['group'];
$fmt = @$opt['fmt']; if (!$fmt) $fmt = 'default';
$fmtopt = @$FPLFormatOpt[$fmt];
if (!is_array($fmtopt)) {
if ($fmtopt) $fmtopt = array('fn' => $fmtopt);
elseif (@$FPLFunctions[$fmt])
$fmtopt = array('fn' => $FPLFunctions[$fmt]);
else $fmtopt = $FPLFormatOpt['default'];
}
$fmtfn = @$fmtopt['fn'];
if (!is_callable($fmtfn)) $fmtfn = $FPLFormatOpt['default']['fn'];
$matches = array();
$opt = array_merge($fmtopt, $opt);
$out = $fmtfn($pagename, $matches, $opt);
$FmtV['$MatchCount'] = count($matches);
if ($outfmt != '$MatchList')
{ $FmtV['$MatchList'] = $out; $out = FmtPageName($outfmt, $pagename); }
if ($out[0] == '<') $out = Keep($out);
return PRR($out);
}
## MakePageList generates a list of pages using the specifications given
## by $opt.
function MakePageList($pagename, $opt, $retpages = 1) {
global $MakePageListOpt, $PageListFilters, $PCache;
StopWatch('MakePageList pre');
SDVA($MakePageListOpt, array('list' => 'default'));
$opt = array_merge((array)$MakePageListOpt, (array)$opt);
if (!@$opt['order'] && !@$opt['trail']) $opt['order'] = 'name';
$opt['order'] = preg_replace('/[^-\\w:$]+/', ',', $opt['order']);
ksort($opt); $opt['=key'] = md5(serialize($opt));
$itemfilters = array(); $postfilters = array();
asort($PageListFilters);
$opt['=phase'] = PAGELIST_PRE; $list=array(); $pn=NULL; $page=NULL;
foreach($PageListFilters as $fn => $v) {
if ($v<0) continue;
$ret = $fn($list, $opt, $pagename, $page);
if ($ret & PAGELIST_ITEM) $itemfilters[] = $fn;
if ($ret & PAGELIST_POST) $postfilters[] = $fn;
}
StopWatch("MakePageList items count=".count($list).", filters=".implode(',',$itemfilters));
$opt['=phase'] = PAGELIST_ITEM;
$matches = array(); $opt['=readc'] = 0;
foreach((array)$list as $pn) {
$page = array();
foreach((array)$itemfilters as $fn)
if (!$fn($list, $opt, $pn, $page)) continue 2;
$page['pagename'] = $page['name'] = $pn;
PCache($pn, $page);
$matches[] = $pn;
}
$list = $matches;
StopWatch("MakePageList post count=".count($list).", readc={$opt['=readc']}");
$opt['=phase'] = PAGELIST_POST; $pn=NULL; $page=NULL;
foreach((array)$postfilters as $fn)
$fn($list, $opt, $pagename, $page);
if ($retpages)
for($i=0; $i<count($list); $i++)
$list[$i] = &$PCache[$list[$i]];
StopWatch('MakePageList end');
return $list;
}
function PageListProtect(&$list, &$opt, $pn, &$page) {
global $EnablePageListProtect;
switch ($opt['=phase']) {
case PAGELIST_PRE:
if (!IsEnabled($EnablePageListProtect, 1) && @$opt['readf'] < 1000)
return 0;
StopWatch("PageListProtect enabled");
$opt['=protectexclude'] = array();
$opt['=protectsafe'] = (array)@$opt['=protectsafe'];
return PAGELIST_ITEM|PAGELIST_POST;
case PAGELIST_ITEM:
if (@$opt['=protectsafe'][$pn]) return 1;
$page = RetrieveAuthPage($pn, 'ALWAYS', false, READPAGE_CURRENT);
$opt['=readc']++;
if (!$page['=auth']['read']) $opt['=protectexclude'][$pn] = 1;
if (!$page['=passwd']['read']) $opt['=protectsafe'][$pn] = 1;
else NoCache();
return 1;
case PAGELIST_POST:
$excl = array_keys($opt['=protectexclude']);
$safe = array_keys($opt['=protectsafe']);
StopWatch("PageListProtect excluded=" .count($excl)
. ", safe=" . count($safe));
$list = array_diff($list, $excl);
return 1;
}
}
function PageListSources(&$list, &$opt, $pn, &$page) {
global $SearchPatterns;
StopWatch('PageListSources begin');
## add the list= option to our list of pagename filter patterns
$opt['=pnfilter'] = array_merge((array)@$opt['=pnfilter'],
(array)@$SearchPatterns[$opt['list']]);
if (@$opt['group']) $opt['=pnfilter'][] = FixGlob($opt['group'], '$1$2.*');
if (@$opt['name']) $opt['=pnfilter'][] = FixGlob($opt['name'], '$1*.$2');
if (@$opt['trail']) {
$trail = ReadTrail($pn, $opt['trail']);
$tlist = array();
foreach($trail as $tstop) {
$n = $tstop['pagename'];
$tlist[] = $n;
$tstop['parentnames'] = array();
PCache($n, $tstop);
}
foreach($trail as $tstop)
$PCache[$tstop['pagename']]['parentnames'][] =
@$trail[$tstop['parent']]['pagename'];
if (!@$opt['=cached']) $list = MatchPageNames($tlist, $opt['=pnfilter']);
} else if (!@$opt['=cached']) $list = ListPages($opt['=pnfilter']);
StopWatch("PageListSources end count=".count($list));
return 0;
}
function PageListPasswords(&$list, &$opt, $pn, &$page) {
if ($opt['=phase'] == PAGELIST_PRE)
return (@$opt['passwd'] > '' && !@$opt['=cached']) ? PAGELIST_ITEM : 0;
if (!$page) { $page = ReadPage($pn, READPAGE_CURRENT); $opt['=readc']++; }
if (!$page) return 0;
return (boolean)preg_grep('/^passwd/', array_keys($page));
}
function PageListIf(&$list, &$opt, $pn, &$page) {
global $Conditions, $Cursor;
## See if we have any "if" processing to perform
if ($opt['=phase'] == PAGELIST_PRE)
return (@$opt['if'] > '') ? PAGELIST_ITEM : 0;
$condspec = $opt['if'];
$Cursor['='] = $pn;
$varpat = '\\{([=*]|!?[-\\w.\\/\\x80-\\xff]*)(\\$:?\\w+)\\}';
while (preg_match("/$varpat/", $condspec, $match)) {
$condspec = PPRE("/$varpat/",
"PVSE(PageVar('$pn', \$m[2], \$m[1]))", $condspec);
}
if (!preg_match("/^\\s*(!?)\\s*(\\S*)\\s*(.*?)\\s*$/", $condspec, $match))
return 0;
list($x, $not, $condname, $condparm) = $match;
if (!isset($Conditions[$condname])) return 1;
$tf = (int)@eval("return ({$Conditions[$condname]});");
return (boolean)($tf xor $not);
}
function PageListTermsTargets(&$list, &$opt, $pn, &$page) {
global $FmtV;
static $reindex = array();
$fold = $GLOBALS['StrFoldFunction'];
switch ($opt['=phase']) {
case PAGELIST_PRE:
$FmtV['$MatchSearched'] = count($list);
$incl = array(); $excl = array();
foreach((array)@$opt[''] as $i) { $incl[] = $fold($i); }
foreach((array)@$opt['+'] as $i) { $incl[] = $fold($i); }
foreach((array)@$opt['-'] as $i) { $excl[] = $fold($i); }
$indexterms = PageIndexTerms($incl);
foreach($incl as $i) {
$delim = (!preg_match('/[^\\w\\x80-\\xff]/', $i)) ? '$' : '/';
$opt['=inclp'][] = $delim . preg_quote($i,$delim) . $delim . 'i';
}
if ($excl)
$opt['=exclp'][] = '$'.implode('|', array_map('preg_quote',$excl)).'$i';
if (@$opt['link']) {
$link = MakePageName($pn, $opt['link']);
$opt['=linkp'] = "/(^|,)$link(,|$)/i";
$indexterms[] = " $link ";
}
if (@$opt['=cached']) return 0;
if ($indexterms) {
StopWatch("PageListTermsTargets begin count=".count($list));
$xlist = PageIndexGrep($indexterms, true);
$list = array_diff($list, $xlist);
StopWatch("PageListTermsTargets end count=".count($list));
}
if (@$opt['=inclp'] || @$opt['=exclp'] || @$opt['=linkp'])
return PAGELIST_ITEM|PAGELIST_POST;
return 0;
case PAGELIST_ITEM:
if (!$page) { $page = ReadPage($pn, READPAGE_CURRENT); $opt['=readc']++; }
if (!$page) return 0;
if (@$opt['=linkp'] && !preg_match($opt['=linkp'], @$page['targets']))
{ $reindex[] = $pn; return 0; }
if (@$opt['=inclp'] || @$opt['=exclp']) {
$text = $fold($pn."\n".@$page['targets']."\n".@$page['text']);
foreach((array)@$opt['=exclp'] as $i)
if (preg_match($i, $text)) return 0;
foreach((array)@$opt['=inclp'] as $i)
if (!preg_match($i, $text)) {
if ($i{0} == '$') $reindex[] = $pn;
return 0;
}
}
return 1;
case PAGELIST_POST:
if ($reindex) PageIndexQueueUpdate($reindex);
$reindex = array();
return 0;
}
}
function PageListVariables(&$list, &$opt, $pn, &$page) {
switch ($opt['=phase']) {
case PAGELIST_PRE:
$varlist = preg_grep('/^\\$/', array_keys($opt));
if (!$varlist) return 0;
foreach($varlist as $v) {
list($inclp, $exclp) = GlobToPCRE($opt[$v]);
if ($inclp) $opt['=varinclp'][$v] = "/$inclp/i";
if ($exclp) $opt['=varexclp'][$v] = "/$exclp/i";
}
return PAGELIST_ITEM;
case PAGELIST_ITEM:
if (@$opt['=varinclp'])
foreach($opt['=varinclp'] as $v => $pat)
if (!preg_match($pat, PageVar($pn, $v))) return 0;
if (@$opt['=varexclp'])
foreach($opt['=varexclp'] as $v => $pat)
if (preg_match($pat, PageVar($pn, $v))) return 0;
return 1;
}
}
function PageListSort(&$list, &$opt, $pn, &$page) {
global $PageListSortCmp, $PCache, $PageListSortRead;
SDVA($PageListSortRead, array('name' => 0, 'group' => 0, 'random' => 0,
'title' => 0));
switch ($opt['=phase']) {
case PAGELIST_PRE:
$ret = 0;
foreach(preg_split('/[^-\\w:$]+/', @$opt['order'], -1, PREG_SPLIT_NO_EMPTY)
as $o) {
$ret |= PAGELIST_POST;
$r = '+';
if ($o{0} == '-') { $r = '-'; $o = substr($o, 1); }
$opt['=order'][$o] = $r;
if ($o{0} != '$' &&
(!isset($PageListSortRead[$o]) || $PageListSortRead[$o]))
$ret |= PAGELIST_ITEM;
}
StopWatch(@"PageListSort pre ret=$ret order={$opt['order']}");
return $ret;
case PAGELIST_ITEM:
if (!$page) { $page = ReadPage($pn, READPAGE_CURRENT); $opt['=readc']++; }
return 1;
}
## case PAGELIST_POST
StopWatch('PageListSort begin');
$order = $opt['=order'];
if (@$order['title'])
foreach($list as $pn) $PCache[$pn]['=title'] = PageVar($pn, '$Title');
if (@$order['group'])
foreach($list as $pn) $PCache[$pn]['group'] = PageVar($pn, '$Group');
if (@$order['random'])
{ NoCache(); foreach($list as $pn) $PCache[$pn]['random'] = rand(); }
foreach(preg_grep('/^\\$/', array_keys($order)) as $o)
foreach($list as $pn)
$PCache[$pn][$o] = PageVar($pn, $o);
$code = '';
foreach($opt['=order'] as $o => $r) {
if (@$PageListSortCmp[$o])
$code .= "\$c = {$PageListSortCmp[$o]}; ";
else
$code .= "\$c = @strcasecmp(\$PCache[\$x]['$o'],\$PCache[\$y]['$o']); ";
$code .= "if (\$c) return $r\$c;\n";
}
StopWatch('PageListSort sort');
if ($code)
uasort($list,
create_function('$x,$y', "global \$PCache; $code return 0;"));
StopWatch('PageListSort end');
}
function PageListCache(&$list, &$opt, $pn, &$page) {
global $PageListCacheDir, $LastModTime, $PageIndexFile;
if (@!$PageListCacheDir) return 0;
if (isset($opt['cache']) && !$opt['cache']) return 0;
$key = $opt['=key'];
$cache = "$PageListCacheDir/$key,cache";
switch ($opt['=phase']) {
case PAGELIST_PRE:
if (!file_exists($cache) || filemtime($cache) <= $LastModTime)
return PAGELIST_POST;
StopWatch("PageListCache begin load key=$key");
list($list, $opt['=protectsafe']) =
unserialize(file_get_contents($cache));
$opt['=cached'] = 1;
StopWatch("PageListCache end load");
return 0;
case PAGELIST_POST:
StopWatch("PageListCache begin save key=$key");
$fp = @fopen($cache, "w");
if ($fp) {
fputs($fp, serialize(array($list, $opt['=protectsafe'])));
fclose($fp);
}
StopWatch("PageListCache end save");
return 0;
}
return 0;
}
## HandleSearchA performs ?action=search. It's basically the same
## as ?action=browse, except it takes its contents from Site.Search.
function HandleSearchA($pagename, $level = 'read') {
global $PageSearchForm, $FmtV, $HandleSearchFmt,
$PageStartFmt, $PageEndFmt;
SDV($HandleSearchFmt,array(&$PageStartFmt, '$PageText', &$PageEndFmt));
SDV($PageSearchForm, '$[{$SiteGroup}/Search]');
$form = RetrieveAuthPage($pagename, $level, true, READPAGE_CURRENT);
if (!$form) Abort("?unable to read $pagename");
PCache($pagename, $form);
$text = preg_replace('/\\[([=@])(.*?)\\1\\]/s', ' ', @$form['text']);
if (!preg_match('/\\(:searchresults(\\s.*?)?:\\)/', $text))
foreach((array)$PageSearchForm as $formfmt) {
$form = ReadPage(FmtPageName($formfmt, $pagename), READPAGE_CURRENT);
if ($form['text']) break;
}
$text = @$form['text'];
if (!$text) $text = '(:searchresults:)';
$FmtV['$PageText'] = MarkupToHTML($pagename,$text);
PrintFmt($pagename, $HandleSearchFmt);
}
########################################################################
## The functions below provide different formatting options for
## the output list, controlled by the fmt= parameter and the
## $FPLFormatOpt hash.
########################################################################
## This helper function handles the count= parameter for extracting
## a range of pagelist in the list.
function CalcRange($range, $n) {
if ($n < 1) return array(0, 0);
if (strpos($range, '..') === false) {
if ($range > 0) return array(1, min($range, $n));
if ($range < 0) return array(max($n + $range + 1, 1), $n);
return array(1, $n);
}
list($r0, $r1) = explode('..', $range);
if ($r0 < 0) $r0 += $n + 1;
if ($r1 < 0) $r1 += $n + 1;
else if ($r1 == 0) $r1 = $n;
if ($r0 < 1 && $r1 < 1) return array($n+1, $n+1);
return array(max($r0, 1), max($r1, 1));
}
## FPLCountA handles fmt=count
function FPLCountA($pagename, &$matches, $opt) {
$matches = array_values(MakePageList($pagename, $opt, 0));
return count($matches);
}
SDVA($FPLTemplateFunctions, array(
'FPLTemplateLoad' => 100,
'FPLTemplateDefaults' => 200,
'FPLTemplatePageList' => 300,
'FPLTemplateSliceList' => 400,
'FPLTemplateFormat' => 500
));
function FPLTemplate($pagename, &$matches, $opt) {
global $FPLTemplateFunctions;
StopWatch("FPLTemplate: Chain begin");
asort($FPLTemplateFunctions, SORT_NUMERIC);
$fnlist = $FPLTemplateFunctions;
$output = '';
foreach($FPLTemplateFunctions as $fn=>$i) {
if ($i<0) continue;
StopWatch("FPLTemplate: $fn");
$fn($pagename, $matches, $opt, $tparts, $output);
}
StopWatch("FPLTemplate: Chain end");
return $output;
}
## Loads a template section
function FPLTemplateLoad($pagename, $matches, $opt, &$tparts){
global $Cursor, $FPLTemplatePageFmt, $RASPageName, $PageListArgPattern;
SDV($FPLTemplatePageFmt, array('{$FullName}',
'{$SiteGroup}.LocalTemplates', '{$SiteGroup}.PageListTemplates'));
$template = @$opt['template'];
if (!$template) $template = @$opt['fmt'];
$ttext = RetrieveAuthSection($pagename, $template, $FPLTemplatePageFmt);
$ttext = PVSE(Qualify($RASPageName, $ttext));
## save any escapes
$ttext = MarkupEscape($ttext);
## remove any anchor markups to avoid duplications
$ttext = preg_replace('/\\[\\[#[A-Za-z][-.:\\w]*\\]\\]/', '', $ttext);
## extract portions of template
$tparts = preg_split('/\\(:(template)\\s+([-!]?)\\s*(\\w+)\\s*(.*?):\\)/i',
$ttext, -1, PREG_SPLIT_DELIM_CAPTURE);
}
## Merge parameters from (:template default :) with those in the (:pagelist:)
function FPLTemplateDefaults($pagename, $matches, &$opt, &$tparts){
global $PageListArgPattern;
$i = 0;
while ($i < count($tparts)) {
if ($tparts[$i] != 'template') { $i++; continue; }
if ($tparts[$i+2] != 'defaults' && $tparts[$i+2] != 'default') { $i+=5; continue; }
$pvars = $GLOBALS['MarkupTable']['{$var}']; # expand {$PVars}
$ttext = preg_replace_callback($pvars['pat'], $pvars['rep'], $tparts[$i+3]);
$opt = array_merge(ParseArgs($ttext, $PageListArgPattern), $opt);
array_splice($tparts, $i, 4);
}
SDVA($opt, array('class' => 'fpltemplate', 'wrap' => 'div'));
}
## get the list of pages
function FPLTemplatePageList($pagename, &$matches, &$opt){
$matches = array_unique(array_merge((array)$matches, MakePageList($pagename, $opt, 0)));
## count matches before any slicing and save value as template var {$$PageListCount}
$opt['PageListCount'] = count($matches);
}
## extract page subset according to 'count=' parameter
function FPLTemplateSliceList($pagename, &$matches, $opt){
if (@$opt['count']) {
list($r0, $r1) = CalcRange($opt['count'], count($matches));
if ($r1 < $r0)
$matches = array_reverse(array_slice($matches, $r1-1, $r0-$r1+1));
else
$matches = array_slice($matches, $r0-1, $r1-$r0+1);
}
}
function FPLTemplateFormat($pagename, $matches, $opt, $tparts, &$output){
global $Cursor, $FPLTemplateMarkupFunction, $PCache;
SDV($FPLTemplateMarkupFunction, 'MarkupToHTML');
$savecursor = $Cursor;
$pagecount = $groupcount = $grouppagecount = $traildepth = 0;
$pseudovars = array('{$$PageCount}' => &$pagecount,
'{$$GroupCount}' => &$groupcount,
'{$$GroupPageCount}' => &$grouppagecount,
'{$$PageTrailDepth}' => &$traildepth);
foreach(preg_grep('/^[\\w$]/', array_keys($opt)) as $k)
if (!is_array($opt[$k]))
$pseudovars["{\$\$$k}"] = PHSC($opt[$k], ENT_NOQUOTES);
$vk = array_keys($pseudovars);
$vv = array_values($pseudovars);
$lgroup = ''; $out = '';
if(count($matches)==0 ) {
$t = 0;
while($t < count($tparts)) {
if($tparts[$t]=='template' && $tparts[$t+2]=='none') {
$out .= MarkupRestore(FPLExpandItemVars($tparts[$t+4], $matches, 0, $pseudovars));
$t+=4;
}
$t++;
}
} # else:
foreach($matches as $i => $pn) {
$traildepth = intval(@$PCache[$pn]['depth']);
$group = PageVar($pn, '$Group');
if ($group != $lgroup) { $groupcount++; $grouppagecount = 0; $lgroup = $group; }
$grouppagecount++; $pagecount++;
$t = 0;
while ($t < count($tparts)) {
if ($tparts[$t] != 'template') { $item = $tparts[$t]; $t++; }
else {
list($neg, $when, $control, $item) = array_slice($tparts, $t+1, 4); $t+=5;
if($when=='none') continue;
if (!$control) {
if ($when == 'first' && ($neg xor ($i != 0))) continue;
if ($when == 'last' && ($neg xor ($i != count($matches) - 1))) continue;
} else {
if ($when == 'first' || !isset($last[$t])) {
$curr = FPLExpandItemVars($control, $matches, $i, $pseudovars);
if ($when == 'first' && ($neg xor (($i != 0) && ($last[$t] == $curr))))
{ $last[$t] = $curr; continue; }
$last[$t] = $curr;
}
if ($when == 'last') {
$next = FPLExpandItemVars($control, $matches, $i+1, $pseudovars);
if ($neg xor ($next == $last[$t] && $i != count($matches) - 1)) continue;
$last[$t] = $next;
}
}
}
$item = FPLExpandItemVars($item, $matches, $i, $pseudovars);
$out .= MarkupRestore($item);
}
}
$class = preg_replace('/[^-a-zA-Z0-9\\x80-\\xff]/', ' ', @$opt['class']);
if ($class) $class = " class='$class'";
$wrap = @$opt['wrap'];
if ($wrap != 'inline') {
$out = $FPLTemplateMarkupFunction($pagename, $out, array('escape' => 0, 'redirect'=>1));
if ($wrap != 'none') $out = "<div$class>$out</div>";
}
$Cursor = $savecursor;
$output .= $out;
}
## This function moves repeated code blocks out of FPLTemplateFormat()
function FPLExpandItemVars($item, $matches, $idx, $psvars) {
global $Cursor, $EnableUndefinedTemplateVars;
$Cursor['<'] = $Cursor['&lt;'] = (string)@$matches[$idx-1];
$Cursor['='] = $pn = (string)@$matches[$idx];
$Cursor['>'] = $Cursor['&gt;'] = (string)@$matches[$idx+1];
$item = str_replace(array_keys($psvars), array_values($psvars), $item);
$item = PPRE('/\\{(=|&[lg]t;)(\\$:?\\w[-\\w]*)\\}/',
"PVSE(PageVar('$pn', \$m[2], \$m[1]))", $item);
if(! IsEnabled($EnableUndefinedTemplateVars, 0))
$item = preg_replace("/\\{\\$\\$\\w+\\}/", '', $item);
return $item;
}
########################################################################
## The functions below optimize searches by maintaining a file of
## words and link cross references (the "page index").
########################################################################
## PageIndexTerms($terms) takes an array of strings and returns a
## normalized list of associated search terms. This reduces the
## size of the index and speeds up searches.
function PageIndexTerms($terms) {
global $StrFoldFunction;
$w = array();
foreach((array)$terms as $t) {
$w = array_merge($w, preg_split('/[^\\w\\x80-\\xff]+/',
$StrFoldFunction($t), -1, PREG_SPLIT_NO_EMPTY));
}
return $w;
}
## The PageIndexUpdate($pagelist) function updates the page index
## file with terms and target links for the pages in $pagelist.
## The optional $dir parameter allows this function to be called
## via register_shutdown_function (which sometimes changes directories
## on us).
function PageIndexUpdate($pagelist = NULL, $dir = '') {
global $EnableReadOnly, $PageIndexUpdateList, $PageIndexFile,
$PageIndexTime, $Now;
if (IsEnabled($EnableReadOnly, 0)) return;
$abort = ignore_user_abort(true);
if ($dir) { flush(); chdir($dir); }
if (is_null($pagelist))
{ $pagelist = (array)$PageIndexUpdateList; $PageIndexUpdateList = array(); }
if (!$pagelist || !$PageIndexFile) return;
SDV($PageIndexTime, 10);
$c = count($pagelist); $updatecount = 0;
StopWatch("PageIndexUpdate begin ($c pages to update)");
$pagelist = (array)$pagelist;
$timeout = time() + $PageIndexTime;
$cmpfn = create_function('$a,$b', 'return strlen($b)-strlen($a);');
Lock(2);
$ofp = fopen("$PageIndexFile,new", 'w');
foreach($pagelist as $pn) {
if (@$updated[$pn]) continue;
@$updated[$pn]++;
if (time() > $timeout) continue;
$page = ReadPage($pn, READPAGE_CURRENT);
if ($page) {
$targets = str_replace(',', ' ', @$page['targets']);
$terms = PageIndexTerms(array(@$page['text'], $targets, $pn));
usort($terms, $cmpfn);
$x = '';
foreach($terms as $t) { if (strpos($x, $t) === false) $x .= " $t"; }
fputs($ofp, "$pn:$Now: $targets :$x\n");
}
$updatecount++;
}
$ifp = @fopen($PageIndexFile, 'r');
if ($ifp) {
while (!feof($ifp)) {
$line = fgets($ifp, 4096);
while (substr($line, -1, 1) != "\n" && !feof($ifp))
$line .= fgets($ifp, 4096);
$i = strpos($line, ':');
if ($i === false) continue;
$n = substr($line, 0, $i);
if (@$updated[$n]) continue;
fputs($ofp, $line);
}
fclose($ifp);
}
fclose($ofp);
if (file_exists($PageIndexFile)) unlink($PageIndexFile);
rename("$PageIndexFile,new", $PageIndexFile);
fixperms($PageIndexFile);
StopWatch("PageIndexUpdate end ($updatecount updated)");
ignore_user_abort($abort);
}
## PageIndexQueueUpdate specifies pages to be updated in
## the index upon shutdown (via register_shutdown function).
function PageIndexQueueUpdate($pagelist) {
global $PageIndexUpdateList;
if (!@$PageIndexUpdateList)
register_shutdown_function('PageIndexUpdate', NULL, getcwd());
$PageIndexUpdateList = array_merge((array)@$PageIndexUpdateList,
(array)$pagelist);
$c1 = count($pagelist); $c2 = count($PageIndexUpdateList);
StopWatch("PageIndexQueueUpdate: queued $c1 pages ($c2 total)");
}
## PageIndexGrep returns a list of pages that match the strings
## provided. Note that some search terms may need to be normalized
## in order to get the desired results (see PageIndexTerms above).
## Also note that this just works for the index; if the index is
## incomplete, then so are the results returned by this list.
## (MakePageList above already knows how to deal with this.)
function PageIndexGrep($terms, $invert = false) {
global $PageIndexFile;
if (!$PageIndexFile) return array();
StopWatch('PageIndexGrep begin');
$pagelist = array();
$fp = @fopen($PageIndexFile, 'r');
if ($fp) {
$terms = (array)$terms;
while (!feof($fp)) {
$line = fgets($fp, 4096);
while (substr($line, -1, 1) != "\n" && !feof($fp))
$line .= fgets($fp, 4096);
$i = strpos($line, ':');
if (!$i) continue;
$add = true;
foreach($terms as $t)
if (strpos($line, $t) === false) { $add = false; break; }
if ($add xor $invert) $pagelist[] = substr($line, 0, $i);
}
fclose($fp);
}
StopWatch('PageIndexGrep end');
return $pagelist;
}
## PostPageIndex is inserted into $EditFunctions to update
## the linkindex whenever a page is saved.
function PostPageIndex($pagename, &$page, &$new) {
global $IsPagePosted;
if ($IsPagePosted) PageIndexQueueUpdate($pagename);
}

218
wiki/scripts/pagerev.php Executable file
View File

@@ -0,0 +1,218 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2014 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script defines routines for displaying page revisions. It
is included by default from the stdconfig.php script.
*/
function LinkSuppress($pagename,$imap,$path,$title,$txt,$fmt=NULL)
{ return $txt; }
SDV($DiffShow['minor'],(@$_REQUEST['minor']!='n')?'y':'n');
SDV($DiffShow['source'],(@$_REQUEST['source']!='n')?'y':'n');
SDV($DiffMinorFmt, ($DiffShow['minor']=='y') ?
"<a href='{\$PageUrl}?action=diff&amp;source=".$DiffShow['source']."&amp;minor=n'>$[Hide minor edits]</a>" :
"<a href='{\$PageUrl}?action=diff&amp;source=".$DiffShow['source']."&amp;minor=y'>$[Show minor edits]</a>" );
SDV($DiffSourceFmt, ($DiffShow['source']=='y') ?
"<a href='{\$PageUrl}?action=diff&amp;source=n&amp;minor=".$DiffShow['minor']."'>$[Show changes to output]</a>" :
"<a href='{\$PageUrl}?action=diff&amp;source=y&amp;minor=".$DiffShow['minor']."'>$[Show changes to markup]</a>");
SDV($PageDiffFmt,"<h2 class='wikiaction'>$[{\$FullName} History]</h2>
<p>$DiffMinorFmt - $DiffSourceFmt</p>
");
SDV($DiffStartFmt,"
<div class='diffbox'><div class='difftime'><a name='diff\$DiffGMT' href='#diff\$DiffGMT'>\$DiffTime</a>
\$[by] <span class='diffauthor' title='\$DiffHost'>\$DiffAuthor</span> - \$DiffChangeSum</div>");
SDV($DiffDelFmt['a'],"
<div class='difftype'>\$[Deleted line \$DiffLines:]</div>
<div class='diffdel'>");
SDV($DiffDelFmt['c'],"
<div class='difftype'>\$[Changed line \$DiffLines from:]</div>
<div class='diffdel'>");
SDV($DiffAddFmt['d'],"
<div class='difftype'>\$[Added line \$DiffLines:]</div>
<div class='diffadd'>");
SDV($DiffAddFmt['c'],"</div>
<div class='difftype'>$[to:]</div>
<div class='diffadd'>");
SDV($DiffEndDelAddFmt,"</div>");
SDV($DiffEndFmt,"</div>");
SDV($DiffRestoreFmt,"
<div class='diffrestore'><a href='{\$PageUrl}?action=edit&amp;restore=\$DiffId&amp;preview=y'>$[Restore]</a></div>");
SDV($HandleActions['diff'], 'HandleDiff');
SDV($HandleAuth['diff'], 'read');
SDV($ActionTitleFmt['diff'], '| $[History]');
SDV($HTMLStylesFmt['diff'], "
.diffbox { width:570px; border-left:1px #999999 solid; margin-top:1.33em; }
.diffauthor { font-weight:bold; }
.diffchangesum { font-weight:bold; }
.difftime { font-family:verdana,sans-serif; font-size:66%;
background-color:#dddddd; }
.difftype { clear:both; font-family:verdana,sans-serif;
font-size:66%; font-weight:bold; }
.diffadd { border-left:5px #99ff99 solid; padding-left:5px; }
.diffdel { border-left:5px #ffff99 solid; padding-left:5px; }
.diffrestore { clear:both; font-family:verdana,sans-serif;
font-size:66%; margin:1.5em 0px; }
.diffmarkup { font-family:monospace; }
.diffmarkup del { background:#ffff99; text-decoration: none; }
.diffmarkup ins { background:#99ff99; text-decoration: none; }");
function PrintDiff($pagename) {
global $DiffHTMLFunction,$DiffShow,$DiffStartFmt,$TimeFmt,
$DiffEndFmt,$DiffRestoreFmt,$FmtV, $LinkFunctions;
$page = ReadPage($pagename);
if (!$page) return;
krsort($page); reset($page);
$lf = $LinkFunctions;
$LinkFunctions['http:'] = 'LinkSuppress';
$LinkFunctions['https:'] = 'LinkSuppress';
SDV($DiffHTMLFunction, 'DiffHTML');
foreach($page as $k=>$v) {
if (!preg_match("/^diff:(\d+):(\d+):?([^:]*)/",$k,$match)) continue;
$diffclass = $match[3];
if ($diffclass=='minor' && $DiffShow['minor']!='y') continue;
$diffgmt = $FmtV['$DiffGMT'] = $match[1];
$FmtV['$DiffTime'] = strftime($TimeFmt,$diffgmt);
$diffauthor = @$page["author:$diffgmt"];
if (!$diffauthor) @$diffauthor=$page["host:$diffgmt"];
if (!$diffauthor) $diffauthor="unknown";
$FmtV['$DiffChangeSum'] = PHSC(@$page["csum:$diffgmt"]);
$FmtV['$DiffHost'] = @$page["host:$diffgmt"];
$FmtV['$DiffAuthor'] = $diffauthor;
$FmtV['$DiffId'] = $k;
$html = $DiffHTMLFunction($pagename, $v);
if ($html===false) continue;
echo FmtPageName($DiffStartFmt,$pagename);
echo $html;
echo FmtPageName($DiffEndFmt,$pagename);
echo FmtPageName($DiffRestoreFmt,$pagename);
}
$LinkFunctions = $lf;
}
# This function converts a single diff entry from the wikipage file
# into HTML, ready for display.
function DiffHTML($pagename, $diff) {
if (@$_REQUEST['nodiff']>'') return '';
global $FmtV, $DiffShow, $DiffAddFmt, $DiffDelFmt, $DiffEndDelAddFmt,
$DiffRenderSourceFunction;
SDV($DiffRenderSourceFunction, 'DiffRenderSource');
$difflines = explode("\n",$diff."\n");
$in=array(); $out=array(); $dtype=''; $html = '';
foreach($difflines as $d) {
if ($d>'') {
if ($d[0]=='-' || $d[0]=='\\') continue;
if ($d[0]=='<') { $out[]=substr($d,2); continue; }
if ($d[0]=='>') { $in[]=substr($d,2); continue; }
}
if (preg_match("/^(\\d+)(,(\\d+))?([adc])(\\d+)(,(\\d+))?/",
$dtype,$match)) {
if (@$match[7]>'') {
$lines='lines';
$count=$match[1].'-'.($match[1]+$match[7]-$match[5]);
} elseif ($match[3]>'') {
$lines='lines'; $count=$match[1].'-'.$match[3];
} else { $lines='line'; $count=$match[1]; }
if ($match[4]=='a' || $match[4]=='c') {
$txt = str_replace('line',$lines,$DiffDelFmt[$match[4]]);
$FmtV['$DiffLines'] = $count;
$html .= FmtPageName($txt,$pagename);
if ($DiffShow['source']=='y')
$html .= "<div class='diffmarkup'>"
.$DiffRenderSourceFunction($in, $out, 0)
."</div>";
else $html .= MarkupToHTML($pagename,
PPRE('/\\(:.*?:\\)/',"Keep(PHSC(\$m[0]))", join("\n",$in)));
}
if ($match[4]=='d' || $match[4]=='c') {
$txt = str_replace('line',$lines,$DiffAddFmt[$match[4]]);
$FmtV['$DiffLines'] = $count;
$html .= FmtPageName($txt,$pagename);
if ($DiffShow['source']=='y')
$html .= "<div class='diffmarkup'>"
.$DiffRenderSourceFunction($in, $out, 1)
."</div>";
else $html .= MarkupToHTML($pagename,
PPRE('/\\(:.*?:\\)/',"Keep(PHSC(\$m[0]))",join("\n",$out)));
}
$html .= FmtPageName($DiffEndDelAddFmt,$pagename);
}
$in=array(); $out=array(); $dtype=$d;
}
return $html;
}
function HandleDiff($pagename, $auth='read') {
global $HandleDiffFmt, $PageStartFmt, $PageDiffFmt, $PageEndFmt;
$page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT);
if (!$page) { Abort("?cannot diff $pagename"); }
PCache($pagename, $page);
SDV($HandleDiffFmt,array(&$PageStartFmt,
&$PageDiffFmt,"<div id='wikidiff'>", 'function:PrintDiff', '</div>',
&$PageEndFmt));
PrintFmt($pagename,$HandleDiffFmt);
}
## Functions for simple word-diff (written by Petko Yotov)
function DiffRenderSource($in, $out, $which) {
global $WordDiffFunction, $EnableDiffInline;
if (!IsEnabled($EnableDiffInline, 1)) {
$a = $which? $out : $in;
return str_replace("\n","<br />",PHSC(join("\n",$a)));
}
$countdifflines = abs(count($in)-count($out));
$lines = $cnt = $x2 = $y2 = array();
foreach($in as $line) {
$tmp = $countdifflines>20 ? array($line) : DiffPrepareInline($line);
if(!$which) $cnt[] = array(count($x2), count($tmp));
$x2 = array_merge($x2, $tmp);
}
foreach($out as $line) {
$tmp = $countdifflines>20 ? array($line) : DiffPrepareInline($line);
if($which) $cnt[] = array(count($y2), count($tmp));
$y2 = array_merge($y2, $tmp);
}
$z = $WordDiffFunction(implode("\n", $x2), implode("\n", $y2));
$z2 = array_map('PHSC', ($which? $y2 : $x2));
array_unshift($z2, '');
foreach (explode("\n", $z) as $zz) {
if (preg_match('/^(\\d+)(,(\\d+))?([adc])(\\d+)(,(\\d+))?/',$zz,$m)) {
$a1 = $a2 = $m[1];
if ($m[3]) $a2=$m[3];
$b1 = $b2 = $m[5];
if ($m[7]) $b2=$m[7];
if (!$which && ($m[4]=='c'||$m[4]=='d')) {
$z2[$a1] = '<del>'. $z2[$a1];
$z2[$a2] .= '</del>';
}
if ($which && ($m[4]=='c'||$m[4]=='a')) {
$z2[$b1] = '<ins>'.$z2[$b1];
$z2[$b2] .= '</ins>';
}
}
}
$line = array_shift($z2);
$z2[0] = $line.$z2[0];
foreach ($cnt as $a) $lines[] = implode('', array_slice($z2, $a[0], $a[1]));
$ret = implode("\n", $lines);
$ret = str_replace(array('</del> <del>', '</ins> <ins>'), ' ', $ret);
$ret = preg_replace('/(<(ins|del)>|^) /', '$1&nbsp;', $ret);
return str_replace(array(" ", "\n ", "\n"),array("&nbsp; ", "<br />&nbsp;", "<br />"),$ret);
}
## Split a line into pieces before passing it through `diff`
function DiffPrepareInline($x) {
global $DiffSplitInlineDelims;
SDV($DiffSplitInlineDelims, "-@!?#$%^&*()=+[]{}.'\"\\:|,<>_/;~");
return preg_split("/([".preg_quote($DiffSplitInlineDelims, '/')."\\s])/",
$x, -1, PREG_SPLIT_DELIM_CAPTURE);
}
SDV($WordDiffFunction, 'PHPDiff'); # faster than sysdiff for many calls
if (IsEnabled($EnableDiffInline, 1) && $DiffShow['source'] == 'y'
&& $WordDiffFunction == 'PHPDiff' && !function_exists('PHPDiff'))
include_once("$FarmD/scripts/phpdiff.php");

39
wiki/scripts/pgcust.php Executable file
View File

@@ -0,0 +1,39 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2002-2005 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script enables per-page and per-group customizations in the
local/ subdirectory (or whatever directory is given by $LocalDir).
For example, to create customizations for the 'Demo' group, place
them in a file called local/Demo.php. To customize a single page,
use the full page name (e.g., local/Demo.MyPage.php).
Per-page/per-group customizations can be handled at any time by adding
include_once("scripts/pgcust.php");
to config.php. It is automatically included by scripts/stdconfig.php
unless $EnablePGCust is set to zero in config.php.
A page's customization is loaded first, followed by any group
customization. If no page or group customizations are loaded,
then 'local/default.php' is loaded.
A per-page configuration file can prevent its group's config from
loading by setting $EnablePGCust=0;. A per-page configuration file
can force group customizations to be loaded first by using include_once
on the group customization file.
*/
$f = 1;
for($p=$pagename;$p;$p=preg_replace('/\\.*[^.]*$/','',$p)) {
if (!IsEnabled($EnablePGCust,1)) return;
if (file_exists("$LocalDir/$p.php"))
{ include_once("$LocalDir/$p.php"); $f=0; }
}
if ($f && IsEnabled($EnablePGCust,1) && file_exists("$LocalDir/default.php"))
include_once("$LocalDir/default.php");

117
wiki/scripts/phpdiff.php Executable file
View File

@@ -0,0 +1,117 @@
<?php if (!defined('PmWiki')) exit();
/*
Copyright 2003,2004 Nils Knappmeier (nk@knappi.org)
Copyright 2004-2010 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This file implements a diff function in native PHP. It is based
upon the PHPDiffEngine code written by Nils Knappmeier, who in turn
had used Daniel Unterberger's diff
(http://www.holomind.de/phpnet/diff.php) as the basis for his code.
Pm's revision of Nils' code simply attempts to streamline it
for speed (eliminate function calls and unnecessary string ops)
and place everything into a single file.
*/
## PHPDiff returns the differences between $old and $new, formatted
## in the standard diff(1) output format.
function PHPDiff($old, $new)
{
StopWatch("PHPDiff: begin");
# split the source text into arrays of lines
$t1 = explode("\n", $old);
$x = array_pop($t1);
if ($x > '') $t1[] = "$x\n\\ No newline at end of file";
$t2 = explode("\n", $new);
$x = array_pop($t2);
if ($x > '') $t2[] = "$x\n\\ No newline at end of file";
$t1_start = 0; $t1_end = count($t1);
$t2_start = 0; $t2_end = count($t2);
# stop with a common ending
while ($t1_start < $t1_end && $t2_start < $t2_end
&& $t1[$t1_end-1] == $t2[$t2_end-1]) { $t1_end--; $t2_end--; }
# skip over any common beginning
while ($t1_start < $t1_end && $t2_start < $t2_end
&& $t1[$t1_start] == $t2[$t2_start]) { $t1_start++; $t2_start++; }
# build a reverse-index array using the line as key and line number as value
# don't store blank lines, so they won't be targets of the shortest distance
# search
for($i = $t1_start; $i < $t1_end; $i++) if ($t1[$i]>'') $r1[$t1[$i]][] = $i;
for($i = $t2_start; $i < $t2_end; $i++) if ($t2[$i]>'') $r2[$t2[$i]][] = $i;
$a1 = $t1_start; $a2 = $t2_start; # start at beginning of each list
$actions = array();
# walk this loop until we reach the end of one of the lists
while ($a1 < $t1_end && $a2 < $t2_end) {
# if we have a common element, save it and go to the next
if ($t1[$a1] == $t2[$a2]) { $actions[] = 4; $a1++; $a2++; continue; }
# otherwise, find the shortest move (Manhattan-distance) from the
# current location
$best1 = $t1_end; $best2 = $t2_end;
$s1 = $a1; $s2 = $a2;
while(($s1 + $s2 - $a1 - $a2) < ($best1 + $best2 - $a1 - $a2)) {
$d = -1;
foreach((array)@$r1[$t2[$s2]] as $n)
if ($n >= $s1) { $d = $n; break; }
if ($d >= $s1 && ($d + $s2 - $a1 - $a2) < ($best1 + $best2 - $a1 - $a2))
{ $best1 = $d; $best2 = $s2; }
$d = -1;
foreach((array)@$r2[$t1[$s1]] as $n)
if ($n >= $s2) { $d = $n; break; }
if ($d >= $s2 && ($s1 + $d - $a1 - $a2) < ($best1 + $best2 - $a1 - $a2))
{ $best1 = $s1; $best2 = $d; }
$s1++; $s2++;
}
while ($a1 < $best1) { $actions[] = 1; $a1++; } # deleted elements
while ($a2 < $best2) { $actions[] = 2; $a2++; } # added elements
}
# we've reached the end of one list, now walk to the end of the other
while($a1 < $t1_end) { $actions[] = 1; $a1++; } # deleted elements
while($a2 < $t2_end) { $actions[] = 2; $a2++; } # added elements
# and this marks our ending point
$actions[] = 8;
# now, let's follow the path we just took and report the added/deleted
# elements into $out.
$op = 0;
$x0 = $x1 = $t1_start; $y0 = $y1 = $t2_start;
$out = array();
foreach($actions as $act) {
if ($act == 1) { $op |= $act; $x1++; continue; }
if ($act == 2) { $op |= $act; $y1++; continue; }
if ($op > 0) {
$xstr = ($x1 == ($x0+1)) ? $x1 : ($x0+1) . ",$x1";
$ystr = ($y1 == ($y0+1)) ? $y1 : ($y0+1) . ",$y1";
if ($op == 1) $out[] = "{$xstr}d{$y1}";
elseif ($op == 3) $out[] = "{$xstr}c{$ystr}";
while ($x0 < $x1) { $out[] = '< ' . $t1[$x0]; $x0++; } # deleted elems
if ($op == 2) $out[] = "{$x1}a{$ystr}";
elseif ($op == 3) $out[] = '---';
while ($y0 < $y1) { $out[] = '> '.$t2[$y0]; $y0++; } # added elems
}
$x1++; $x0 = $x1;
$y1++; $y0 = $y1;
$op = 0;
}
$out[] = '';
StopWatch("PHPDiff: end");
return join("\n",$out);
}
if (!function_exists(@$DiffFunction))
$DiffFunction = 'PHPDiff';

57
wiki/scripts/prefs.php Executable file
View File

@@ -0,0 +1,57 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2005-2014 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script handles per-browser preferences. Preference settings
are stored in wiki pages as XLPage translations, and a cookie on
the browser tells PmWiki where to find the browser's preferred
settings.
This script looks for a ?setprefs= request parameter (e.g., in
a url); when it finds one it sets a 'setprefs' cookie on the browser
identifying the page to be used to load browser preferences,
and loads the associated preferences.
If there is no ?setprefs= request, then the script uses the
'setprefs' cookie from the browser to load the preference settings.
*/
SDV($PrefsCookie, $CookiePrefix.'setprefs');
SDV($PrefsCookieExpires, $Now + 60 * 60 * 24 * 365);
$LogoutCookies[] = $PrefsCookie;
$sp = '';
if (@$_COOKIE[$PrefsCookie]) $sp = $_COOKIE[$PrefsCookie];
if (isset($_GET['setprefs'])) {
$sp = MakePageName($pagename, $_GET['setprefs']);
setcookie($PrefsCookie, $sp, $PrefsCookieExpires, '/');
}
if ($sp && PageExists($sp)) XLPage('prefs', $sp, true);
if(is_array($XL['prefs'])) {
foreach($XL['prefs'] as $k=>$v) {
if(! preg_match('/^(e_rows|e_cols|TimeFmt|Locale|Site\\.EditForm)$|^ak_/', $k))
unset($XL['prefs'][$k]);
}
}
XLSDV('en', array(
'ak_view' => '',
'ak_edit' => 'e',
'ak_history' => 'h',
'ak_attach' => '',
'ak_backlinks' => '',
'ak_logout' => '',
'ak_print' => '',
'ak_recentchanges' => 'c',
'ak_save' => 's',
'ak_saveedit' => 'u',
'ak_savedraft' => 'd',
'ak_preview' => 'p',
'ak_em' => '',
'ak_strong' => '',
));

121
wiki/scripts/refcount.php Executable file
View File

@@ -0,0 +1,121 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2011 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This file does simple reference counting on pages in a PmWiki site.
Simply activate this script using
include_once('scripts/refcount.php');
in the config.php file and then use ?action=refcount to bring up
the reference count form. The output is a table where each row
of the table contains a page name or link reference, the number
of (non-RecentChanges) pages that contain links to the page,
the number of RecentChanges pages with links to the page, and the
total number of references in all pages.
*/
SDV($PageRefCountFmt,"<h2 class='wikiaction'>Reference Count Results</h2>");
SDV($RefCountTimeFmt," <small>%Y-%b-%d %H:%M</small>");
SDV($HandleActions['refcount'], 'HandleRefCount');
function PrintRefCount($pagename) {
global $GroupPattern,$NamePattern,$PageRefCountFmt,$RefCountTimeFmt, $ScriptUrl;
$pagelist = ListPages();
$grouplist = array();
foreach($pagelist as $pname) {
if (!preg_match("/^($GroupPattern)[\\/.]($NamePattern)$/",$pname,$m))
continue;
$grouplist[$m[1]]=$m[1];
}
asort($grouplist);
$grouplist = array_merge(array('all' => 'all groups'),$grouplist);
$wlist = array('all','missing','existing','orphaned');
$tlist = isset($_REQUEST['tlist']) ? $_REQUEST['tlist'] : array('all');
$flist = isset($_REQUEST['flist']) ? $_REQUEST['flist'] : array('all');
$whichrefs = @$_REQUEST['whichrefs'];
$showrefs = (@$_REQUEST['showrefs']=='checked')? "checked='checked'" : '';
$submit = @$_REQUEST['submit'];
echo FmtPageName($PageRefCountFmt,$pagename);
echo FmtPageName("<form method='post' action='{\$PageUrl}'><input type='hidden' name='action' value='refcount'/>
<table cellspacing='10'><tr><td valign='top'>Show
<br/><select name='whichrefs'>",$pagename);
foreach($wlist as $w)
echo "<option ",($whichrefs==$w) ? 'selected="selected"' : ''," value='$w'>$w</option>\n";
echo "</select></td><td valign='top'> page names in group<br/>
<select name='tlist[]' multiple='multiple' size='4'>";
foreach($grouplist as $g=>$t)
echo "<option ",in_array($g,$tlist) ? 'selected="selected"' : ''," value='$g'>$t</option>\n";
echo "</select></td><td valign='top'> referenced from pages in<br/>
<select name='flist[]' multiple='multiple' size='4'>";
foreach($grouplist as $g=>$t)
echo "<option ",in_array($g,$flist) ? 'selected="selected"' : ''," value='$g'>$t</option>\n";
echo "</select></td></tr></table>
<p><input type='checkbox' name='showrefs' value='checked' $showrefs/>
Display referencing pages
</p><p><input type='submit' name='submit' value='Search'/></p></form><hr/>";
if ($submit) {
foreach($pagelist as $pname) {
$ref = array();
$page = ReadPage($pname, READPAGE_CURRENT);
if (!$page) continue;
$tref[$pname]['time'] = $page['time'];
if (!in_array('all',$flist) &&
!in_array(FmtPageName('$Group',$pname),$flist)) continue;
$rc = preg_match('/RecentChanges$/',$pname);
foreach(explode(',',@$page['targets']) as $r) {
if ($r=='') continue;
if ($rc) @$tref[$r]['rc']++;
else { @$tref[$r]['page']++; @$pref[$r][$pname]++; }
}
}
uasort($tref,'RefCountCmp');
echo "<table >
<tr><th></th><th colspan='2'>Referring pages</th></tr>
<tr><th>Name / Time</th><th>All</th><th>R.C.</th></tr>";
reset($tref);
foreach($tref as $p=>$c) {
if (!in_array('all',$tlist) &&
!in_array(FmtPageName('$Group',$p),$tlist)) continue;
if ($whichrefs=='missing' && PageExists($p)) continue;
elseif ($whichrefs=='existing' && !PageExists($p)) continue;
elseif ($whichrefs=='orphaned' &&
(@$tref[$p]['page']>0 || !PageExists($p))) continue;
echo "<tr><td valign='top'>",LinkPage($pagename, '', $p, '', $p);
if (@$tref[$p]['time']) echo strftime($RefCountTimeFmt,$tref[$p]['time']);
if ($showrefs && is_array(@$pref[$p])) {
foreach($pref[$p] as $pr=>$pc)
echo "<dd>", LinkPage($pagename, '', $pr, '', $pr);
}
echo "</td>";
echo "<td align='center' valign='top'>",@$tref[$p]['page']+0,"</td>";
echo "<td align='center' valign='top'>",@$tref[$p]['rc']+0,"</td>";
echo "</tr>";
}
echo "</table>";
}
}
function RefCountCmp($ua,$ub) {
if (@($ua['page']!=$ub['page'])) return @($ub['page']-$ua['page']);
if (@($ua['rc']!=$ub['rc'])) return @($ub['rc']-$ua['rc']);
return @($ub['time']-$ua['time']);
}
function HandleRefCount($pagename, $auth='read') {
global $HandleRefCountFmt,$PageStartFmt,$PageEndFmt;
$page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT);
if (!$page) Abort('?unauthorized');
PCache($pagename, $page);
SDV($HandleRefCountFmt,array(&$PageStartFmt,
'function:PrintRefCount',&$PageEndFmt));
PrintFmt($pagename,$HandleRefCountFmt);
}

76
wiki/scripts/robots.php Executable file
View File

@@ -0,0 +1,76 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2005-2006 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This file provides various features to allow PmWiki to control
what web crawlers (robots) see when they visit the site. Of course
it's still possible to control robots at the webserver level
and via robots.txt, but this page provides some finer level
of control.
The $MetaRobots variable controls generation of the
<meta name='robots' ... /> tag in the head of the HTML document.
By default $MetaRobots is set so that robots do not index pages in
the Site, SiteAdmin, and PmWiki groups.
The $RobotPattern variable is used to determine if the user agent
accessing the site is a robot, and $IsRobotAgent is set accordingly.
By default this pattern identifies Googlebot, Yahoo! Slurp, msnbot,
BecomeBot, and HTTrack as robots.
If the agent is deemed a robot, then the $RobotActions array is
checked to see if robots are allowed to perform the given action,
and if not the robot is immediately sent an HTTP 403 Forbidden
response.
If $EnableRobotCloakActions is set, then a pattern is added to
$FmtP to hide any "?action=" url parameters in page urls
generated by PmWiki for actions that robots aren't allowed to
access. This can greatly reduce the load on the server by
not providing the robot with links to pages that it will be
forbidden to index anyway.
*/
## $MetaRobots provides the value for the <meta name='robots' ...> tag.
SDV($MetaRobots,
($action!='browse' || !PageExists($pagename)
|| preg_match('#^PmWiki[./](?!PmWiki$)|^Site(Admin)?[./]#', $pagename))
? 'noindex,nofollow' : 'index,follow');
if ($MetaRobots)
$HTMLHeaderFmt['robots'] =
" <meta name='robots' content='\$MetaRobots' />\n";
## $RobotPattern is used to identify robots.
SDV($RobotPattern,'Googlebot|Slurp|msnbot|Teoma|ia_archiver|BecomeBot|HTTrack|MJ12bot|XML Sitemaps|Yandex');
SDV($IsRobotAgent,
$RobotPattern && preg_match("!$RobotPattern!", @$_SERVER['HTTP_USER_AGENT']));
if (!$IsRobotAgent) return;
## $RobotActions indicates which actions a robot is allowed to perform.
SDVA($RobotActions, array('browse' => 1, 'rss' => 1, 'dc' => 1));
if (!@$RobotActions[$action]) {
$pagename = ResolvePageName($pagename);
if (!PageExists($pagename)) {
header("HTTP/1.1 404 Not Found");
print("<h1>Not Found</h1>");
exit();
}
header("HTTP/1.1 403 Forbidden");
print("<h1>Forbidden</h1>");
exit();
}
## The following removes any ?action= parameters that robots aren't
## allowed to access.
if (IsEnabled($EnableRobotCloakActions, 0)) {
$p = create_function('$a', 'return (boolean)$a;');
$p = join('|', array_keys(array_filter($RobotActions, $p)));
$FmtPV['$PageUrl'] =
'PUE(($EnablePathInfo)
? "\\$ScriptUrl/$group/$name"
: "\\$ScriptUrl?n=$group.$name")';
$FmtP["/(\\\$ScriptUrl[^#\"'\\s<>]+)\\?action=(?!$p)\\w+/"] = '$1';
}

74
wiki/scripts/simuledit.php Executable file
View File

@@ -0,0 +1,74 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2014 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This file enables merging of concurrent edits, using the "diff3"
program available on most Unix systems to merge the edits. If
diff3 is not available or you'd like to use a different command,
then set $SysMergeCmd accordingly.
*/
array_unshift($EditFunctions,'MergeSimulEdits');
$HTMLStylesFmt['simuledit'] = ".editconflict { color:green;
font-style:italic; margin-top:1.33em; margin-bottom:1.33em; }\n";
function Merge($newtext,$oldtext,$pagetext) {
global $WorkDir,$SysMergeCmd, $SysMergePassthru;
SDV($SysMergeCmd,"/usr/bin/diff3 -L '' -L '' -L '' -m -E");
if (substr($newtext,-1,1)!="\n") $newtext.="\n";
if (substr($oldtext,-1,1)!="\n") $oldtext.="\n";
if (substr($pagetext,-1,1)!="\n") $pagetext.="\n";
$tempnew = tempnam($WorkDir,"new");
$tempold = tempnam($WorkDir,"old");
$temppag = tempnam($WorkDir,"page");
if ($newfp=fopen($tempnew,'w')) { fputs($newfp,$newtext); fclose($newfp); }
if ($oldfp=fopen($tempold,'w')) { fputs($oldfp,$oldtext); fclose($oldfp); }
if ($pagfp=fopen($temppag,'w')) { fputs($pagfp,$pagetext); fclose($pagfp); }
$mergetext = '';
if (IsEnabled($SysMergePassthru, 0)) {
ob_start();
passthru("$SysMergeCmd $tempnew $tempold $temppag");
$mergetext = ob_get_clean();
}
else {
$merge_handle = popen("$SysMergeCmd $tempnew $tempold $temppag",'r');
if ($merge_handle) {
while (!feof($merge_handle)) $mergetext .= fread($merge_handle,4096);
pclose($merge_handle);
}
}
@unlink($tempnew); @unlink($tempold); @unlink($temppag);
return $mergetext;
}
function MergeSimulEdits($pagename,&$page,&$new) {
global $Now, $EnablePost, $MessagesFmt, $WorkDir;
if (@!$_POST['basetime'] || !PageExists($pagename)
|| $page['time'] >= $Now
|| $_POST['basetime']>=$page['time']
|| $page['text'] == $new['text']) return;
$EnablePost = 0;
$old = array();
RestorePage($pagename,$page,$old,"diff:{$_POST['basetime']}");
$text = Merge($new['text'],$old['text'],$page['text']);
if ($text > '') { $new['text'] = $text; $ec = '$[EditConflict]'; }
else $ec = '$[EditWarning]';
XLSDV('en', array(
'EditConflict' => "The page you are
editing has been modified since you started editing it.
The modifications have been merged into the text below,
you may want to verify the results of the merge before
pressing save. Conflicts the system couldn't resolve are
bracketed by &lt;&lt;&lt;&lt;&lt;&lt;&lt; and
&gt;&gt;&gt;&gt;&gt;&gt;&gt;.",
'EditWarning' => "The page you are editing has been modified
since you started editing it. If you continue, your
changes will overwrite any changes that others have made."));
$MessagesFmt[] = "<p class='editconflict'>$ec
(<a target='_blank' href='\$PageUrl?action=diff'>$[View changes]</a>)
</p>\n";
}

147
wiki/scripts/skins.php Executable file
View File

@@ -0,0 +1,147 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2007 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This file implements the skin selection code for PmWiki. Skin
selection is controlled by the $Skin variable, which can also
be an array (in which case the first skin found is loaded).
In addition, $ActionSkin[$action] specifies other skins to be
searched based on the current action.
*/
SDV($Skin, 'pmwiki');
SDV($ActionSkin['print'], 'print');
SDV($FarmPubDirUrl, $PubDirUrl);
SDV($PageLogoUrl, "$FarmPubDirUrl/skins/pmwiki/pmwiki-32.gif");
SDVA($TmplDisplay, array('PageEditFmt' => 0));
# $PageTemplateFmt is deprecated
if (isset($PageTemplateFmt)) LoadPageTemplate($pagename,$PageTemplateFmt);
else {
$x = array_merge((array)@$ActionSkin[$action], (array)$Skin);
SetSkin($pagename, $x);
}
SDV($PageCSSListFmt,array(
'pub/css/local.css' => '$PubDirUrl/css/local.css',
'pub/css/{$Group}.css' => '$PubDirUrl/css/{$Group}.css',
'pub/css/{$FullName}.css' => '$PubDirUrl/css/{$FullName}.css'));
foreach((array)$PageCSSListFmt as $k=>$v)
if (file_exists(FmtPageName($k,$pagename)))
$HTMLHeaderFmt[] = "<link rel='stylesheet' type='text/css' href='$v' />\n";
# SetSkin changes the current skin to the first available skin from
# the $skin array.
function SetSkin($pagename, $skin) {
global $Skin, $SkinLibDirs, $SkinDir, $SkinDirUrl,
$IsTemplateLoaded, $PubDirUrl, $FarmPubDirUrl, $FarmD, $GCount;
SDV($SkinLibDirs, array(
"./pub/skins/\$Skin" => "$PubDirUrl/skins/\$Skin",
"$FarmD/pub/skins/\$Skin" => "$FarmPubDirUrl/skins/\$Skin"));
foreach((array)$skin as $sfmt) {
$Skin = FmtPageName($sfmt, $pagename); $GCount = 0;
foreach($SkinLibDirs as $dirfmt => $urlfmt) {
$SkinDir = FmtPageName($dirfmt, $pagename);
if (is_dir($SkinDir))
{ $SkinDirUrl = FmtPageName($urlfmt, $pagename); break 2; }
}
}
if (!is_dir($SkinDir)) {
unset($Skin);
Abort("?unable to find skin from list ".implode(' ',(array)$skin));
}
$IsTemplateLoaded = 0;
if (file_exists("$SkinDir/$Skin.php"))
include_once("$SkinDir/$Skin.php");
else if (file_exists("$SkinDir/skin.php"))
include_once("$SkinDir/skin.php");
if ($IsTemplateLoaded) return;
if (file_exists("$SkinDir/$Skin.tmpl"))
LoadPageTemplate($pagename, "$SkinDir/$Skin.tmpl");
else if (file_exists("$SkinDir/skin.tmpl"))
LoadPageTemplate($pagename, "$SkinDir/skin.tmpl");
else if (($dh = opendir($SkinDir))) {
while (($fname = readdir($dh)) !== false) {
if ($fname[0] == '.') continue;
if (substr($fname, -5) != '.tmpl') continue;
if ($IsTemplateLoaded)
Abort("?unable to find unique template in $SkinDir");
LoadPageTemplate($pagename, "$SkinDir/$fname");
}
closedir($dh);
}
if (!$IsTemplateLoaded) Abort("Unable to load $Skin template", 'skin');
}
# LoadPageTemplate loads a template into $TmplFmt
function LoadPageTemplate($pagename,$tfilefmt) {
global $PageStartFmt, $PageEndFmt,
$EnableSkinDiag, $HTMLHeaderFmt, $HTMLFooterFmt,
$IsTemplateLoaded, $TmplFmt, $TmplDisplay,
$PageTextStartFmt, $PageTextEndFmt, $SkinDirectivesPattern;
SDV($PageTextStartFmt, "\n<div id='wikitext'>\n");
SDV($PageTextEndFmt, "</div>\n");
SDV($SkinDirectivesPattern,
"[[<]!--((?:wiki|file|function|markup):.*?)--[]>]");
$sddef = array('PageEditFmt' => 0);
$k = implode('', file(FmtPageName($tfilefmt, $pagename)));
if (IsEnabled($EnableSkinDiag, 0)) {
if (!preg_match('/<!--((No)?(HT|X)MLHeader|HeaderText)-->/i', $k))
Abort("Skin template missing &lt;!--HTMLHeader--&gt;", 'htmlheader');
if (!preg_match('/<!--(No)?(HT|X)MLFooter-->/i', $k))
Abort("Skin template missing &lt;!--HTMLFooter--&gt;", 'htmlheader');
}
$sect = preg_split(
'#[[<]!--(/?(?:Page[A-Za-z]+Fmt|(?:HT|X)ML(?:Head|Foot)er|HeaderText|PageText).*?)--[]>]#',
$k, 0, PREG_SPLIT_DELIM_CAPTURE);
$TmplFmt['Start'] = array_merge(array('headers:'),
preg_split("/$SkinDirectivesPattern/s",
array_shift($sect),0,PREG_SPLIT_DELIM_CAPTURE));
$TmplFmt['End'] = array($PageTextEndFmt);
$ps = 'Start';
while (count($sect)>0) {
$k = array_shift($sect);
$v = preg_split("/$SkinDirectivesPattern/s",
array_shift($sect),0,PREG_SPLIT_DELIM_CAPTURE);
$TmplFmt[$ps][] = "<!--$k-->";
if ($k{0} == '/')
{ $TmplFmt[$ps][] = (count($v) > 1) ? $v : $v[0]; continue; }
@list($var, $sd) = explode(' ', $k, 2);
$GLOBALS[$var] = (count($v) > 1) ? $v : $v[0];
if ($sd > '') $sddef[$var] = $sd;
if ($var == 'PageText') { $ps = 'End'; }
if ($var == 'HTMLHeader' || $var == 'XMLHeader')
$TmplFmt[$ps][] = &$HTMLHeaderFmt;
if ($var == 'HTMLFooter' || $var == 'XMLFooter')
$TmplFmt[$ps][] = &$HTMLFooterFmt;
## <!--HeaderText--> deprecated, 2.1.16
if ($var == 'HeaderText') { $TmplFmt[$ps][] = &$HTMLHeaderFmt; }
$TmplFmt[$ps][$var] =& $GLOBALS[$var];
}
array_push($TmplFmt['Start'], $PageTextStartFmt);
$PageStartFmt = 'function:PrintSkin Start';
$PageEndFmt = 'function:PrintSkin End';
$IsTemplateLoaded = 1;
SDVA($TmplDisplay, $sddef);
}
# This function is called to print a portion of the skin template
# according to the settings in $TmplDisplay.
function PrintSkin($pagename, $arg) {
global $TmplFmt, $TmplDisplay;
foreach ($TmplFmt[$arg] as $k => $v)
if (!isset($TmplDisplay[$k]) || $TmplDisplay[$k])
PrintFmt($pagename, $v);
}

99
wiki/scripts/stdconfig.php Executable file
View File

@@ -0,0 +1,99 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2002-2007 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This file allows features to be easily enabled/disabled in config.php.
Simply set variables for the features to be enabled/disabled in config.php
before including this file. For example:
$EnableQAMarkup=0; #disable Q: and A: tags
$EnableWikiStyles=1; #include default wikistyles
Each feature has a default setting, if the corresponding $Enable
variable is not set then you get the default.
To avoid processing any of the features of this file, set
$EnableStdConfig = 0;
in config.php.
*/
$pagename = ResolvePageName($pagename);
if (!IsEnabled($EnableStdConfig,1)) return;
if (!function_exists('session_start') && IsEnabled($EnableRequireSession, 1))
Abort('PHP is lacking session support', 'session');
if (IsEnabled($EnablePGCust,1))
include_once("$FarmD/scripts/pgcust.php");
if (isset($PostConfig) && is_array($PostConfig)) {
asort($PostConfig, SORT_NUMERIC);
foreach ($PostConfig as $k=>$v) {
if (!$k || !$v || $v<0 || $v>=50) continue;
if (function_exists($k)) $k($pagename);
elseif (file_exists($k)) include_once($k);
}
}
if (IsEnabled($EnableRobotControl,1))
include_once("$FarmD/scripts/robots.php");
if (IsEnabled($EnableCaches, 1))
include_once("$FarmD/scripts/caches.php");
## Scripts that are part of a standard PmWiki distribution.
if (IsEnabled($EnableAuthorTracking,1))
include_once("$FarmD/scripts/author.php");
if (IsEnabled($EnablePrefs, 1))
include_once("$FarmD/scripts/prefs.php");
if (IsEnabled($EnableSimulEdit, 1))
include_once("$FarmD/scripts/simuledit.php");
if (IsEnabled($EnableDrafts, 0))
include_once("$FarmD/scripts/draft.php"); # after simuledit + prefs
if (IsEnabled($EnableSkinLayout,1))
include_once("$FarmD/scripts/skins.php"); # must come after prefs
if (@$Transition || IsEnabled($EnableTransitions, 0))
include_once("$FarmD/scripts/transition.php"); # must come after skins
if (@$LinkWikiWords || IsEnabled($EnableWikiWords, 0))
include_once("$FarmD/scripts/wikiwords.php"); # must come before stdmarkup
if (IsEnabled($EnableStdMarkup,1))
include_once("$FarmD/scripts/stdmarkup.php"); # must come after transition
if ($action=='diff' && @!$HandleActions['diff'])
include_once("$FarmD/scripts/pagerev.php");
if (IsEnabled($EnableWikiTrails,1))
include_once("$FarmD/scripts/trails.php");
if (IsEnabled($EnableWikiStyles,1))
include_once("$FarmD/scripts/wikistyles.php");
if (IsEnabled($EnableMarkupExpressions, 1)
&& !function_exists('MarkupExpression'))
include_once("$FarmD/scripts/markupexpr.php");
if (IsEnabled($EnablePageList,1))
include_once("$FarmD/scripts/pagelist.php");
if (IsEnabled($EnableVarMarkup,1))
include_once("$FarmD/scripts/vardoc.php");
if (!function_exists(@$DiffFunction))
include_once("$FarmD/scripts/phpdiff.php");
if ($action=='crypt')
include_once("$FarmD/scripts/crypt.php");
if ($action=='edit' && IsEnabled($EnableGUIButtons,0))
include_once("$FarmD/scripts/guiedit.php");
if (IsEnabled($EnableForms,1))
include_once("$FarmD/scripts/forms.php"); # must come after prefs
if (IsEnabled($EnableUpload,0))
include_once("$FarmD/scripts/upload.php"); # must come after forms
if (IsEnabled($EnableBlocklist, 0))
include_once("$FarmD/scripts/blocklist.php");
if (IsEnabled($EnableNotify,0))
include_once("$FarmD/scripts/notify.php");
if (IsEnabled($EnableDiag,0))
include_once("$FarmD/scripts/diag.php");
if (IsEnabled($EnableUpgradeCheck,1)) {
SDV($StatusPageName, "$SiteAdminGroup.Status");
$page = ReadPage($StatusPageName, READPAGE_CURRENT);
if (@$page['updatedto'] != $VersionNum)
{ $action = 'upgrade'; include_once("$FarmD/scripts/upgrades.php"); }
}

504
wiki/scripts/stdmarkup.php Executable file
View File

@@ -0,0 +1,504 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2015 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script defines PmWiki's standard markup. It is automatically
included from stdconfig.php unless $EnableStdMarkup==0.
Each call to Markup() below adds a new rule to PmWiki's translation
engine (unless a rule with the same name has already been defined).
The form of the call is Markup($id,$where,$pat,$rep);
$id is a unique name for the rule, $where is the position of the rule
relative to another rule, $pat is the pattern to look for, and
$rep is the string to replace it with.
*/
## first we preserve text in [=...=] and [@...@]
function PreserveText($sigil, $text, $lead) {
if ($sigil=='=') return $lead.Keep($text);
if (strpos($text, "\n")===false)
return "$lead<code class='escaped'>".Keep($text)."</code>";
$text = preg_replace("/\n[^\\S\n]+$/", "\n", $text);
if ($lead == "" || $lead == "\n")
return "$lead<pre class='escaped'>".Keep($text)."</pre>";
return "$lead<:pre,1>".Keep($text);
}
Markup_e('[=','_begin',"/(\n[^\\S\n]*)?\\[([=@])(.*?)\\2\\]/s",
"PreserveText(\$m[2], \$m[3], \$m[1])");
Markup_e('restore','<_end',"/$KeepToken(\\d.*?)$KeepToken/",
'$GLOBALS[\'KPV\'][$m[1]]');
Markup('<:', '>restore',
'/<:[^>]*>/', '');
Markup('<vspace>', '<restore',
'/<vspace>/',
"<div class='vspace'></div>");
Markup('<vspace><p>', '<<vspace>',
"/<vspace><p\\b(([^>]*)(\\s)class=(['\"])([^>]*?)\\4)?/",
"<p$2 class='vspace$3$5'");
## remove carriage returns before preserving text
Markup('\\r','<[=','/\\r/','');
# $[phrase] substitutions
Markup_e('$[phrase]', '>[=',
'/\\$\\[(?>([^\\]]+))\\]/', "NoCache(XL(\$m[1]))");
# {$var} substitutions
Markup_e('{$var}', '>$[phrase]',
'/\\{(\\*|!?[-\\w.\\/\\x80-\\xff]*)(\\$:?\\w[-\\w]*)\\}/',
"PRR(PVSE(PageVar(\$pagename, \$m[2], \$m[1])))");
# invisible (:textvar:...:) definition
Markup('textvar:', '<split',
'/\\(: *\\w[-\\w]* *:(?!\\)).*?:\\)/s', '');
## handle relative text vars in includes
if (IsEnabled($EnableRelativePageVars, 1))
SDV($QualifyPatterns["/\\{([-\\w\\x80-\\xfe]*)(\\$:?\\w+\\})/"],
PCCF("'{' . (\$m[1] ? MakePageName(\$pagename, \$m[1]) : \$pagename) . \$m[2]", 'qualify'));
## character entities
Markup('&','<if','/&amp;(?>([A-Za-z0-9]+|#\\d+|#[xX][A-Fa-f0-9]+));/',
'&$1;');
Markup('&amp;amp;', '<&', '/&amp;amp;/', Keep('&amp;'));
## (:if:)/(:elseif:)/(:else:)
SDV($CondTextPattern,
"/ \\(:if (\d*) (?:end)? \\b[^\n]*?:\\)
.*?
(?: \\(: (?:if\\1|if\\1end) \\s* :\\)
| (?=\\(:(?:if\\1|if\\1end)\\b[^\n]*?:\\) | $)
)
/six");
SDV($CondTextReplacement, "CondText2(\$pagename, \$m[0], \$m[1])");
Markup_e('if', 'fulltext', $CondTextPattern, $CondTextReplacement);
function CondText2($pagename, $text, $code = '') {
global $Conditions, $CondTextPattern, $CondTextReplacement;
$if = "if$code";
$repl = str_replace('$pagename', "'$pagename'", $CondTextReplacement);
$parts = preg_split("/\\(:(?:{$if}end|$if|else *$if|else$code)\\b\\s*(.*?)\\s*:\\)/",
$text, -1, PREG_SPLIT_DELIM_CAPTURE);
$x = array_shift($parts);
while ($parts) {
list($condspec, $condtext) = array_splice($parts, 0, 2);
if (!preg_match("/^\\s*(!?)\\s*(\\S*)\\s*(.*?)\\s*$/", $condspec, $match)) continue;
list($x, $not, $condname, $condparm) = $match;
if (!isset($Conditions[$condname]))
return PPRE($CondTextPattern, $repl, $condtext);
$tf = @eval("return ({$Conditions[$condname]});");
if ($tf xor $not)
return PPRE($CondTextPattern, $repl, $condtext);
}
return '';
}
## (:include:)
Markup_e('include', '>if',
'/\\(:include\\s+(\\S.*?):\\)/i',
"PRR(IncludeText(\$pagename, \$m[1]))");
## (:redirect:)
Markup_e('redirect', '<include',
'/\\(:redirect\\s+(\\S.*?):\\)/i',
"RedirectMarkup(\$pagename, \$m[1])");
$SaveAttrPatterns['/\\(:(if\\d*|include|redirect)(\\s.*?)?:\\)/i'] = ' ';
## GroupHeader/GroupFooter handling
Markup_e('nogroupheader', '>include',
'/\\(:nogroupheader:\\)/i',
"PZZ(\$GLOBALS['GroupHeaderFmt']='')");
Markup_e('nogroupfooter', '>include',
'/\\(:nogroupfooter:\\)/i',
"PZZ(\$GLOBALS['GroupFooterFmt']='')");
Markup_e('groupheader', '>nogroupheader',
'/\\(:groupheader:\\)/i',
"PRR(FmtPageName(\$GLOBALS['GroupHeaderFmt'],\$pagename))");
Markup_e('groupfooter','>nogroupfooter',
'/\\(:groupfooter:\\)/i',
"PRR(FmtPageName(\$GLOBALS['GroupFooterFmt'],\$pagename))");
## (:nl:)
Markup('nl0','<split',"/([^\n])(?>(?:\\(:nl:\\))+)([^\n])/i","$1\n$2");
Markup('nl1','>nl0',"/\\(:nl:\\)/i",'');
## \\$ (end of line joins)
Markup_e('\\$','>nl1',"/\\\\(?>(\\\\*))\n/",
"str_repeat('<br />',strlen(\$m[1]))");
## Remove one <:vspace> after !headings
Markup('!vspace', '>\\$', "/^(!(?>[^\n]+)\n)<:vspace>/m", '$1');
## (:noheader:),(:nofooter:),(:notitle:)...
Markup_e('noheader', 'directives',
'/\\(:noheader:\\)/i',
"SetTmplDisplay('PageHeaderFmt',0)");
Markup_e('nofooter', 'directives',
'/\\(:nofooter:\\)/i',
"SetTmplDisplay('PageFooterFmt',0)");
Markup_e('notitle', 'directives',
'/\\(:notitle:\\)/i',
"SetTmplDisplay('PageTitleFmt',0)");
Markup_e('noleft', 'directives',
'/\\(:noleft:\\)/i',
"SetTmplDisplay('PageLeftFmt',0)");
Markup_e('noright', 'directives',
'/\\(:noright:\\)/i',
"SetTmplDisplay('PageRightFmt',0)");
Markup_e('noaction', 'directives',
'/\\(:noaction:\\)/i',
"SetTmplDisplay('PageActionFmt',0)");
## (:spacewikiwords:)
Markup_e('spacewikiwords', 'directives',
'/\\(:(no)?spacewikiwords:\\)/i',
"PZZ(\$GLOBALS['SpaceWikiWords']=(\$m[1]!='no'))");
## (:linkwikiwords:)
Markup_e('linkwikiwords', 'directives',
'/\\(:(no)?linkwikiwords:\\)/i',
"PZZ(\$GLOBALS['LinkWikiWords']=(\$m[1]!='no'))");
## (:linebreaks:)
Markup_e('linebreaks', 'directives',
'/\\(:(no)?linebreaks:\\)/i',
"PZZ(\$GLOBALS['HTMLPNewline'] = (\$m[1]!='no') ? '<br />' : '')");
## (:messages:)
Markup_e('messages', 'directives',
'/^\\(:messages:\\)/i',
"'<:block>'.Keep(
FmtPageName(implode('',(array)\$GLOBALS['MessagesFmt']), \$pagename))");
## (:comment:)
Markup('comment', 'directives', '/\\(:comment .*?:\\)/i', '');
## (:title:) +fix for PITS:00266, 00779
$tmpwhen = IsEnabled($EnablePageTitlePriority, 0) ? '<include' : 'directives';
$tmpkeep = IsEnabled($EnablePageTitlePriority, 0) ? '1' : 'NULL';
Markup_e('title', $tmpwhen,
'/\\(:title\\s(.*?):\\)/i',
"PZZ(PCache(\$pagename,
\$zz=array('title' => SetProperty(\$pagename, 'title', \$m[1], NULL, $tmpkeep))))");
unset($tmpwhen, $tmpkeep);
## (:keywords:), (:description:)
Markup_e('keywords', 'directives',
"/\\(:keywords?\\s+(.+?):\\)/i",
"PZZ(SetProperty(\$pagename, 'keywords', \$m[1], ', '))");
Markup_e('description', 'directives',
"/\\(:description\\s+(.+?):\\)/i",
"PZZ(SetProperty(\$pagename, 'description', \$m[1], '\n'))");
$HTMLHeaderFmt['meta'] = 'function:PrintMetaTags';
function PrintMetaTags($pagename, $args) {
global $PCache;
foreach(array('keywords', 'description') as $n) {
foreach((array)@$PCache[$pagename]["=p_$n"] as $v) {
$v = str_replace("'", '&#039;', $v);
print "<meta name='$n' content='$v' />\n";
}
}
}
#### inline markups ####
## ''emphasis''
Markup("''",'inline',"/''(.*?)''/",'<em>$1</em>');
## '''strong'''
Markup("'''","<''","/'''(.*?)'''/",'<strong>$1</strong>');
## '''''strong emphasis'''''
Markup("'''''","<'''","/'''''(.*?)'''''/",'<strong><em>$1</em></strong>');
## @@code@@
Markup('@@','inline','/@@(.*?)@@/','<code>$1</code>');
## '+big+', '-small-'
Markup("'+","<'''''","/'\\+(.*?)\\+'/",'<big>$1</big>');
Markup("'-","<'''''","/'\\-(.*?)\\-'/",'<small>$1</small>');
## '^superscript^', '_subscript_'
Markup("'^","<'''''","/'\\^(.*?)\\^'/",'<sup>$1</sup>');
Markup("'_","<'''''","/'_(.*?)_'/",'<sub>$1</sub>');
## [+big+], [-small-]
Markup_e('[+','inline','/\\[(([-+])+)(.*?)\\1\\]/',
"'<span style=\'font-size:'.(round(pow(6/5,(\$m[2]=='-'? -1:1)*strlen(\$m[1]))*100,0)).'%\'>'.
\$m[3].'</span>'");
## {+ins+}, {-del-}
Markup('{+','inline','/\\{\\+(.*?)\\+\\}/','<ins>$1</ins>');
Markup('{-','inline','/\\{-(.*?)-\\}/','<del>$1</del>');
## [[<<]] (break)
Markup('[[<<]]','inline','/\\[\\[&lt;&lt;\\]\\]/',"<br clear='all' />");
###### Links ######
## [[free links]]
Markup_e('[[','links',"/(?>\\[\\[\\s*(.*?)\\]\\])($SuffixPattern)/",
"Keep(MakeLink(\$pagename,\$m[1],NULL,\$m[2]),'L')");
## [[!Category]]
SDV($CategoryGroup,'Category');
SDV($LinkCategoryFmt,"<a class='categorylink' href='\$LinkUrl'>\$LinkText</a>");
Markup_e('[[!','<[[','/\\[\\[!(.*?)\\]\\]/',
"Keep(MakeLink(\$pagename,'$CategoryGroup/'.\$m[1],NULL,'',\$GLOBALS['LinkCategoryFmt']),'L')");
# This is a temporary workaround for blank category pages.
# It may be removed in a future release (Pm, 2006-01-24)
if (preg_match("/^$CategoryGroup\\./", $pagename)) {
SDV($DefaultPageTextFmt, '');
SDV($PageNotFoundHeaderFmt, 'HTTP/1.1 200 Ok');
}
## [[target | text]]
Markup_e('[[|','<[[',
"/(?>\\[\\[([^|\\]]*)\\|\\s*)(.*?)\\s*\\]\\]($SuffixPattern)/",
"Keep(MakeLink(\$pagename,\$m[1],\$m[2],\$m[3]),'L')");
## [[text -> target ]]
Markup_e('[[->','>[[|',
"/(?>\\[\\[([^\\]]+?)\\s*-+&gt;\\s*)(.*?)\\]\\]($SuffixPattern)/",
"Keep(MakeLink(\$pagename,\$m[2],\$m[1],\$m[3]),'L')");
if (IsEnabled($EnableRelativePageLinks, 1))
SDV($QualifyPatterns['/(\\[\\[(?>[^\\]]+?->)?\\s*)([-\\w\\x80-\\xfe\\s\'()]+([|#?].*?)?\\]\\])/'],
PCCF("\$m[1].\$group.'/'.\$m[2]", 'qualify'));
## [[#anchor]]
Markup_e('[[#','<[[','/(?>\\[\\[#([A-Za-z][-.:\\w]*))\\]\\]/',
"Keep(TrackAnchors(\$m[1]) ? '' : \"<a name='{\$m[1]}' id='{\$m[1]}'></a>\", 'L')");
function TrackAnchors($x) { global $SeenAnchor; return @$SeenAnchor[$x]++; }
## [[target |#]] reference links
Markup_e('[[|#', '<[[|',
"/(?>\\[\\[([^|\\]]+))\\|\\s*#\\s*\\]\\]/",
"Keep(MakeLink(\$pagename,\$m[1],'['.++\$GLOBALS['MarkupFrame'][0]['ref'].']'),'L')");
## [[target |+]] title links moved inside LinkPage()
## bare urllinks
Markup_e('urllink','>[[',
"/\\b(?>(\\L))[^\\s$UrlExcludeChars]*[^\\s.,?!$UrlExcludeChars]/",
"Keep(MakeLink(\$pagename,\$m[0],\$m[0]),'L')");
## mailto: links
Markup_e('mailto','<urllink',
"/\\bmailto:([^\\s$UrlExcludeChars]*[^\\s.,?!$UrlExcludeChars])/",
"Keep(MakeLink(\$pagename,\$m[0],\$m[1]),'L')");
## inline images
Markup_e('img','<urllink',
"/\\b(?>(\\L))([^\\s$UrlExcludeChars]+$ImgExtPattern)(\"([^\"]*)\")?/",
"Keep(\$GLOBALS['LinkFunctions'][\$m[1]](\$pagename,\$m[1],\$m[2],\$m[4],\$m[1].\$m[2],
\$GLOBALS['ImgTagFmt']),'L')");
## bare wikilinks
## v2.2: markup rule moved to scripts/wikiwords.php)
Markup('wikilink', '>urllink');
## escaped `WikiWords
## v2.2: rule kept here for markup compatibility with 2.1 and earlier
Markup_e('`wikiword', '<wikilink',
"/`(($GroupPattern([\\/.]))?($WikiWordPattern))/",
"Keep(\$m[1])");
#### Block markups ####
## Completely blank lines don't do anything.
Markup('blank', '<block', '/^\\s+$/', '');
## process any <:...> markup (after all other block markups)
Markup_e('^<:','>block','/^(?=\\s*\\S)(<:([^>]+)>)?/',"Block(\$m[2])");
## unblocked lines w/block markup become anonymous <:block>
Markup('^!<:', '<^<:',
"/^(?!<:)(?=.*(<\\/?($BlockPattern)\\b)|$KeepToken\\d+B$KeepToken)/",
'<:block>');
## Lines that begin with displayed images receive their own block. A
## pipe following the image indicates a "caption" (generates a linebreak).
Markup_e('^img', 'block',
"/^((?>(\\s+|%%|%[A-Za-z][-,=:#\\w\\s'\".]*%)*)$KeepToken(\\d+L)$KeepToken)(\\s*\\|\\s?)?(.*)$/",
"(strpos(\$GLOBALS['KPV'][\$m[3]],'<img')===false) ? \$m[0] :
'<:block,1><div>'.\$m[1] . (\$m[4] ? '<br />' : '') .\$m[5].'</div>'");
## Whitespace at the beginning of lines can be used to maintain the
## indent level of a previous list item, or a preformatted text block.
Markup_e('^ws', '<^img', '/^\\s+ #1/x', "WSIndent(\$m[0])");
function WSIndent($i) {
global $MarkupFrame;
$icol = strlen($i);
for($depth = count(@$MarkupFrame[0]['cs']); $depth > 0; $depth--)
if (@$MarkupFrame[0]['is'][$depth] == $icol) {
$MarkupFrame[0]['idep'] = $depth;
$MarkupFrame[0]['icol'] = $icol;
return '';
}
return $i;
}
## The $EnableWSPre setting uses leading spaces on markup lines to indicate
## blocks of preformatted text.
SDV($EnableWSPre, 1);
Markup_e('^ ', 'block',
'/^\\s+ #2/x',
"(\$GLOBALS['EnableWSPre'] > 0 && strlen(\$m[0]) >= \$GLOBALS['EnableWSPre'])
? '<:pre,1>'.\$m[0] : \$m[0]");
## bullet lists
Markup('^*','block','/^(\\*+)\\s?(\\s*)/','<:ul,$1,$0>$2');
## numbered lists
Markup('^#','block','/^(#+)\\s?(\\s*)/','<:ol,$1,$0>$2');
## indented (->) /hanging indent (-<) text
Markup('^->','block','/^(?>(-+))&gt;\\s?(\\s*)/','<:indent,$1,$1 $2>$2');
Markup('^-<','block','/^(?>(-+))&lt;\\s?(\\s*)/','<:outdent,$1,$1 $2>$2');
## definition lists
Markup('^::','block','/^(:+)(\s*)([^:]+):/','<:dl,$1,$1$2><dt>$2$3</dt><dd>');
## Q: and A:
Markup('^Q:', 'block', '/^Q:(.*)$/', "<:block,1><p class='question'>$1</p>");
Markup('^A:', 'block', '/^A:/', Keep(''));
## tables
## ||cell||, ||!header cell||, ||!caption!||
Markup_e('^||||', 'block',
'/^\\|\\|.*\\|\\|.*$/',
"FormatTableRow(\$m[0])");
## ||table attributes
Markup_e('^||','>^||||','/^\\|\\|(.*)$/',
"PZZ(\$GLOBALS['BlockMarkups']['table'][0] = '<table '.PQA(\$m[1]).'>')
.'<:block,1>'");
## headings
Markup_e('^!', 'block',
'/^(!{1,6})\\s?(.*)$/',
"'<:block,1><h'.strlen(\$m[1]).'>'.\$m[2].'</h'.strlen(\$m[1]).'>'");
## horiz rule
Markup('^----','>^->','/^----+/','<:block,1><hr />');
#### (:table:) markup (AdvancedTables)
function Cells($name,$attr) {
global $MarkupFrame, $EnableTableAutoValignTop;
$attr = PQA($attr);
$tattr = @$MarkupFrame[0]['tattr'];
$name = strtolower($name);
$key = preg_replace('/end$/', '', $name);
if (preg_match("/^(?:head|cell)(nr)?$/", $name)) $key = 'cell';
$out = '<:block>'.MarkupClose($key);
if (substr($name, -3) == 'end') return $out;
$cf = & $MarkupFrame[0]['closeall'];
if ($name == 'table') $MarkupFrame[0]['tattr'] = $attr;
else if ($key == 'cell') {
if (IsEnabled($EnableTableAutoValignTop, 1) && strpos($attr, "valign=")===false)
$attr .= " valign='top'";
$t = (strpos($name, 'head')===0 ) ? 'th' : 'td';
if (!@$cf['table']) {
$tattr = @$MarkupFrame[0]['tattr'];
$out .= "<table $tattr><tr><$t $attr>";
$cf['table'] = '</tr></table>';
} else if ( preg_match("/nr$/", $name)) $out .= "</tr><tr><$t $attr>";
else $out .= "<$t $attr>";
$cf['cell'] = "</$t>";
} else {
$tag = preg_replace('/\\d+$/', '', $key);
$out .= "<$tag $attr>";
$cf[$key] = "</$tag>";
}
return $out;
}
Markup_e('table', '<block',
'/^\\(:(table|cell|cellnr|head|headnr|tableend|(?:div\\d*|section\\d*|article\\d*|header|footer|nav|address|aside)(?:end)?)(\\s.*?)?:\\)/i',
"Cells(\$m[1],\$m[2])");
Markup('^>>', '<table',
'/^&gt;&gt;(.+?)&lt;&lt;(.*)$/',
'(:div:)%div $1 apply=div%$2 ');
Markup('^>><<', '<^>>',
'/^&gt;&gt;&lt;&lt;/',
'(:divend:)');
#### special stuff ####
## (:markup:) for displaying markup examples
function MarkupMarkup($pagename, $text, $opt = '') {
global $MarkupWordwrapFunction, $MarkupWrapTag;
SDV($MarkupWordwrapFunction,
PCCF('return str_replace(" ", " &nbsp;", nl2br($m));'));
SDV($MarkupWrapTag, 'code');
$MarkupMarkupOpt = array('class' => 'vert');
$opt = array_merge($MarkupMarkupOpt, ParseArgs($opt));
$html = MarkupToHTML($pagename, $text, array('escape' => 0));
if (@$opt['caption'])
$caption = str_replace("'", '&#039;',
"<caption>{$opt['caption']}</caption>");
$class = preg_replace('/[^-\\s\\w]+/', ' ', @$opt['class']);
if (strpos($class, 'horiz') !== false)
{ $sep = ''; $pretext = $MarkupWordwrapFunction($text, 40); }
else
{ $sep = '</tr><tr>'; $pretext = $MarkupWordwrapFunction($text, 75); }
return Keep(@"<table class='markup $class' align='center'>$caption
<tr><td class='markup1' valign='top'><$MarkupWrapTag>$pretext</$MarkupWrapTag></td>$sep<td
class='markup2' valign='top'>$html</td></tr></table>");
}
Markup_e('markup', '<[=',
"/\\(:markup(\\s+([^\n]*?))?:\\)[^\\S\n]*\\[([=@])(.*?)\\3\\]/si",
"MarkupMarkup(\$pagename, \$m[4], \$m[2])");
Markup_e('markupend', '>markup',
"/\\(:markup(\\s+([^\n]*?))?:\\)[^\\S\n]*\n(.*?)\\(:markupend:\\)/si",
"MarkupMarkup(\$pagename, \$m[3], \$m[1])");
SDV($HTMLStylesFmt['markup'], "
table.markup { border:2px dotted #ccf; width:90%; }
td.markup1, td.markup2 { padding-left:10px; padding-right:10px; }
table.vert td.markup1 { border-bottom:1px solid #ccf; }
table.horiz td.markup1 { width:23em; border-right:1px solid #ccf; }
table.markup caption { text-align:left; }
div.faq p, div.faq pre { margin-left:2em; }
div.faq p.question { margin:1em 0 0.75em 0; font-weight:bold; }
div.faqtoc div.faq * { display:none; }
div.faqtoc div.faq p.question
{ display:block; font-weight:normal; margin:0.5em 0 0.5em 20px; line-height:normal; }
div.faqtoc div.faq p.question * { display:inline; }
");
#### Special conditions ####
## The code below adds (:if date:) conditions to the markup.
$Conditions['date'] = "CondDate(\$condparm)";
function CondDate($condparm) {
global $Now;
if (!preg_match('/^(\\S*?)(\\.\\.(\\S*))?(\\s+\\S.*)?$/',
trim($condparm), $match))
return false;
if ($match[4] == '') { $x0 = $Now; NoCache(); }
else { list($x0, $x1) = DRange($match[4]); }
if ($match[1] > '') {
list($t0, $t1) = DRange($match[1]);
if ($x0 < $t0) return false;
if ($match[2] == '' && $x0 >= $t1) return false;
}
if ($match[3] > '') {
list($t0, $t1) = DRange($match[3]);
if ($x0 >= $t1) return false;
}
return true;
}
# This pattern enables the (:encrypt <phrase>:) markup/replace-on-save
# pattern.
SDV($ROSPatterns['/\\(:encrypt\\s+([^\\s:=]+).*?:\\)/'], PCCF("return pmcrypt(\$m[1]);"));

126
wiki/scripts/trails.php Executable file
View File

@@ -0,0 +1,126 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2002-2013 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script enables markup of the form <<|TrailPage|>> to be
used to build "trails" through wiki documents.
This feature is automatically included from stdconfig.php unless
disabled by $EnableWikiTrails = 0; . To explicitly include this feature,
execute
include_once("scripts/trails.php");
from config.php somewhere.
Once enabled, the <<|TrailPage|>> markup is replaced with
<< PrevPage | TrailPage | NextPage >> on output. TrailPage should
contain either a bullet or number list defining the sequence of pages
in the "trail".
The ^|TrailPage|^ markup uses the depth of the bullets to display
the ancestry of the TrailPage to the current one. The <|TrailPage|>
markup is like <<|TrailPage|>> except that "< PrevPage |" and
"| NextPage >" are omitted if at the beginning or end of the
trail respectively. Thanks to John Rankin for contributing these
markups and the original suggestion for WikiTrails.
*/
Markup_e('<<|','<links','/&lt;&lt;\\|([^|]+|\\[\\[(.+?)\\]\\])\\|&gt;&gt;/',
"PRR(MakeTrailStop(\$pagename,\$m[1]))");
Markup_e('<|','><<|','/&lt;\\|([^|]+|\\[\\[(.+?)\\]\\])\\|&gt;/',
"PRR(MakeTrailStopB(\$pagename,\$m[1]))");
Markup_e('^|','<links','/\\^\\|([^|]+|\\[\\[(.+?)\\]\\])\\|\\^/',
"PRR(MakeTrailPath(\$pagename,\$m[1]))");
SDVA($SaveAttrPatterns, array(
'/<<\\|([^|]+|\\[\\[(.+?)\\]\\])\\|>>/' => '$1',
'/<\\|([^|]+|\\[\\[(.+?)\\]\\])\\|>/' => '$1',
'/\\^\\|([^|]+|\\[\\[(.+?)\\]\\])\\|\\^/' => '$1'));
$Conditions['ontrail'] = 'CondOnTrail($pagename, $condparm)';
function CondOnTrail($pagename, $condparm) {
@list($trailname, $pn) = preg_split('/\\s+/', $condparm, 2);
$trail = ReadTrail($pagename, $trailname);
if (!$trail) return false;
$pn = ($pn > '') ? MakePageName($pagename, $pn) : $pagename;
foreach($trail as $t)
if ($t['pagename'] == $pn) return true;
return false;
}
function ReadTrail($pagename, $trailname) {
global $RASPageName, $SuffixPattern, $GroupPattern, $WikiWordPattern,
$LinkWikiWords;
if (preg_match('/^\\[\\[(.+?)(-&gt;|\\|)(.+?)\\]\\]$/', $trailname, $m))
$trailname = ($m[2] == '|') ? $m[1] : $m[3];
$trailtext = RetrieveAuthSection($pagename, $trailname);
$trailname = $RASPageName;
$trailtext = Qualify($trailname, $trailtext);
$t = array();
$n = 0;
foreach(explode("\n", PHSC(@$trailtext, ENT_NOQUOTES))
as $x) {
$x = preg_replace("/\\[\\[([^\\]]*)-&gt;([^\\]]*)\\]\\]/",'[[$2|$1]]',$x);
if (!preg_match("/^([#*:]+) \\s*
(\\[\\[([^:#!|][^|:]*?)(?:\".*?\")?(\\|.*?)?\\]\\]($SuffixPattern)
| (($GroupPattern([\\/.]))?$WikiWordPattern)) (.*)/x",$x,$match))
continue;
if (@$match[6]) {
if (!$LinkWikiWords) continue;
$tgt = MakePageName($trailname, $match[6]);
} else $tgt = MakePageName($trailname, $match[3]);
$t[$n]['depth'] = $depth = strlen($match[1]);
$t[$n]['pagename'] = $tgt;
$t[$n]['markup'] = $match[2];
$t[$n]['detail'] = $match[9];
for($i=$depth;$i<10;$i++) $d[$i]=$n;
if ($depth>1) $t[$n]['parent']=@$d[$depth-1];
$n++;
}
return $t;
}
function MakeTrailStop($pagename,$trailname) {
$t = ReadTrail($pagename,$trailname);
$prev=''; $next='';
for($i=0;$i<count($t);$i++) {
if ($t[$i]['pagename']==$pagename) {
if ($i>0) $prev = $t[$i-1]['markup'];
if ($i+1<count($t)) $next = $t[$i+1]['markup'];
}
}
return "<span class='wikitrail'>&lt;&lt; $prev | $trailname | $next &gt;&gt;</span>";
}
function MakeTrailStopB($pagename,$trailname) {
$t = ReadTrail($pagename,$trailname);
$prev = ''; $next = '';
for($i=0;$i<count($t);$i++) {
if ($t[$i]['pagename']==$pagename) {
if ($i>0) $prev = '&lt; '.$t[$i-1]['markup'].' | ';
if ($i+1<count($t)) $next = ' | '.$t[$i+1]['markup'].' &gt;';
}
}
return "<span class='wikitrail'>$prev$trailname$next</span>";
}
function MakeTrailPath($pagename,$trailname) {
global $TrailPathSep;
SDV($TrailPathSep,' | ');
$t = ReadTrail($pagename,$trailname);
$crumbs = '';
for($i=0;$i<count($t);$i++) {
if ($t[$i]['pagename']==$pagename) {
while (@$t[$i]['depth']>0) {
$crumbs = $TrailPathSep.$t[$i]['markup'].$crumbs;
$i = @$t[$i]['parent'];
}
return "<span class='wikitrail'>$trailname$crumbs</span>";
}
}
return "<span class='wikitrail'>$trailname</span>";
}

277
wiki/scripts/transition.php Executable file
View File

@@ -0,0 +1,277 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2005-2014 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script handles various "fixup transitions" that might need to
occur to help existing sites smoothly upgrade to newer releases of
PmWiki. Rather than put the workarounds in the main code files, we
try to centralize them here so we can see what's deprecated and a
simple switch (?trans=0 in the url) can tell the admin if his site
is relying on an outdated feature or way of doing things.
Transitions defined in this script:
$Transition['nosessionencode'] - turn off session encoding
$Transition['version'] < 2001967 - all transitions listed above
$Transition['wspre'] - leading spaces are pre text
$Transition['version'] < 2001941 - all transitions listed above
$Transition['wikiwords'] - 2.1-style WikiWord processing
$Transition['version'] < 2001924 - all transitions listed above
$Transition['abslinks'] - absolute links/page vars
$Transition['version'] < 2001901 - all transitions listed above
$Transition['vspace'] - restore <p class='vspace'></p>
$Transition['version'] < 2001006 - all transitions listed above
$Transition['fplbygroup'] - restore FPLByGroup function
$Transition['version'] < 2000915 - all transitions listed above
$Transition['mainrc'] - keep using Main.AllRecentChanges
$Transition['mainapprovedurls'] - keep using Main.ApprovedUrls
$Transition['pageeditfmt'] - default $PageEditFmt value
$Transition['mainpages'] - other default pages in Main
$Transition['version'] < 1999944 - all transitions listed above
To get all of the transitions for compatibility with a previous
version of PmWiki, simply set $Transition['version'] in a local
configuration file to the version number you want compatibility
with. All of the transitions associated with that version will
then be enabled. Example:
# Keep compatibility with PmWiki version 2.0.13
$Transition['version'] = 2000013;
To explicitly enable or disable specific transitions, set
the corresponding $Transition[] element to 1 or 0. This will
override the $Transition['version'] item listed above. For
example, to enable just the 'pageeditfmt' transition, use
$Transition['pageeditfmt'] = 1;
*/
## if ?trans=0 is specified, then we don't do any fixups.
if (@$_REQUEST['trans']==='0') return;
## set a default Transition version if we don't have one
SDV($Transition['version'], $VersionNum);
## Transitions from 2.2.0-beta67
if (@$Transition['version'] < 2001967)
SDVA($Transition, array('nosessionencode' => 1));
if (@$Transition['nosessionencode']) {
$SessionEncode = NULL;
$SessionDecode = NULL;
}
## Transitions from 2.2.0-beta41
if (@$Transition['version'] < 2001941)
SDVA($Transition, array('wspre' => 1));
if (@$Transition['wspre']) SDV($EnableWSPre, 1);
## Transitions from 2.2.0-beta24
if (@$Transition['version'] < 2001924)
SDVA($Transition, array('wikiwords' => 1));
## wikiwords:
## This restores the PmWiki 2.1 behavior for WikiWord processing.
## WikiWords aren't linked by default, but appear with
## <span class='wikiword'>...</span> tags around them.
if (@$Transition['wikiwords']) {
SDV($EnableWikiWords, 1);
SDV($LinkWikiWords, 0);
}
## Transitions from 2.2.0-beta1
if (@$Transition['version'] < 2001901)
SDVA($Transition, array('abslinks' => 1));
## abslinks:
## This restores settings so that PmWiki treats all links
## as absolute (following the 2.1.x and earlier interpretation).
if (@$Transition['abslinks']) {
SDV($EnableRelativePageLinks, 0);
SDV($EnableRelativePageVars, 0);
}
## Transitions from 2.1.12
if (@$Transition['version'] < 2001012)
SDVA($Transition, array('nodivnest' => 1));
## nodivnest:
## This restores the PmWiki 2.1.11 behavior that doesn't
## allow nesting of divs and tables.
if (@$Transition['nodivnest']) {
function TCells($name,$attr) {
global $MarkupFrame;
$attr = preg_replace('/([a-zA-Z]=)([^\'"]\\S*)/',"\$1'\$2'",$attr);
$tattr = @$MarkupFrame[0]['tattr'];
$name = strtolower($name);
$out = '<:block>';
if (strncmp($name, 'cell', 4) != 0 || @$MarkupFrame[0]['closeall']['div']) {
$out .= @$MarkupFrame[0]['closeall']['div'];
unset($MarkupFrame[0]['closeall']['div']);
$out .= @$MarkupFrame[0]['closeall']['table'];
unset($MarkupFrame[0]['closeall']['table']);
}
if ($name == 'div') {
$MarkupFrame[0]['closeall']['div'] = "</div>";
$out .= "<div $attr>";
}
if ($name == 'table') $MarkupFrame[0]['tattr'] = $attr;
if (strncmp($name, 'cell', 4) == 0) {
if (strpos($attr, "valign=")===false) $attr .= " valign='top'";
if (!@$MarkupFrame[0]['closeall']['table']) {
$MarkupFrame[0]['closeall']['table'] = "</td></tr></table>";
$out .= "<table $tattr><tr><td $attr>";
} else if ($name == 'cellnr') $out .= "</td></tr><tr><td $attr>";
else $out .= "</td><td $attr>";
}
return $out;
}
Markup_e('table', '<block',
'/^\\(:(table|cell|cellnr|tableend|div|divend)(\\s.*?)?:\\)/i',
"TCells(\$m[1],\$m[2])");
}
## Transitions from 2.1.7
if (@$Transition['version'] < 2001007)
SDVA($Transition, array('vspace' => 1));
## vspace:
## This restores PmWiki's use of <p class='vspace'></p> to mark
## vertical space in the output.
if (@$Transition['vspace']) $HTMLVSpace = "<p class='vspace'></p>";
## Transitions from 2.1.beta15
if (@$Transition['version'] < 2000915)
SDVA($Transition, array('fplbygroup' => 1));
## fplbygroup:
## The FPLByGroup function was removed in 2.1.beta15, this restores it.
if (@$Transition['fplbygroup'] && !function_exists('FPLByGroup')) {
SDV($FPLFormatOpt['bygroup'], array('fn' => 'FPLByGroup'));
function FPLByGroup($pagename, &$matches, $opt) {
global $FPLByGroupStartFmt, $FPLByGroupEndFmt, $FPLByGroupGFmt,
$FPLByGroupIFmt, $FPLByGroupOpt;
SDV($FPLByGroupStartFmt,"<dl class='fplbygroup'>");
SDV($FPLByGroupEndFmt,'</dl>');
SDV($FPLByGroupGFmt,"<dt><a href='\$ScriptUrl/\$Group'>\$Group</a> /</dt>\n");
SDV($FPLByGroupIFmt,"<dd><a href='\$PageUrl'>\$Name</a></dd>\n");
SDVA($FPLByGroupOpt, array('readf' => 0, 'order' => 'name'));
$matches = MakePageList($pagename,
array_merge((array)$FPLByGroupOpt, $opt), 0);
if (@$opt['count']) array_splice($matches, $opt['count']);
if (count($matches)<1) return '';
$out = '';
foreach($matches as $pn) {
$pgroup = FmtPageName($FPLByGroupGFmt, $pn);
if ($pgroup != @$lgroup) { $out .= $pgroup; $lgroup = $pgroup; }
$out .= FmtPageName($FPLByGroupIFmt, $pn);
}
return FmtPageName($FPLByGroupStartFmt, $pagename) . $out .
FmtPageName($FPLByGroupEndFmt, $pagename);
}
}
## Transitions from 2.0.beta44
if (@$Transition['version'] < 1999944)
SDVA($Transition, array('mainrc' => 1, 'mainapprovedurls' => 1,
'pageeditfmt' => 1, 'mainpages' => 1));
## mainrc:
## 2.0.beta44 switched Main.AllRecentChanges to be
## $SiteGroup.AllRecentChanges. This setting keeps Main.AllRecentChanges
## if it exists.
if (@$Transition['mainrc'] && PageExists('Main.AllRecentChanges')) {
SDV($RecentChangesFmt['Main.AllRecentChanges'],
'* [[$Group.$Name]] . . . $CurrentTime $[by] $AuthorLink');
}
## siteapprovedurls:
## 2.0.beta44 switched Main.ApprovedUrls to be $SiteGroup.ApprovedUrls .
## This setting keeps using Main.ApprovedUrls if it exists.
if (@$Transition['mainapprovedurls'] && PageExists('Main.ApprovedUrls')) {
$ApprovedUrlPagesFmt = (array)$ApprovedUrlPagesFmt;
if (PageExists(FmtPageName($ApprovedUrlPagesFmt[0], $pagename)))
$ApprovedUrlPagesFmt[] = 'Main.ApprovedUrls';
else array_unshift($ApprovedUrlPagesFmt, 'Main.ApprovedUrls');
}
## pageeditfmt:
## 2.0.beta44 switched to using wiki markup forms for page editing.
## However, some sites and skins have customized values of $PageEdit.
## This setting restores the default values.
if (@$Transition['pageeditfmt']) {
SDV($PageEditFmt, "<div id='wikiedit'>
<a id='top' name='top'></a>
<h1 class='wikiaction'>$[Editing \$FullName]</h1>
<form method='post' action='\$PageUrl?action=edit'>
<input type='hidden' name='action' value='edit' />
<input type='hidden' name='n' value='\$FullName' />
<input type='hidden' name='basetime' value='\$EditBaseTime' />
\$EditMessageFmt
<textarea id='text' name='text' rows='25' cols='60'
onkeydown='if (event.keyCode==27) event.returnValue=false;'
>\$EditText</textarea><br />
$[Author]: <input type='text' name='author' value='\$Author' />
<input type='checkbox' name='diffclass' value='minor' \$DiffClassMinor />
$[This is a minor edit]<br />
<input type='submit' name='post' value=' $[Save] ' />
<input type='submit' name='preview' value=' $[Preview] ' />
<input type='reset' value=' $[Reset] ' /></form></div>");
if (@$_POST['preview'])
SDV($PagePreviewFmt, "<div id='wikipreview'>
<h2 class='wikiaction'>$[Preview \$FullName]</h2>
<p><b>$[Page is unsaved]</b></p>
\$PreviewText
<hr /><p><b>$[End of preview -- remember to save]</b><br />
<a href='#top'>$[Top]</a></p></div>");
SDV($HandleEditFmt, array(&$PageStartFmt,
&$PageEditFmt, 'wiki:$[PmWiki.EditQuickReference]', &$PagePreviewFmt,
&$PageEndFmt));
$EditMessageFmt = implode('', $MessagesFmt) . $EditMessageFmt;
if ($action=='edit' && IsEnabled($EnableGUIButtons, 0))
array_push($EditFunctions, 'GUIEdit');
} else $MessagesFmt[] = @$EditMessageFmt;
function GUIEdit($pagename, &$page, &$new) {
global $EditMessageFmt;
$EditMessageFmt .= GUIButtonCode($pagename);
}
## mainpages:
## In 2.0.beta44 several utility pages change location to the new Site
## group. These settings cause some skins (that use translations)
## to know to link to the new locations.
if (@$Transition['mainpages']) {
XLSDV('en', array(
'Main/SearchWiki' => XL('Site/Search'),
'PmWiki.EditQuickReference' => XL('Site/EditQuickReference'),
'PmWiki.UploadQuickReference' => XL('Site/UploadQuickReference'),
));
}

99
wiki/scripts/upgrades.php Executable file
View File

@@ -0,0 +1,99 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2007-2011 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
*/
global $HandleActions, $HandleAuth;
$HandleActions['upgrade'] = 'HandleUpgrade';
$HandleAuth['upgrade'] = 'read';
function HandleUpgrade($pagename, $auth = 'ALWAYS') {
global $SiteGroup, $SiteAdminGroup, $StatusPageName, $ScriptUrl,
$AuthUserPageFmt, $VersionNum, $Version;
StopWatch('HandleUpgrade: begin');
$message = '';
$done = '';
## check for Site.* --> SiteAdmin.*
foreach(array('AuthUser', 'NotifyList', 'Blocklist', 'ApprovedUrls') as $n) {
$n0 = "$SiteGroup.$n"; $n1 = "$SiteAdminGroup.$n";
StopWatch("HandleUpgrade: checking $n0 -> $n1");
## checking AuthUser is special, because Site.AuthUser comes with the
## distribution.
if ($n == 'AuthUser') {
## if we already have a user-modified SiteAdmin.AuthUser, we can skip
SDV($AuthUserPageFmt, '$SiteAdminGroup.AuthUser');
$n1 = FmtPageName($AuthUserPageFmt, $pagename);
$page = ReadPage($n1, READPAGE_CURRENT);
if (@$page['time'] > 1000000000) continue;
## if there's not a user-modified Site.AuthUser, we can skip
$page = ReadPage($n0, READPAGE_CURRENT);
if (@$page['time'] == 1000000000) continue;
} else if (!PageExists($n0) || PageExists($n1)) continue;
if (@$_REQUEST['migrate'] == 'yes') {
## if the admin wants PmWiki to migrate, do it.
$page = RetrieveAuthPage($n0, 'admin', true);
StopWatch("HandleUpgrade: copying $n0 -> $n1");
if ($page) {
WritePage($n1, $page);
$done .= "<li>Copied $n0 to $n1</li>";
continue;
}
}
$message .= "<li>$n0 -&gt; $n1</li>";
}
if ($message) {
$migrateurl = "$ScriptUrl?action=upgrade&amp;migrate=yes";
$infourl = 'http://www.pmwiki.org/wiki/PmWiki/UpgradeToSiteAdmin';
$message =
"<h2>Upgrade notice -- SiteAdmin group</h2>
<p>This version of PmWiki expects several administrative pages
from the <em>Site</em> group to be found in a new <em>SiteAdmin</em> group.
On this site, the following pages appear to need to be relocated:</p>
<ul>$message</ul>
<p>For more information about this change, including the various
options for proceeding, see</p>
<blockquote><a target='_blank' href='$infourl'>$infourl</a></blockquote>
<form action='$ScriptUrl' method='post'>
<p>If you would like PmWiki to attempt to automatically copy
these pages into their new <br /> locations for you, try
<input type='hidden' name='action' value='upgrade' />
<input type='hidden' name='migrate' value='yes' />
<input type='submit' value='Relocate pages listed above' />
(admin password required) </p>
</form>
<p>If you want to configure PmWiki so that it continues to
look for the above pages in <em>$SiteGroup</em>, add the
following line near the top of <em>local/config.php</em>:</p>
<blockquote><pre>\$SiteAdminGroup = \$SiteGroup;</pre></blockquote>
$Version
";
print $message;
exit;
}
StopWatch("UpgradeCheck: writing $StatusPageName");
Lock(2);
SDV($StatusPageName, "$SiteAdminGroup.Status");
$page = ReadPage($StatusPageName);
$page['updatedto'] = $VersionNum;
WritePage($StatusPageName, $page);
if ($done) {
$done .= "<li>Updated $StatusPageName</li>";
echo "<h2>Upgrade to $Version ... ok</h2><ul>$done</ul>";
$GLOBALS['EnableRedirect'] = 0;
}
Redirect($pagename);
}

374
wiki/scripts/upload.php Executable file
View File

@@ -0,0 +1,374 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2015 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script adds upload capabilities to PmWiki. Uploads can be
enabled by setting
$EnableUpload = 1;
in config.php. In addition, an upload password must be set, as
the default is to lock uploads. In some configurations it may also
be necessary to set values for $UploadDir and $UploadUrlFmt,
especially if any form of URL rewriting is being performed.
See the PmWiki.UploadsAdmin page for more information.
*/
## $EnableUploadOverwrite determines if we allow previously uploaded
## files to be overwritten.
SDV($EnableUploadOverwrite,1);
## $UploadExts contains the list of file extensions we're willing to
## accept, along with the Content-Type: value appropriate for each.
SDVA($UploadExts,array(
'gif' => 'image/gif', 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg',
'png' => 'image/png', 'bmp' => 'image/bmp', 'ico' => 'image/x-icon',
'wbmp'=> 'image/vnd.wap.wbmp', 'svg' => 'image/svg+xml', 'xcf' => 'image/x-xcf',
'mp3' => 'audio/mpeg', 'au' => 'audio/basic', 'wav' => 'audio/x-wav',
'ogg' => 'audio/ogg', 'flac' => 'audio/x-flac',
'ogv' => 'video/ogg', 'mp4' => 'video/mp4', 'webm' => 'video/webm',
'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg',
'mov' => 'video/quicktime', 'qt' => 'video/quicktime',
'wmf' => 'text/plain', 'avi' => 'video/x-msvideo',
'zip' => 'application/zip', '7z' => 'application/x-7z-compressed',
'gz' => 'application/x-gzip', 'tgz' => 'application/x-gzip',
'rpm' => 'application/x-rpm',
'hqx' => 'application/mac-binhex40', 'sit' => 'application/x-stuffit',
'doc' => 'application/msword', 'ppt' => 'application/vnd.ms-powerpoint',
'xls' => 'application/vnd.ms-excel', 'mdb' => 'text/plain',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'exe' => 'application/octet-stream',
'pdf' => 'application/pdf', 'psd' => 'text/plain',
'ps' => 'application/postscript', 'ai' => 'application/postscript',
'eps' => 'application/postscript',
'htm' => 'text/html', 'html' => 'text/html', 'css' => 'text/css',
'fla' => 'application/x-shockwave-flash',
'swf' => 'application/x-shockwave-flash',
'txt' => 'text/plain', 'rtf' => 'application/rtf',
'tex' => 'application/x-tex', 'dvi' => 'application/x-dvi',
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'odg' => 'application/vnd.oasis.opendocument.graphics',
'epub'=> 'application/epub+zip',
'kml' => 'application/vnd.google-earth.kml+xml',
'kmz' => 'application/vnd.google-earth.kmz',
'' => 'text/plain'));
# Array containing forbidden strings in a filename, array('.php', '.cgi')
SDV($UploadBlacklist, array());
SDV($UploadMaxSize,50000);
SDV($UploadPrefixQuota,0);
SDV($UploadDirQuota,0);
foreach($UploadExts as $k=>$v)
if (!isset($UploadExtSize[$k])) $UploadExtSize[$k]=$UploadMaxSize;
SDV($UploadDir,'uploads');
SDV($UploadPermAdd,0444);
SDV($UploadPermSet,0);
SDV($UploadPrefixFmt,'/$Group');
SDV($UploadFileFmt,"$UploadDir$UploadPrefixFmt");
$v = preg_replace('#^/(.*/)#', '', $UploadDir);
SDV($UploadUrlFmt,preg_replace('#/[^/]*$#', "/$v", $PubDirUrl, 1));
SDV($LinkUploadCreateFmt, "<a rel='nofollow' class='createlinktext' href='\$LinkUpload'>\$LinkText</a><a rel='nofollow' class='createlink' href='\$LinkUpload'>&nbsp;&Delta;</a>");
SDVA($ActionTitleFmt, array('upload' => '| $[Attach]'));
SDV($PageUploadFmt,array("
<div id='wikiupload'>
<h2 class='wikiaction'>$[Attachments for] {\$FullName}</h2>
<h3>\$UploadResult</h3>
<form enctype='multipart/form-data' action='{\$PageUrl}' method='post'>
<input type='hidden' name='n' value='{\$FullName}' />
<input type='hidden' name='action' value='postupload' />
<table border='0'>
<tr><td align='right'>$[File to upload:]</td><td><input
name='uploadfile' type='file' /></td></tr>
<tr><td align='right'>$[Name attachment as:]</td>
<td><input type='text' name='upname' value='\$UploadName' /><input
type='submit' value=' $[Upload] ' /><br />
</td></tr></table></form></div>",
'wiki:$[{$SiteGroup}/UploadQuickReference]'));
XLSDV('en',array(
'ULsuccess' => 'successfully uploaded',
'ULbadname' => 'invalid attachment name',
'ULbadtype' => '\'$upext\' is not an allowed file extension',
'ULtoobig' => 'file is larger than maximum allowed by webserver',
'ULtoobigext' => 'file is larger than allowed maximum of $upmax
bytes for \'$upext\' files',
'ULpartial' => 'incomplete file received',
'ULnofile' => 'no file uploaded',
'ULexists' => 'file with that name already exists',
'ULpquota' => 'group quota exceeded',
'ULtquota' => 'upload quota exceeded'));
SDV($PageAttributes['passwdupload'],'$[Set new upload password:]');
SDV($DefaultPasswords['upload'],'*');
SDV($AuthCascade['upload'], 'read');
SDV($FmtPV['$PasswdUpload'], 'PasswdVar($pn, "upload")');
Markup_e('attachlist', 'directives',
'/\\(:attachlist\\s*(.*?):\\)/i',
"Keep('<ul>'.FmtUploadList('$pagename',\$m[1]).'</ul>')");
SDV($GUIButtons['attach'], array(220, 'Attach:', '', '$[file.ext]',
'$GUIButtonDirUrlFmt/attach.gif"$[Attach file]"'));
SDV($LinkFunctions['Attach:'], 'LinkUpload');
SDV($IMap['Attach:'], '$1');
SDVA($HandleActions, array('upload' => 'HandleUpload',
'postupload' => 'HandlePostUpload',
'download' => 'HandleDownload'));
SDVA($HandleAuth, array('upload' => 'upload',
'download' => 'read'));
SDV($HandleAuth['postupload'], $HandleAuth['upload']);
SDV($UploadVerifyFunction, 'UploadVerifyBasic');
function MakeUploadName($pagename,$x) {
global $UploadNameChars, $MakeUploadNamePatterns;
SDV($UploadNameChars, "-\\w. ");
SDV($MakeUploadNamePatterns, array(
"/[^$UploadNameChars]/" => '',
'/\\.[^.]*$/' => PCCF('return strtolower($m[0]);'),
'/^[^[:alnum:]_]+/' => '',
'/[^[:alnum:]_]+$/' => ''));
return PPRA($MakeUploadNamePatterns, $x);
}
function LinkUpload($pagename, $imap, $path, $alt, $txt, $fmt=NULL) {
global $FmtV, $UploadFileFmt, $LinkUploadCreateFmt,
$UploadUrlFmt, $UploadPrefixFmt, $EnableDirectDownload;
if (preg_match('!^(.*)/([^/]+)$!', $path, $match)) {
$pagename = MakePageName($pagename, $match[1]);
$path = $match[2];
}
$upname = MakeUploadName($pagename, $path);
$encname = rawurlencode($upname);
$filepath = FmtPageName("$UploadFileFmt/$upname", $pagename);
$FmtV['$LinkUpload'] =
FmtPageName("\$PageUrl?action=upload&amp;upname=$encname", $pagename);
$FmtV['$LinkText'] = $txt;
if (!file_exists($filepath))
return FmtPageName($LinkUploadCreateFmt, $pagename);
$path = PUE(FmtPageName(IsEnabled($EnableDirectDownload, 1)
? "$UploadUrlFmt$UploadPrefixFmt/$encname"
: "{\$PageUrl}?action=download&amp;upname=$encname",
$pagename));
return LinkIMap($pagename, $imap, $path, $alt, $txt, $fmt);
}
# Authenticate group downloads with the group password
function UploadAuth($pagename, $auth, $cache=0){
global $GroupAttributesFmt, $EnableUploadGroupAuth;
if (IsEnabled($EnableUploadGroupAuth,0)){
SDV($GroupAttributesFmt,'$Group/GroupAttributes');
$pn_upload = FmtPageName($GroupAttributesFmt, $pagename);
} else $pn_upload = $pagename;
$page = RetrieveAuthPage($pn_upload, $auth, true, READPAGE_CURRENT);
if(!$page) Abort("?No '$auth' permissions for $pagename");
if($cache) PCache($pn_upload,$page);
return true;
}
function HandleUpload($pagename, $auth = 'upload') {
global $FmtV,$UploadExtMax, $EnableReadOnly,
$HandleUploadFmt,$PageStartFmt,$PageEndFmt,$PageUploadFmt;
UploadAuth($pagename, $auth, 1);
$FmtV['$UploadName'] = MakeUploadName($pagename,@$_REQUEST['upname']);
$upresult = PHSC(@$_REQUEST['upresult']);
$uprname = PHSC(@$_REQUEST['uprname']);
$FmtV['$upext'] = PHSC(@$_REQUEST['upext']);
$FmtV['$upmax'] = PHSC(@$_REQUEST['upmax']);
$FmtV['$UploadResult'] = ($upresult) ?
FmtPageName("<i>$uprname</i>: $[UL$upresult]",$pagename) :
(@$EnableReadOnly ? XL('Cannot modify site -- $EnableReadOnly is set'): '');
SDV($HandleUploadFmt,array(&$PageStartFmt,&$PageUploadFmt,&$PageEndFmt));
PrintFmt($pagename,$HandleUploadFmt);
}
function HandleDownload($pagename, $auth = 'read') {
global $UploadFileFmt, $UploadExts, $DownloadDisposition, $EnableIMSCaching;
SDV($DownloadDisposition, "inline");
UploadAuth($pagename, $auth);
$upname = MakeUploadName($pagename, @$_REQUEST['upname']);
$filepath = FmtPageName("$UploadFileFmt/$upname", $pagename);
if (!$upname || !file_exists($filepath)) {
header("HTTP/1.0 404 Not Found");
Abort("?requested file not found");
exit();
}
if (IsEnabled($EnableIMSCaching, 0)) {
header('Cache-Control: private');
header('Expires: ');
$filelastmod = gmdate('D, d M Y H:i:s \G\M\T', filemtime($filepath));
if (@$_SERVER['HTTP_IF_MODIFIED_SINCE'] == $filelastmod)
{ header("HTTP/1.0 304 Not Modified"); exit(); }
header("Last-Modified: $filelastmod");
}
preg_match('/\\.([^.]+)$/',$filepath,$match);
if ($UploadExts[@$match[1]])
header("Content-Type: {$UploadExts[@$match[1]]}");
header("Content-Length: ".filesize($filepath));
header("Content-disposition: $DownloadDisposition; filename=\"$upname\"");
$fp = fopen($filepath, "rb");
if ($fp) {
while (!feof($fp)) echo fread($fp, 4096);
flush();
fclose($fp);
}
exit();
}
function HandlePostUpload($pagename, $auth = 'upload') {
global $UploadVerifyFunction, $UploadFileFmt, $LastModFile,
$EnableUploadVersions, $Now, $RecentUploadsFmt, $FmtV,
$NotifyItemUploadFmt, $NotifyItemFmt, $IsUploadPosted,
$UploadRedirectFunction, $UploadPermAdd, $UploadPermSet,
$EnableReadOnly;
if(IsEnabled($EnableReadOnly, 0))
Abort('Cannot modify site -- $EnableReadOnly is set', 'readonly');
UploadAuth($pagename, $auth);
$uploadfile = $_FILES['uploadfile'];
$upname = $_REQUEST['upname'];
if ($upname=='') $upname=$uploadfile['name'];
$upname = MakeUploadName($pagename,$upname);
if (!function_exists($UploadVerifyFunction))
Abort('?no UploadVerifyFunction available');
$filepath = FmtPageName("$UploadFileFmt/$upname",$pagename);
$result = $UploadVerifyFunction($pagename,$uploadfile,$filepath);
if ($result=='') {
$filedir = preg_replace('#/[^/]*$#','',$filepath);
mkdirp($filedir);
if (IsEnabled($EnableUploadVersions, 0))
@rename($filepath, "$filepath,$Now");
if (!move_uploaded_file($uploadfile['tmp_name'],$filepath))
{ Abort("?cannot move uploaded file to $filepath"); return; }
fixperms($filepath, $UploadPermAdd, $UploadPermSet);
if ($LastModFile) { touch($LastModFile); fixperms($LastModFile); }
$result = "upresult=success";
$FmtV['$upname'] = $upname;
$FmtV['$upsize'] = $uploadfile['size'];
if (IsEnabled($RecentUploadsFmt, 0)) {
PostRecentChanges($pagename, '', '', $RecentUploadsFmt);
}
if (IsEnabled($NotifyItemUploadFmt, 0) && function_exists('NotifyUpdate')) {
$NotifyItemFmt = $NotifyItemUploadFmt;
$IsUploadPosted = 1;
register_shutdown_function('NotifyUpdate', $pagename, getcwd());
}
}
SDV($UploadRedirectFunction, 'Redirect');
$UploadRedirectFunction($pagename,"{\$PageUrl}?action=upload&uprname=$upname&$result");
}
function UploadVerifyBasic($pagename,$uploadfile,$filepath) {
global $EnableUploadOverwrite,$UploadExtSize,$UploadPrefixQuota,
$UploadDirQuota,$UploadDir, $UploadBlacklist;
if (count($UploadBlacklist)) {
$tmp = explode("/", $filepath);
$upname = strtolower(end($tmp));
foreach($UploadBlacklist as $needle) {
if (strpos($upname, $needle)!==false) return 'upresult=badname';
}
}
if (!$EnableUploadOverwrite && file_exists($filepath))
return 'upresult=exists';
preg_match('/\\.([^.\\/]+)$/',$filepath,$match); $ext=@$match[1];
$maxsize = $UploadExtSize[$ext];
if ($maxsize<=0) return "upresult=badtype&upext=$ext";
if ($uploadfile['size']>$maxsize)
return "upresult=toobigext&upext=$ext&upmax=$maxsize";
switch (@$uploadfile['error']) {
case 1: return 'upresult=toobig';
case 2: return 'upresult=toobig';
case 3: return 'upresult=partial';
case 4: return 'upresult=nofile';
}
if (!is_uploaded_file($uploadfile['tmp_name'])) return 'upresult=nofile';
$filedir = preg_replace('#/[^/]*$#','',$filepath);
if ($UploadPrefixQuota &&
(dirsize($filedir)-@filesize($filepath)+$uploadfile['size']) >
$UploadPrefixQuota) return 'upresult=pquota';
if ($UploadDirQuota &&
(dirsize($UploadDir)-@filesize($filepath)+$uploadfile['size']) >
$UploadDirQuota) return 'upresult=tquota';
return '';
}
function dirsize($dir) {
$size = 0;
$dirp = @opendir($dir);
if (!$dirp) return 0;
while (($file=readdir($dirp)) !== false) {
if ($file[0]=='.') continue;
if (is_dir("$dir/$file")) $size+=dirsize("$dir/$file");
else $size+=filesize("$dir/$file");
}
closedir($dirp);
return $size;
}
function FmtUploadList($pagename, $args) {
global $UploadDir, $UploadPrefixFmt, $UploadUrlFmt, $EnableUploadOverwrite,
$TimeFmt, $EnableDirectDownload, $IMapLinkFmt, $UrlLinkFmt, $FmtV;
$opt = ParseArgs($args);
if (@$opt[''][0]) $pagename = MakePageName($pagename, $opt[''][0]);
if (@$opt['ext'])
$matchext = '/\\.('
. implode('|', preg_split('/\\W+/', $opt['ext'], -1, PREG_SPLIT_NO_EMPTY))
. ')$/i';
$uploaddir = FmtPageName("$UploadDir$UploadPrefixFmt", $pagename);
$uploadurl = FmtPageName(IsEnabled($EnableDirectDownload, 1)
? "$UploadUrlFmt$UploadPrefixFmt/"
: "\$PageUrl?action=download&amp;upname=",
$pagename);
$dirp = @opendir($uploaddir);
if (!$dirp) return '';
$filelist = array();
while (($file=readdir($dirp)) !== false) {
if ($file{0} == '.') continue;
if (@$matchext && !preg_match(@$matchext, $file)) continue;
$filelist[$file] = rawurlencode($file);
}
closedir($dirp);
$out = array();
natcasesort($filelist);
$overwrite = '';
$fmt = IsEnabled($IMapLinkFmt['Attach:'], $UrlLinkFmt);
foreach($filelist as $file=>$encfile) {
$FmtV['$LinkUrl'] = PUE("$uploadurl$encfile");
$FmtV['$LinkText'] = $file;
$FmtV['$LinkUpload'] =
FmtPageName("\$PageUrl?action=upload&amp;upname=$encfile", $pagename);
$stat = stat("$uploaddir/$file");
if ($EnableUploadOverwrite)
$overwrite = FmtPageName("<a rel='nofollow' class='createlink'
href='\$LinkUpload'>&nbsp;&Delta;</a>",
$pagename);
$lnk = FmtPageName($fmt, $pagename);
$out[] = "<li> $lnk$overwrite ... ".
number_format($stat['size']) . " bytes ... " .
strftime($TimeFmt, $stat['mtime']) . "</li>";
}
return implode("\n",$out);
}
# this adds (:if [!]attachments:) to the markup
$Conditions['attachments'] = "AttachExist(\$pagename)";
function AttachExist($pagename) {
global $UploadDir, $UploadPrefixFmt;
$uploaddir = FmtPageName("$UploadDir$UploadPrefixFmt", $pagename);
$count = 0;
$dirp = @opendir($uploaddir);
if ($dirp) {
while (($file = readdir($dirp)) !== false)
if ($file{0} != '.') $count++;
closedir($dirp);
}
return $count;
}

126
wiki/scripts/urlapprove.php Executable file
View File

@@ -0,0 +1,126 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2013 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script provides a URL-approval capability. To enable this
script, add the following line to a configuration file:
include_once('scripts/urlapprove.php');
The URL prefixes to be allowed are stored as patterns in
$WhiteUrlPatterns. This array can be loaded from config.php, or
from the wiki pages given by the $ApprovedUrlPagesFmt[] array.
Any http: or https: URL that isn't in $WhiteUrlPatterns is rendered
using $UnapprovedLinkFmt.
The script also provides ?action=approveurls and ?action=approvesites,
which scan the current page for any new URLs to be automatically added
the first page of $UrlApprovalPagesFmt.
Finally, the script will block any post containing more than
$UnapprovedLinkCountMax unapproved urls in it. By default this
is set to a very large number, leaving the posting of unapproved
urls wide open, but by setting $UnapprovedLinkCountMax to a smaller
number you can limit the number of unapproved urls that make it into
a page. (Wikispammers seem to like to post long lists of urls, while
more "normal" authors tend to only post a few.)
*/
$LinkFunctions['http:'] = 'LinkHTTP';
$LinkFunctions['https:'] = 'LinkHTTP';
SDV($ApprovedUrlPagesFmt, array('$SiteAdminGroup.ApprovedUrls'));
SDV($UnapprovedLinkFmt,
"\$LinkText<a class='apprlink' href='{\$PageUrl}?action=approvesites'>$[(approve sites)]</a>");
$HTMLStylesFmt['urlapprove'] = '.apprlink { font-size:smaller; }';
SDV($ApproveUrlPattern,
"\\bhttps?:[^\\s$UrlExcludeChars]*[^\\s.,?!$UrlExcludeChars]");
$WhiteUrlPatterns = (array)$WhiteUrlPatterns;
SDV($HandleActions['approveurls'], 'HandleApprove');
SDV($HandleAuth['approveurls'], 'edit');
SDV($HandleActions['approvesites'], 'HandleApprove');
SDV($HandleAuth['approvesites'], 'edit');
SDV($UnapprovedLinkCountMax, 1000000);
array_splice($EditFunctions, array_search('PostPage', $EditFunctions),
0, 'BlockUnapprovedPosts');
function LinkHTTP($pagename,$imap,$path,$alt,$txt,$fmt=NULL) {
global $EnableUrlApprovalRequired, $IMap, $WhiteUrlPatterns, $FmtV,
$UnapprovedLink, $UnapprovedLinkCount, $UnapprovedLinkFmt;
if (!IsEnabled($EnableUrlApprovalRequired,1))
return LinkIMap($pagename,$imap,$path,$alt,$txt,$fmt);
static $havereadpages;
if (!$havereadpages) { ReadApprovedUrls($pagename); $havereadpages=true; }
$p = str_replace(' ','%20',$path);
$url = str_replace('$1',$p,$IMap[$imap]);
if (!isset($UnapprovedLink)) $UnapprovedLink = array();
foreach((array)$WhiteUrlPatterns as $pat) {
if (preg_match("!^$pat(/|$)!i",$url))
return LinkIMap($pagename,$imap,$path,$alt,$txt,$fmt);
}
$FmtV['$LinkUrl'] = PUE(str_replace('$1',$path,$IMap[$imap]));
$FmtV['$LinkText'] = $txt;
$FmtV['$LinkAlt'] = str_replace(array('"',"'"),array('&#34;','&#39;'),$alt);
$UnapprovedLink[] = $url;
@$UnapprovedLinkCount++;
return FmtPageName($UnapprovedLinkFmt,$pagename);
}
function ReadApprovedUrls($pagename) {
global $ApprovedUrlPagesFmt,$ApproveUrlPattern,$WhiteUrlPatterns;
foreach((array)$ApprovedUrlPagesFmt as $p) {
$pn = FmtPageName($p, $pagename);
StopWatch("ReadApprovedUrls $pn begin");
$apage = ReadPage($pn, READPAGE_CURRENT);
preg_match_all("/$ApproveUrlPattern/",@$apage['text'],$match);
foreach($match[0] as $a)
$WhiteUrlPatterns[] = preg_quote($a,'!');
StopWatch("ReadApprovedUrls $pn end");
}
}
function HandleApprove($pagename, $auth='edit') {
global $ApproveUrlPattern,$WhiteUrlPatterns,$ApprovedUrlPagesFmt,$action;
Lock(2);
$page = ReadPage($pagename);
$text = preg_replace('/[()]/','',$page['text']);
preg_match_all("/$ApproveUrlPattern/",$text,$match);
ReadApprovedUrls($pagename);
$addpat = array();
foreach($match[0] as $a) {
if ($action=='approvesites')
$a=preg_replace("!^([^:]+://[^/]+).*$!",'$1',$a);
$addpat[] = $a;
}
if (count($addpat)>0) {
$aname = FmtPageName($ApprovedUrlPagesFmt[0],$pagename);
$apage = RetrieveAuthPage($aname, $auth);
if (!$apage) Abort("?cannot edit $aname");
$new = $apage;
if (substr($new['text'],-1,1)!="\n") $new['text'].="\n";
foreach($addpat as $a) {
foreach((array)$WhiteUrlPatterns as $pat)
if (preg_match("!^$pat(/|$)!i",$a)) continue 2;
$urlp = preg_quote($a,'!');
$WhiteUrlPatterns[] = $urlp;
$new['text'].=" $a\n";
}
$_POST['post'] = 'y';
PostPage($aname,$apage,$new);
}
Redirect($pagename);
}
function BlockUnapprovedPosts($pagename, &$page, &$new) {
global $EnableUrlApprovalRequired, $UnapprovedLinkCount,
$UnapprovedLinkCountMax, $EnablePost, $MessagesFmt, $BlockMessageFmt;
if (!IsEnabled($EnableUrlApprovalRequired, 1)) return;
if ($UnapprovedLinkCount <= $UnapprovedLinkCountMax) return;
if ($page['=auth']['admin']) return;
$EnablePost = 0;
$MessagesFmt[] = $BlockMessageFmt;
$MessagesFmt[] = XL('Too many unapproved external links.');
}

78
wiki/scripts/vardoc.php Executable file
View File

@@ -0,0 +1,78 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2002-2013 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script provides special handling for WikiWords that are
preceded by a $, treating them as PmWiki variables to be looked up
in the variable documentation pages if such documentation exists.
The $VarPagesFmt variable contains a list of pages to be searched
to build an index of the variable documentation. This index is
generated only once per browse request, and then only when needed.
*/
SDV($VarPagesFmt,array('$[PmWiki.Variables]'));
Markup_e('varlink','<wikilink',"/\\$($WikiWordPattern)\\b/",
"Keep(VarLink(\$pagename,\$m[1],'$'.\$m[1]))");
Markup('vardef','<links',"/^:\\$($WikiWordPattern):/",
':[[#$1]]$$1:');
Markup_e('varindex', 'directives',
'/\\(:varindex:\\)/i',
"Keep(VarIndexList(\$pagename))");
$HTMLStylesFmt['vardoc'] = "a.varlink { text-decoration:none; }\n";
function VarLink($pagename,$tgt,$txt) {
global $VarIndex,$FmtV,$VarLinkMissingFmt,$VarLinkExistsFmt;
SDV($VarLinkMissingFmt,'$LinkText');
SDV($VarLinkExistsFmt,"<a class='varlink' href='\$LinkUrl'><code class='varlink'>\$LinkText</code></a>");
VarIndexLoad($pagename);
$FmtV['$LinkText'] = str_replace('$', '&#36;', $txt);
$FmtV['$LinkUrl'] = @$VarIndex[$tgt]['url'];
if (@!$VarIndex[$tgt]['url'])
return FmtPageName($VarLinkMissingFmt,$pagename);
return FmtPageName($VarLinkExistsFmt,$pagename);
}
function VarIndexLoad($pagename) {
global $VarPagesFmt,$VarIndex,$WikiWordPattern;
static $loaded;
$VarIndex = (array)@$VarIndex;
if ($loaded) return;
foreach($VarPagesFmt as $vf) {
$v = FmtPageName($vf, $pagename);
if (@$loaded[$v]) continue;
$vlist = array($v);
$t = ReadTrail($pagename,$v);
if ($t)
for($i=0;$i<count($t);$i++)
if (@!$loaded[$t[$i]['pagename']]) $vlist[]=$t[$i]['pagename'];
foreach($vlist as $vname) {
$vpage = ReadPage($vname, READPAGE_CURRENT); @$loaded[$vname]++;
if (!$vpage) continue;
if (!preg_match_all("/\n:\\$([[:upper:]]\\w+):/",@$vpage['text'],$match))
continue;
foreach($match[1] as $n) {
$VarIndex[$n]['pagename'] = $vname;
$VarIndex[$n]['url'] = FmtPageName("{\$PageUrl}#$n",$vname);
}
}
}
}
# VarIndexList() generates a table of all indexed variables.
function VarIndexList($pagename) {
global $VarIndex;
if (!isset($VarIndex)) VarIndexLoad($pagename);
ksort($VarIndex);
$out = "<table><tr><th>Variable</th><th>Documented in</th></tr>\n";
foreach($VarIndex as $v=>$a)
$out .= FmtPageName("<tr><td><a class='varlink'
href='{$a['url']}'><code>&#036;$v</code></a></td><td><a
href='{\$PageUrl}'>{\$Name}</a></td></tr>\n",$a['pagename']);
$out .= "</table>";
return $out;
}

1
wiki/scripts/version.php Executable file
View File

@@ -0,0 +1 @@
<?php $Version="pmwiki-2.2.75"; $VersionNum=2002075;

193
wiki/scripts/wikistyles.php Executable file
View File

@@ -0,0 +1,193 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2015 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
*/
SDV($WikiStylePattern,'%%|%[A-Za-z][-,=:#\\w\\s\'"().]*%');
## %% markup
Markup('%%','style','%','return ApplyStyles($x);');
## %define=...% markup on a line by itself
Markup_e('%define=', '>split',
"/^(?=%define=)((?:$WikiStylePattern)\\s*)+$/",
"PZZ(ApplyStyles(\$m[0]))");
## restore links before applying styles
Markup_e('restorelinks','<%%',"/$KeepToken(\\d+L)$KeepToken/",
'$GLOBALS[\'KPV\'][$m[1]]');
# define PmWiki's standard/default wikistyles
if (IsEnabled($EnableStdWikiStyles,1)) {
## standard colors
foreach(array('black','white','red','yellow','blue','gray',
'silver','maroon','green','navy','purple') as $c)
SDV($WikiStyle[$c]['color'],$c);
## %newwin% style opens links in a new window
SDV($WikiStyle['newwin']['target'],'_blank');
## %comment% style turns markup into a comment via display:none css
SDV($WikiStyle['comment']['display'],'none');
## display, margin, padding, and border css properties
$WikiStyleCSS[] =
'float|clear|display|(margin|padding|border)(-(left|right|top|bottom))?';
$WikiStyleCSS[] = 'white-space';
$WikiStyleCSS[] = '((min|max)-)?(width|height)';
## list-styles
$WikiStyleCSS[] = 'list-style';
foreach(array('decimal'=>'decimal', 'roman'=>'lower-roman',
'ROMAN'=>'upper-roman', 'alpha'=>'lower-alpha', 'ALPHA'=>'upper-alpha')
as $k=>$v)
SDV($WikiStyle[$k],array('apply'=>'list','list-style'=>$v));
## apply ranges
SDVA($WikiStyleApply,array(
'item' => 'li|dt',
'list' => 'ul|ol|dl',
'div' => 'div',
'article' => 'article',
'section' => 'section',
'nav' => 'nav',
'aside' => 'aside',
'header' => 'header',
'footer' => 'footer',
'address' => 'address',
'pre' => 'pre',
'img' => 'img',
'block' => 'p(?!\\s+class=)|div|ul|ol|dl|li|dt|pre|h[1-6]|article|section|nav|aside|address|header|footer',
'p' => 'p(?!\\s+class=)'));
foreach(array('item', 'list', 'block', 'p', 'div') as $c)
SDV($WikiStyle[$c],array('apply'=>$c));
## block justifications
foreach(array('left','right','center','justify') as $c)
SDV($WikiStyle[$c],array('apply'=>'block','text-align'=>$c));
## frames, floating frames, and floats
SDV($HTMLStylesFmt['wikistyles'], "
.frame
{ border:1px solid #cccccc; padding:4px; background-color:#f9f9f9; }
.lfloat { float:left; margin-right:0.5em; }
.rfloat { float:right; margin-left:0.5em; }\n");
SDV($WikiStyle['thumb'], array('width' => '100px'));
SDV($WikiStyle['frame'], array('class' => 'frame'));
SDV($WikiStyle['lframe'], array('class' => 'frame lfloat'));
SDV($WikiStyle['rframe'], array('class' => 'frame rfloat'));
SDV($WikiStyle['cframe'], array(
'class' => 'frame', 'margin-left' => 'auto', 'margin-right' => 'auto',
'width' => '200px', 'apply' => 'block', 'text-align' => 'center'));
## preformatted text sections
SDV($WikiStyle['pre'], array('apply' => 'block', 'white-space' => 'pre'));
SDV($WikiStyle['sidehead'], array('apply' => 'block', 'class' => 'sidehead'));
}
SDVA($WikiStyleAttr,array(
'vspace' => 'img',
'hspace' => 'img',
'align' => 'img',
'value' => 'li',
'target' => 'a',
'accesskey' => 'a',
'rel' => 'a'));
SDVA($WikiStyleRepl,array(
'/^%(.*)%$/' => '$1',
'/\\bbgcolor([:=])/' => 'background-color$1',
'/\\b(\d+)pct\\b/' => '$1%',
));
$WikiStyleCSS[] = 'color|background-color';
$WikiStyleCSS[] = 'text-align|text-decoration';
$WikiStyleCSS[] = 'font-size|font-family|font-weight|font-style';
SDV($imgTag, '(?:img|object|embed)'); SDV($aTag, 'a'); SDV($spanTag, 'span');
function ApplyStyles($x) {
global $UrlExcludeChars, $WikiStylePattern, $WikiStyleRepl, $WikiStyle,
$WikiStyleAttr, $WikiStyleCSS, $WikiStyleApply, $BlockPattern,
$WikiStyleTag, $imgTag, $aTag, $spanTag, $WikiStyleAttrPrefix;
$wt = @$WikiStyleTag; $ns = $WikiStyleAttrPrefix; $ws = '';
$x = PPRE("/\\b(href|src)=(['\"]?)[^$UrlExcludeChars]+\\2/",
"Keep(\$m[0])", $x);
$x = PPRE("/\\bhttps?:[^$UrlExcludeChars]+/", "Keep(\$m[0])", $x);
$parts = preg_split("/($WikiStylePattern)/",$x,-1,PREG_SPLIT_DELIM_CAPTURE);
$parts[] = NULL;
$out = '';
$style = array();
$wikicsspat = '/^('.implode('|',(array)$WikiStyleCSS).')$/';
while ($parts) {
$p = array_shift($parts);
if (preg_match("/^$WikiStylePattern\$/",$p)) {
$WikiStyle['curr']=$style; $style=array();
foreach((array)$WikiStyleRepl as $pat=>$rep)
$p=preg_replace($pat,$rep,$p);
preg_match_all(
'/\\b([a-zA-Z][-\\w]*)([:=]([-#,\\w.()%]+|([\'"]).*?\\4))?/',
$p, $match, PREG_SET_ORDER);
while ($match) {
$m = array_shift($match);
if (@$m[2]) $style[$m[1]]=preg_replace('/^([\'"])(.*?)\\1$/','$2',$m[3]);
else if (!isset($WikiStyle[$m[1]])) @$style['class'] .= ' ' . $m[1];
else {
$c = @$style['class'];
$style=array_merge($style,(array)$WikiStyle[$m[1]]);
if ($c && !preg_match("/(^| )$c( |$)/", $style['class']) )
$style['class'] = $c . ' ' . $style['class'];
}
}
if (@$style['define']) {
$d = $style['define']; unset($style['define']);
$WikiStyle[$d] = $style;
}
if (@$WikiStyleApply[$style['apply']]) {
$apply[$style['apply']] =
array_merge((array)@$apply[$style['apply']],$style);
$style=array();
}
continue;
}
if (is_null($p))
{ $alist=@$apply; unset($alist['']); $p=$out; $out=''; }
elseif ($p=='') continue;
else { $alist=array(''=>$style); }
foreach((array)$alist as $a=>$s) {
$spanattr = ''; $stylev = array(); $id = '';
foreach((array)$s as $k=>$v) {
$v = trim($v);
if ($wt) $ws = str_replace('$1', "$ns$k='$v'", $wt);
if ($k == 'class' && $v) $spanattr = "{$ns}class='$v'";
elseif ($k=='id') $id = preg_replace('/[^-A-Za-z0-9:_.]+/', '_', $v);
elseif (($k=='width' || $k=='height') && !@$WikiStyleApply[$a]
&& preg_match("/\\s*<$imgTag\\b/", $p))
$p = preg_replace("/<($imgTag)\\b(?![^>]*\\s$k=)/",
"$ws<$1 $ns$k='$v'", $p);
elseif (@$WikiStyleAttr[$k])
$p = preg_replace(
"/<({$WikiStyleAttr[$k]}(?![^>]*\\s(?:$ns)?$k=))([^>]*)>/s",
"$ws<$1 $ns$k='$v' $2>", $p);
elseif (preg_match($wikicsspat,$k)) $stylev[]="$k: $v;";
}
if ($stylev) $spanattr .= " {$ns}style='".implode(' ',$stylev)."'";
if ($id) $spanattr .= " {$ns}id='$id'";
if ($spanattr) {
if ($wt) $ws = str_replace('$1', $spanattr, $wt);
if (!@$WikiStyleApply[$a]) {
$p = preg_replace("!^(.*?)($|</?($BlockPattern))!s",
"$ws<$spanTag $spanattr>$1</$spanTag>$2", $p, 1);
}
elseif (!preg_match('/^(\\s*<[^>]+>)*$/s',$p) ||
preg_match("/<$imgTag\\b/", $p)) {
$p = preg_replace("/<({$WikiStyleApply[$a]})\\b/",
"$ws<$1 $spanattr", $p);
}
}
if (@$s['color']) {
$colorattr = "{$ns}style='color: {$s['color']}'";
if ($wt) $ws = str_replace('$1', $colorattr, $wt);
$p = preg_replace("/<$aTag\\b/", "$ws<$aTag $colorattr", $p);
}
}
$out .= $p;
}
return $out;
}

69
wiki/scripts/wikiwords.php Executable file
View File

@@ -0,0 +1,69 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2001-2013 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script adds WikiWord (CamelCase) processing to PmWiki.
Originally WikiWords were part of the default configuration,
but their usage has died out over time and so it's now optional.
To enable WikiWord links, simply add the following to
a local customization file:
$EnableWikiWords = 1;
To have PmWiki recognize and process WikiWords but not link
them (i.e., the default behavior in PmWiki 2.1), also add
$LinkWikiWords = 0;
If you want only the first occurrence of a WikiWord to be converted
to a link, set $WikiWordCountMax=1.
$WikiWordCountMax = 1; # converts only first WikiWord
$WikiWordCountMax = 0; # another way to disable WikiWord links
The $WikiWordCount array can be used to control the number of times
a WikiWord is converted to a link. This is useful for disabling
or limiting specific WikiWords.
$WikiWordCount['PhD'] = 0; # disables 'PhD'
$WikiWordCount['PmWiki'] = 1; # convert only first 'PmWiki'
$WikiWordCount['WikiWord'] = -1; # ignore $SpaceWikiWord setting
By default, PmWiki is configured such that only the first occurrence
of 'PmWiki' in a page is treated as a WikiWord. If you want to
restore 'PmWiki' to be treated like other WikiWords, uncomment the
line below.
unset($WikiWordCount['PmWiki']);
If you want to disable WikiWords matching a pattern, you can use
something like the following. Note that the first argument has to
be different for each call to Markup(). The example below disables
WikiWord links like COM1, COM2, COM1234, etc.
Markup('COM\d+', '<wikilink', '/\\bCOM\\d+/', "Keep('$0')");
*/
SDV($LinkWikiWords, 1);
## bare wikilinks
Markup_e('wikilink', '>urllink',
"/\\b(?<![#&])($GroupPattern([\\/.]))?($WikiWordPattern)/",
"Keep('<span class=\\'wikiword\\'>'.WikiLink(\$pagename,\$m[0]).'</span>',
'L')");
function WikiLink($pagename, $word) {
global $LinkWikiWords, $WikiWordCount, $SpaceWikiWords, $AsSpacedFunction,
$MarkupFrame, $WikiWordCountMax;
if (!$LinkWikiWords || ($WikiWordCount[$word] < 0)) return $word;
$text = ($SpaceWikiWords) ? $AsSpacedFunction($word) : $word;
$text = preg_replace('!.*/!', '', $text);
if (!isset($MarkupFrame[0]['wwcount'][$word]))
$MarkupFrame[0]['wwcount'][$word] = $WikiWordCountMax;
if ($MarkupFrame[0]['wwcount'][$word]-- < 1) return $text;
return MakeLink($pagename, $word, $text);
}

View File

@@ -0,0 +1,13 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2005-2011 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
*/
global $HTTPHeaders, $Charset, $DefaultPageCharset;
$HTTPHeaders[] = "Content-type: text/html; charset=iso-8859-13;";
$Charset = "ISO-8859-13";
SDVA($DefaultPageCharset, array('ISO-8859-1'=>$Charset));

View File

@@ -0,0 +1,65 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2011 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This file is used to enable the iso-8859-2 character set in PmWiki.
The first part converts the charset to iso-8859-2 and removes
conflicts for newline and keep tokens; the second part
handles the conversion of pagenames from utf-8 (sent by browsers)
into iso-8859-2 if needed.
*/
global $HTTPHeaders, $pagename, $KeepToken, $Charset, $DefaultPageCharset;
$HTTPHeaders[] = "Content-Type: text/html; charset=iso-8859-2;";
$Charset = "ISO-8859-2";
SDVA($DefaultPageCharset, array('ISO-8859-1'=>$Charset));
$KeepToken = "\263\263\263";
$pagename = $_REQUEST['n'];
if (!$pagename) $pagename = @$_GET['pagename'];
if ($pagename=='' && $EnablePathInfo)
$pagename = @substr($_SERVER['PATH_INFO'],1);
if (!$pagename &&
preg_match('!^'.preg_quote($_SERVER['SCRIPT_NAME'],'!').'/?([^?]*)!',
$_SERVER['REQUEST_URI'],$match))
$pagename = urldecode($match[1]);
$pagename = preg_replace('!/+$!','',$pagename);
if (!preg_match('/[\\x80-\\x9f]/', $pagename)) return;
if (function_exists('iconv'))
$pagename = iconv('UTF-8','ISO-8859-2',$pagename);
else {
$conv = array(
' '=>'<27>', 'Ą'=>'<27>', '˘'=>'<27>', 'Ł'=>'<27>',
'¤'=>'<27>', 'Ľ'=>'<27>', 'Ś'=>'<27>', '§'=>'<27>',
'¨'=>'<27>', 'Š'=>'<27>', 'Ş'=>'<27>', 'Ť'=>'<27>',
'Ź'=>'<27>', '­'=>'<27>', 'Ž'=>'<27>', 'Ż'=>'<27>',
'°'=>'<27>', 'ą'=>'<27>', '˛'=>'<27>', 'ł'=>'<27>',
'´'=>'<27>', 'ľ'=>'<27>', 'ś'=>'<27>', 'ˇ'=>'<27>',
'¸'=>'<27>', 'š'=>'<27>', 'ş'=>'<27>', 'ť'=>'<27>',
'ź'=>'<27>', '˝'=>'<27>', 'ž'=>'<27>', 'ż'=>'<27>',
'Ŕ'=>'<27>', 'Á'=>'<27>', 'Â'=>'<27>', 'Ă'=>'<27>',
'Ä'=>'<27>', 'Ĺ'=>'<27>', 'Ć'=>'<27>', 'Ç'=>'<27>',
'Č'=>'<27>', 'É'=>'<27>', 'Ę'=>'<27>', 'Ë'=>'<27>',
'Ě'=>'<27>', 'Í'=>'<27>', 'Î'=>'<27>', 'Ď'=>'<27>',
'Đ'=>'<27>', 'Ń'=>'<27>', 'Ň'=>'<27>', 'Ó'=>'<27>',
'Ô'=>'<27>', 'Ő'=>'<27>', 'Ö'=>'<27>', '×'=>'<27>',
'Ř'=>'<27>', 'Ů'=>'<27>', 'Ú'=>'<27>', 'Ű'=>'<27>',
'Ü'=>'<27>', 'Ý'=>'<27>', 'Ţ'=>'<27>', 'ß'=>'<27>',
'ŕ'=>'<27>', 'á'=>'<27>', 'â'=>'<27>', 'ă'=>'<27>',
'ä'=>'<27>', 'ĺ'=>'<27>', 'ć'=>'<27>', 'ç'=>'<27>',
'č'=>'<27>', 'é'=>'<27>', 'ę'=>'<27>', 'ë'=>'<27>',
'ě'=>'<27>', 'í'=>'<27>', 'î'=>'<27>', 'ď'=>'<27>',
'đ'=>'<27>', 'ń'=>'<27>', 'ň'=>'<27>', 'ó'=>'<27>',
'ô'=>'<27>', 'ő'=>'<27>', 'ö'=>'<27>', '÷'=>'<27>',
'ř'=>'<27>', 'ů'=>'<27>', 'ú'=>'<27>', 'ű'=>'<27>',
'ü'=>'<27>', 'ý'=>'<27>', 'ţ'=>'<27>', '˙'=>'<27>',
);
$pagename = str_replace(array_keys($conv),array_values($conv),$pagename);
}

View File

@@ -0,0 +1,14 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2005-2011 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
*/
global $HTTPHeaders, $Charset, $DefaultPageCharset;
$HTTPHeaders[] = "Content-type: text/html; charset=iso-8859-9;";
$Charset = "ISO-8859-9";
SDVA($DefaultPageCharset, array('ISO-8859-1'=>$Charset));

634
wiki/scripts/xlpage-utf-8.php Executable file
View File

@@ -0,0 +1,634 @@
<?php if (!defined('PmWiki')) exit();
/* Copyright 2004-2013 Patrick R. Michaud (pmichaud@pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script configures PmWiki to use utf-8 in page content and
pagenames. There are some unfortunate side effects about PHP's
utf-8 implementation, however. First, since PHP doesn't have a
way to do pattern matching on upper/lowercase UTF-8 characters,
WikiWords are limited to the ASCII-7 set, and all links to page
names with UTF-8 characters have to be in double brackets.
Second, we have to assume that all non-ASCII characters are valid
in pagenames, since there's no way to determine which UTF-8
characters are "letters" and which are punctuation.
*/
global $HTTPHeaders, $KeepToken, $pagename,
$GroupPattern, $NamePattern, $WikiWordPattern, $SuffixPattern,
$PageNameChars, $MakePageNamePatterns, $CaseConversions, $StringFolding,
$Charset, $HTMLHeaderFmt, $StrFoldFunction, $AsSpacedFunction;
$Charset = 'UTF-8';
$HTTPHeaders['utf-8'] = 'Content-type: text/html; charset=UTF-8';
$HTMLHeaderFmt['utf-8'] =
"<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />";
$pagename = @$_REQUEST['n'];
if (!$pagename) $pagename = @$_REQUEST['pagename'];
if (!$pagename &&
preg_match('!^'.preg_quote($_SERVER['SCRIPT_NAME'],'!').'/?([^?]*)!',
$_SERVER['REQUEST_URI'],$match))
$pagename = urldecode($match[1]);
$pagename = preg_replace('!/+$!','',$pagename);
$FmtPV['$RequestedPage'] = "'".PHSC($pagename, ENT_QUOTES)."'";
$GroupPattern = '[\\w\\x80-\\xfe]+(?:-[\\w\\x80-\\xfe]+)*';
$NamePattern = '[\\w\\x80-\\xfe]+(?:-[\\w\\x80-\\xfe]+)*';
$WikiWordPattern =
'[A-Z][A-Za-z0-9]*(?:[A-Z][a-z0-9]|[a-z0-9][A-Z])[A-Za-z0-9]*';
$SuffixPattern = '(?:-?[A-Za-z0-9\\x80-\\xd6]+)*';
SDV($PageNameChars, '-[:alnum:]\\x80-\\xfe');
SDV($MakePageNamePatterns, array(
'/[?#].*$/' => '', # strip everything after ? or #
"/'/" => '', # strip single-quotes
"/[^$PageNameChars]+/" => ' ', # convert everything else to space
'/(?<=^| )([a-z])/' => PCCF("return strtoupper(\$m[1]);"),
'/(?<=^| )([\\xc0-\\xdf].)/' => PCCF("return utf8toupper(\$m[1]);"),
'/ /' => ''));
SDV($StrFoldFunction, 'utf8fold');
$AsSpacedFunction = 'AsSpacedUTF8';
function utf8toupper($x) {
global $CaseConversions;
if (strlen($x) <= 2 && @$CaseConversions[$x])
return $CaseConversions[$x];
static $lower, $upper;
if (!@$lower) {
$lower = array_keys($CaseConversions);
$upper = array_values($CaseConversions);
}
return str_replace($lower, $upper, $x);
}
function utf8fold($x) {
global $StringFolding;
static $source, $target;
if (!@$source) {
$source = array_keys($StringFolding);
$target = array_values($StringFolding);
}
return str_replace($source, $target, $x);
}
function AsSpacedUTF8($text) {
global $CaseConversions;
static $lower, $upper;
if (!@$CaseConversions) return AsSpaced($text);
if (!@$lower) {
$lower = implode('|', array_keys($CaseConversions));
$upper = implode('|', array_values($CaseConversions));
}
$text = preg_replace("/($lower|\\d)($upper)/", '$1 $2', $text);
$text = preg_replace('/([^-\\d])(\\d[-\\d]*( |$))/', '$1 $2', $text);
return preg_replace("/($upper)(($upper)($lower|\\d))/", '$1 $2', $text);
}
SDVA($MarkupExpr, array(
'substr' => 'call_user_func_array("utf8string", $args)',
'strlen' => 'utf8string($args[0], "strlen")',
'ucfirst' => 'utf8string($args[0], "ucfirst")',
'ucwords' => 'utf8string($args[0], "ucwords")',
'tolower' => 'utf8string($args[0], "tolower")',
'toupper' => 'utf8string($args[0], "toupper")',
));
function utf8string($str, $start=false, $len=false) { # strlen+substr++ combo for UTF-8
global $CaseConversions;
static $lower;
if (!@$lower) $lower = implode('|', array_keys($CaseConversions));
$ascii = preg_match('/[\\x80-\\xFF]/', $str)? 0:1;
switch ((string)$start) {
case 'ucfirst': return $ascii ? ucfirst($str) :
PPRE("/^($lower)/", '$GLOBALS["CaseConversions"][$m[1]]', $str);
case 'ucwords': return $ascii ? ucwords($str) :
PPRE("/(^|\\s+)($lower)/", '$m[1].$GLOBALS["CaseConversions"][$m[2]]', $str);
case 'tolower': return $ascii ? strtolower($str) : utf8fold($str);
case 'toupper': return $ascii ? strtoupper($str) : utf8toupper($str);
}
if ($ascii) {
if ($start==='strlen') return strlen($str);
if ($len===false) return substr($str, $start);
return substr($str, $start, $len);
}
$letters = preg_split("/([\\x00-\\x7f]|[\\xc2-\\xdf].|[\\xe0-\\xef]..|[\\xf0-\\xf4]...)/",
$str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
if ($start==='strlen') return count($letters);
if ($len===false) return implode('', array_slice($letters, $start));
return implode('', array_slice($letters, $start, $len));
}
## Conversion tables.
## $CaseConversion maps lowercase utf8 sequences to
## their uppercase equivalents. The table was derived from [1].
## $StringFolding normalizes strings so that "equivalent"
## forms will match using a binary comparison (derived from [2]).
## [1] http://unicode.org/Public/UNIDATA/UnicodeData.txt
## [2] http://unicode.org/Public/UNIDATA/CaseFolding.txt
SDV($CaseConversions, array(
## U+0060
"a" => "A", "b" => "B", "c" => "C", "d" => "D", "e" => "E", "f" => "F",
"g" => "G", "h" => "H", "i" => "I", "j" => "J", "k" => "K", "l" => "L",
"m" => "M", "n" => "N", "o" => "O", "p" => "P", "q" => "Q", "r" => "R",
"s" => "S", "t" => "T", "u" => "U", "v" => "V", "w" => "W", "x" => "X",
"y" => "Y", "z" => "Z",
## U+00b5
"\xc2\xb5" => "\xce\x9c",
## U+00E0 to U+00FF
"\xc3\xa0" => "\xc3\x80", "\xc3\xa1" => "\xc3\x81",
"\xc3\xa2" => "\xc3\x82", "\xc3\xa3" => "\xc3\x83",
"\xc3\xa4" => "\xc3\x84", "\xc3\xa5" => "\xc3\x85",
"\xc3\xa6" => "\xc3\x86", "\xc3\xa7" => "\xc3\x87",
"\xc3\xa8" => "\xc3\x88", "\xc3\xa9" => "\xc3\x89",
"\xc3\xaa" => "\xc3\x8a", "\xc3\xab" => "\xc3\x8b",
"\xc3\xac" => "\xc3\x8c", "\xc3\xad" => "\xc3\x8d",
"\xc3\xae" => "\xc3\x8e", "\xc3\xaf" => "\xc3\x8f",
"\xc3\xb0" => "\xc3\x90", "\xc3\xb1" => "\xc3\x91",
"\xc3\xb2" => "\xc3\x92", "\xc3\xb3" => "\xc3\x93",
"\xc3\xb4" => "\xc3\x94", "\xc3\xb5" => "\xc3\x95",
"\xc3\xb6" => "\xc3\x96", "\xc3\xb8" => "\xc3\x98",
"\xc3\xb9" => "\xc3\x99", "\xc3\xba" => "\xc3\x9a",
"\xc3\xbb" => "\xc3\x9b", "\xc3\xbc" => "\xc3\x9c",
"\xc3\xbd" => "\xc3\x9d", "\xc3\xbe" => "\xc3\x9e",
"\xc3\xbf" => "\xc5\xb8",
## U+0100
"\xc4\x81" => "\xc4\x80", "\xc4\x83" => "\xc4\x82",
"\xc4\x85" => "\xc4\x84", "\xc4\x87" => "\xc4\x86",
"\xc4\x89" => "\xc4\x88", "\xc4\x8b" => "\xc4\x8a",
"\xc4\x8d" => "\xc4\x8c", "\xc4\x8f" => "\xc4\x8e",
"\xc4\x91" => "\xc4\x90", "\xc4\x93" => "\xc4\x92",
"\xc4\x95" => "\xc4\x94", "\xc4\x97" => "\xc4\x96",
"\xc4\x99" => "\xc4\x98", "\xc4\x9b" => "\xc4\x9a",
"\xc4\x9d" => "\xc4\x9c", "\xc4\x9f" => "\xc4\x9e",
"\xc4\xa1" => "\xc4\xa0", "\xc4\xa3" => "\xc4\xa2",
"\xc4\xa5" => "\xc4\xa4", "\xc4\xa7" => "\xc4\xa6",
"\xc4\xa9" => "\xc4\xa8", "\xc4\xab" => "\xc4\xaa",
"\xc4\xad" => "\xc4\xac", "\xc4\xaf" => "\xc4\xae",
"\xc4\xb1" => "I", "\xc4\xb3" => "\xc4\xb2",
"\xc4\xb5" => "\xc4\xb4", "\xc4\xb7" => "\xc4\xb6",
"\xc4\xba" => "\xc4\xb9", "\xc4\xbc" => "\xc4\xbb",
"\xc4\xbe" => "\xc4\xbd",
## U+0140
"\xc5\x80" => "\xc4\xbf", "\xc5\x82" => "\xc5\x81",
"\xc5\x84" => "\xc5\x83", "\xc5\x86" => "\xc5\x85",
"\xc5\x88" => "\xc5\x87", "\xc5\x8b" => "\xc5\x8a",
"\xc5\x8d" => "\xc5\x8c", "\xc5\x8f" => "\xc5\x8e",
"\xc5\x91" => "\xc5\x90", "\xc5\x93" => "\xc5\x92",
"\xc5\x95" => "\xc5\x94", "\xc5\x97" => "\xc5\x96",
"\xc5\x99" => "\xc5\x98", "\xc5\x9b" => "\xc5\x9a",
"\xc5\x9d" => "\xc5\x9c", "\xc5\x9f" => "\xc5\x9e",
"\xc5\xa1" => "\xc5\xa0", "\xc5\xa3" => "\xc5\xa2",
"\xc5\xa5" => "\xc5\xa4", "\xc5\xa7" => "\xc5\xa6",
"\xc5\xa9" => "\xc5\xa8", "\xc5\xab" => "\xc5\xaa",
"\xc5\xad" => "\xc5\xac", "\xc5\xaf" => "\xc5\xae",
"\xc5\xb1" => "\xc5\xb0", "\xc5\xb3" => "\xc5\xb2",
"\xc5\xb5" => "\xc5\xb4", "\xc5\xb7" => "\xc5\xb6",
"\xc5\xba" => "\xc5\xb9", "\xc5\xbc" => "\xc5\xbb",
"\xc5\xbe" => "\xc5\xbd", "\xc5\xbf" => "S",
## U+0180
"\xc6\x80" => "\xc9\x83", "\xc6\x83" => "\xc6\x82",
"\xc6\x85" => "\xc6\x84", "\xc6\x88" => "\xc6\x87",
"\xc6\x8c" => "\xc6\x8b", "\xc6\x92" => "\xc6\x91",
"\xc6\x95" => "\xc7\xb6", "\xc6\x99" => "\xc6\x98",
"\xc6\x9a" => "\xc8\xbd", "\xc6\x9e" => "\xc8\xa0",
"\xc6\xa1" => "\xc6\xa0", "\xc6\xa3" => "\xc6\xa2",
"\xc6\xa5" => "\xc6\xa4", "\xc6\xa8" => "\xc6\xa7",
"\xc6\xad" => "\xc6\xac", "\xc6\xb0" => "\xc6\xaf",
"\xc6\xb4" => "\xc6\xb3", "\xc6\xb6" => "\xc6\xb5",
"\xc6\xb9" => "\xc6\xb8", "\xc6\xbd" => "\xc6\xbc",
"\xc6\xbf" => "\xc7\xb7",
## U+01c0
"\xc7\x85" => "\xc7\x84", "\xc7\x86" => "\xc7\x84",
"\xc7\x88" => "\xc7\x87", "\xc7\x89" => "\xc7\x87",
"\xc7\x8b" => "\xc7\x8a", "\xc7\x8c" => "\xc7\x8a",
"\xc7\x8e" => "\xc7\x8d", "\xc7\x90" => "\xc7\x8f",
"\xc7\x92" => "\xc7\x91", "\xc7\x94" => "\xc7\x93",
"\xc7\x96" => "\xc7\x95", "\xc7\x98" => "\xc7\x97",
"\xc7\x9a" => "\xc7\x99", "\xc7\x9c" => "\xc7\x9b",
"\xc7\x9d" => "\xc6\x8e", "\xc7\x9f" => "\xc7\x9e",
"\xc7\xa1" => "\xc7\xa0", "\xc7\xa3" => "\xc7\xa2",
"\xc7\xa5" => "\xc7\xa4", "\xc7\xa7" => "\xc7\xa6",
"\xc7\xa9" => "\xc7\xa8", "\xc7\xab" => "\xc7\xaa",
"\xc7\xad" => "\xc7\xac", "\xc7\xaf" => "\xc7\xae",
"\xc7\xb2" => "\xc7\xb1", "\xc7\xb3" => "\xc7\xb1",
"\xc7\xb5" => "\xc7\xb4", "\xc7\xb9" => "\xc7\xb8",
"\xc7\xbb" => "\xc7\xba", "\xc7\xbd" => "\xc7\xbc",
"\xc7\xbf" => "\xc7\xbe",
## U+0200
"\xc8\x81" => "\xc8\x80", "\xc8\x83" => "\xc8\x82",
"\xc8\x85" => "\xc8\x84", "\xc8\x87" => "\xc8\x86",
"\xc8\x89" => "\xc8\x88", "\xc8\x8b" => "\xc8\x8a",
"\xc8\x8d" => "\xc8\x8c", "\xc8\x8f" => "\xc8\x8e",
"\xc8\x91" => "\xc8\x90", "\xc8\x93" => "\xc8\x92",
"\xc8\x95" => "\xc8\x94", "\xc8\x97" => "\xc8\x96",
"\xc8\x99" => "\xc8\x98", "\xc8\x9b" => "\xc8\x9a",
"\xc8\x9d" => "\xc8\x9c", "\xc8\x9f" => "\xc8\x9e",
"\xc8\xa3" => "\xc8\xa2", "\xc8\xa5" => "\xc8\xa4",
"\xc8\xa7" => "\xc8\xa6", "\xc8\xa9" => "\xc8\xa8",
"\xc8\xab" => "\xc8\xaa", "\xc8\xad" => "\xc8\xac",
"\xc8\xaf" => "\xc8\xae", "\xc8\xb1" => "\xc8\xb0",
"\xc8\xb3" => "\xc8\xb2", "\xc8\xbc" => "\xc8\xbb",
## U+0240
"\xc9\x82" => "\xc9\x81", "\xc9\x87" => "\xc9\x86",
"\xc9\x89" => "\xc9\x88", "\xc9\x8b" => "\xc9\x8a",
"\xc9\x8d" => "\xc9\x8c", "\xc9\x8f" => "\xc9\x8e",
"\xc9\x93" => "\xc6\x81", "\xc9\x94" => "\xc6\x86",
"\xc9\x96" => "\xc6\x89", "\xc9\x97" => "\xc6\x8a",
"\xc9\x99" => "\xc6\x8f", "\xc9\x9b" => "\xc6\x90",
"\xc9\xa0" => "\xc6\x93", "\xc9\xa3" => "\xc6\x94",
"\xc9\xa8" => "\xc6\x97", "\xc9\xa9" => "\xc6\x96",
"\xc9\xab" => "\xe2\xb1\xa2", "\xc9\xaf" => "\xc6\x9c",
"\xc9\xb2" => "\xc6\x9d", "\xc9\xb5" => "\xc6\x9f",
"\xc9\xbd" => "\xe2\xb1\xa4",
## U+0280
"\xca\x80" => "\xc6\xa6", "\xca\x83" => "\xc6\xa9",
"\xca\x88" => "\xc6\xae", "\xca\x89" => "\xc9\x84",
"\xca\x8a" => "\xc6\xb1", "\xca\x8b" => "\xc6\xb2",
"\xca\x8c" => "\xc9\x85", "\xca\x92" => "\xc6\xb7",
## U+0340
"\xcd\x85" => "\xce\x99", "\xcd\xbb" => "\xcf\xbd",
"\xcd\xbc" => "\xcf\xbe", "\xcd\xbd" => "\xcf\xbf",
## U+0380
"\xce\xac" => "\xce\x86", "\xce\xad" => "\xce\x88",
"\xce\xae" => "\xce\x89", "\xce\xaf" => "\xce\x8a",
"\xce\xb1" => "\xce\x91", "\xce\xb2" => "\xce\x92",
"\xce\xb3" => "\xce\x93", "\xce\xb4" => "\xce\x94",
"\xce\xb5" => "\xce\x95", "\xce\xb6" => "\xce\x96",
"\xce\xb7" => "\xce\x97", "\xce\xb8" => "\xce\x98",
"\xce\xb9" => "\xce\x99", "\xce\xba" => "\xce\x9a",
"\xce\xbb" => "\xce\x9b", "\xce\xbc" => "\xce\x9c",
"\xce\xbd" => "\xce\x9d", "\xce\xbe" => "\xce\x9e",
"\xce\xbf" => "\xce\x9f",
## U+03c0
"\xcf\x80" => "\xce\xa0", "\xcf\x81" => "\xce\xa1",
"\xcf\x82" => "\xce\xa3", "\xcf\x83" => "\xce\xa3",
"\xcf\x84" => "\xce\xa4", "\xcf\x85" => "\xce\xa5",
"\xcf\x86" => "\xce\xa6", "\xcf\x87" => "\xce\xa7",
"\xcf\x88" => "\xce\xa8", "\xcf\x89" => "\xce\xa9",
"\xcf\x8a" => "\xce\xaa", "\xcf\x8b" => "\xce\xab",
"\xcf\x8c" => "\xce\x8c", "\xcf\x8d" => "\xce\x8e",
"\xcf\x8e" => "\xce\x8f", "\xcf\x90" => "\xce\x92",
"\xcf\x91" => "\xce\x98", "\xcf\x95" => "\xce\xa6",
"\xcf\x96" => "\xce\xa0", "\xcf\x99" => "\xcf\x98",
"\xcf\x9b" => "\xcf\x9a", "\xcf\x9d" => "\xcf\x9c",
"\xcf\x9f" => "\xcf\x9e", "\xcf\xa1" => "\xcf\xa0",
"\xcf\xa3" => "\xcf\xa2", "\xcf\xa5" => "\xcf\xa4",
"\xcf\xa7" => "\xcf\xa6", "\xcf\xa9" => "\xcf\xa8",
"\xcf\xab" => "\xcf\xaa", "\xcf\xad" => "\xcf\xac",
"\xcf\xaf" => "\xcf\xae", "\xcf\xb0" => "\xce\x9a",
"\xcf\xb1" => "\xce\xa1", "\xcf\xb2" => "\xcf\xb9",
"\xcf\xb5" => "\xce\x95", "\xcf\xb8" => "\xcf\xb7",
"\xcf\xbb" => "\xcf\xba",
## U+0400
"\xd0\xb0" => "\xd0\x90", "\xd0\xb1" => "\xd0\x91",
"\xd0\xb2" => "\xd0\x92", "\xd0\xb3" => "\xd0\x93",
"\xd0\xb4" => "\xd0\x94", "\xd0\xb5" => "\xd0\x95",
"\xd0\xb6" => "\xd0\x96", "\xd0\xb7" => "\xd0\x97",
"\xd0\xb8" => "\xd0\x98", "\xd0\xb9" => "\xd0\x99",
"\xd0\xba" => "\xd0\x9a", "\xd0\xbb" => "\xd0\x9b",
"\xd0\xbc" => "\xd0\x9c", "\xd0\xbd" => "\xd0\x9d",
"\xd0\xbe" => "\xd0\x9e", "\xd0\xbf" => "\xd0\x9f",
## U+0440
"\xd1\x80" => "\xd0\xa0", "\xd1\x81" => "\xd0\xa1",
"\xd1\x82" => "\xd0\xa2", "\xd1\x83" => "\xd0\xa3",
"\xd1\x84" => "\xd0\xa4", "\xd1\x85" => "\xd0\xa5",
"\xd1\x86" => "\xd0\xa6", "\xd1\x87" => "\xd0\xa7",
"\xd1\x88" => "\xd0\xa8", "\xd1\x89" => "\xd0\xa9",
"\xd1\x8a" => "\xd0\xaa", "\xd1\x8b" => "\xd0\xab",
"\xd1\x8c" => "\xd0\xac", "\xd1\x8d" => "\xd0\xad",
"\xd1\x8e" => "\xd0\xae", "\xd1\x8f" => "\xd0\xaf",
"\xd1\x90" => "\xd0\x80", "\xd1\x91" => "\xd0\x81",
"\xd1\x92" => "\xd0\x82", "\xd1\x93" => "\xd0\x83",
"\xd1\x94" => "\xd0\x84", "\xd1\x95" => "\xd0\x85",
"\xd1\x96" => "\xd0\x86", "\xd1\x97" => "\xd0\x87",
"\xd1\x98" => "\xd0\x88", "\xd1\x99" => "\xd0\x89",
"\xd1\x9a" => "\xd0\x8a", "\xd1\x9b" => "\xd0\x8b",
"\xd1\x9c" => "\xd0\x8c", "\xd1\x9d" => "\xd0\x8d",
"\xd1\x9e" => "\xd0\x8e", "\xd1\x9f" => "\xd0\x8f",
"\xd1\xa1" => "\xd1\xa0", "\xd1\xa3" => "\xd1\xa2",
"\xd1\xa5" => "\xd1\xa4", "\xd1\xa7" => "\xd1\xa6",
"\xd1\xa9" => "\xd1\xa8", "\xd1\xab" => "\xd1\xaa",
"\xd1\xad" => "\xd1\xac", "\xd1\xaf" => "\xd1\xae",
"\xd1\xb1" => "\xd1\xb0", "\xd1\xb3" => "\xd1\xb2",
"\xd1\xb5" => "\xd1\xb4", "\xd1\xb7" => "\xd1\xb6",
"\xd1\xb9" => "\xd1\xb8", "\xd1\xbb" => "\xd1\xba",
"\xd1\xbd" => "\xd1\xbc", "\xd1\xbf" => "\xd1\xbe",
## U+0480
"\xd2\x81" => "\xd2\x80", "\xd2\x8b" => "\xd2\x8a",
"\xd2\x8d" => "\xd2\x8c", "\xd2\x8f" => "\xd2\x8e",
"\xd2\x91" => "\xd2\x90", "\xd2\x93" => "\xd2\x92",
"\xd2\x95" => "\xd2\x94", "\xd2\x97" => "\xd2\x96",
"\xd2\x99" => "\xd2\x98", "\xd2\x9b" => "\xd2\x9a",
"\xd2\x9d" => "\xd2\x9c", "\xd2\x9f" => "\xd2\x9e",
"\xd2\xa1" => "\xd2\xa0", "\xd2\xa3" => "\xd2\xa2",
"\xd2\xa5" => "\xd2\xa4", "\xd2\xa7" => "\xd2\xa6",
"\xd2\xa9" => "\xd2\xa8", "\xd2\xab" => "\xd2\xaa",
"\xd2\xad" => "\xd2\xac", "\xd2\xaf" => "\xd2\xae",
"\xd2\xb1" => "\xd2\xb0", "\xd2\xb3" => "\xd2\xb2",
"\xd2\xb5" => "\xd2\xb4", "\xd2\xb7" => "\xd2\xb6",
"\xd2\xb9" => "\xd2\xb8", "\xd2\xbb" => "\xd2\xba",
"\xd2\xbd" => "\xd2\xbc", "\xd2\xbf" => "\xd2\xbe",
## U+04c0
"\xd3\x82" => "\xd3\x81", "\xd3\x84" => "\xd3\x83",
"\xd3\x86" => "\xd3\x85", "\xd3\x88" => "\xd3\x87",
"\xd3\x8a" => "\xd3\x89", "\xd3\x8c" => "\xd3\x8b",
"\xd3\x8e" => "\xd3\x8d", "\xd3\x8f" => "\xd3\x80",
"\xd3\x91" => "\xd3\x90", "\xd3\x93" => "\xd3\x92",
"\xd3\x95" => "\xd3\x94", "\xd3\x97" => "\xd3\x96",
"\xd3\x99" => "\xd3\x98", "\xd3\x9b" => "\xd3\x9a",
"\xd3\x9d" => "\xd3\x9c", "\xd3\x9f" => "\xd3\x9e",
"\xd3\xa1" => "\xd3\xa0", "\xd3\xa3" => "\xd3\xa2",
"\xd3\xa5" => "\xd3\xa4", "\xd3\xa7" => "\xd3\xa6",
"\xd3\xa9" => "\xd3\xa8", "\xd3\xab" => "\xd3\xaa",
"\xd3\xad" => "\xd3\xac", "\xd3\xaf" => "\xd3\xae",
"\xd3\xb1" => "\xd3\xb0", "\xd3\xb3" => "\xd3\xb2",
"\xd3\xb5" => "\xd3\xb4", "\xd3\xb7" => "\xd3\xb6",
"\xd3\xb9" => "\xd3\xb8", "\xd3\xbb" => "\xd3\xba",
"\xd3\xbd" => "\xd3\xbc", "\xd3\xbf" => "\xd3\xbe",
## U+0500
"\xd4\x81" => "\xd4\x80", "\xd4\x83" => "\xd4\x82",
"\xd4\x85" => "\xd4\x84", "\xd4\x87" => "\xd4\x86",
"\xd4\x89" => "\xd4\x88", "\xd4\x8b" => "\xd4\x8a",
"\xd4\x8d" => "\xd4\x8c", "\xd4\x8f" => "\xd4\x8e",
"\xd4\x91" => "\xd4\x90", "\xd4\x93" => "\xd4\x92",
## U+0560
"\xd5\xa1" => "\xd4\xb1", "\xd5\xa2" => "\xd4\xb2",
"\xd5\xa3" => "\xd4\xb3", "\xd5\xa4" => "\xd4\xb4",
"\xd5\xa5" => "\xd4\xb5", "\xd5\xa6" => "\xd4\xb6",
"\xd5\xa7" => "\xd4\xb7", "\xd5\xa8" => "\xd4\xb8",
"\xd5\xa9" => "\xd4\xb9", "\xd5\xaa" => "\xd4\xba",
"\xd5\xab" => "\xd4\xbb", "\xd5\xac" => "\xd4\xbc",
"\xd5\xad" => "\xd4\xbd", "\xd5\xae" => "\xd4\xbe",
"\xd5\xaf" => "\xd4\xbf", "\xd5\xb0" => "\xd5\x80",
"\xd5\xb1" => "\xd5\x81", "\xd5\xb2" => "\xd5\x82",
"\xd5\xb3" => "\xd5\x83", "\xd5\xb4" => "\xd5\x84",
"\xd5\xb5" => "\xd5\x85", "\xd5\xb6" => "\xd5\x86",
"\xd5\xb7" => "\xd5\x87", "\xd5\xb8" => "\xd5\x88",
"\xd5\xb9" => "\xd5\x89", "\xd5\xba" => "\xd5\x8a",
"\xd5\xbb" => "\xd5\x8b", "\xd5\xbc" => "\xd5\x8c",
"\xd5\xbd" => "\xd5\x8d", "\xd5\xbe" => "\xd5\x8e",
"\xd5\xbf" => "\xd5\x8f",
## U+0580
"\xd6\x80" => "\xd5\x90", "\xd6\x81" => "\xd5\x91",
"\xd6\x82" => "\xd5\x92", "\xd6\x83" => "\xd5\x93",
"\xd6\x84" => "\xd5\x94", "\xd6\x85" => "\xd5\x95",
"\xd6\x86" => "\xd5\x96"
));
SDV($StringFolding, array(
## U+0040
"A" => "a", "B" => "b", "C" => "c", "D" => "d", "E" => "e", "F" => "f",
"G" => "g", "H" => "h", "I" => "i", "J" => "j", "K" => "k", "L" => "l",
"M" => "m", "N" => "n", "O" => "o", "P" => "p", "Q" => "q", "R" => "r",
"S" => "s", "T" => "t", "U" => "u", "V" => "v", "W" => "w", "X" => "x",
"Y" => "y", "Z" => "z",
## U+00B5
"\xc2\xb5" => "\xce\xbc",
## U+00C0
"\xc3\x80" => "\xc3\xa0", "\xc3\x81" => "\xc3\xa1",
"\xc3\x82" => "\xc3\xa2", "\xc3\x83" => "\xc3\xa3",
"\xc3\x84" => "\xc3\xa4", "\xc3\x85" => "\xc3\xa5",
"\xc3\x86" => "\xc3\xa6", "\xc3\x87" => "\xc3\xa7",
"\xc3\x88" => "\xc3\xa8", "\xc3\x89" => "\xc3\xa9",
"\xc3\x8a" => "\xc3\xaa", "\xc3\x8b" => "\xc3\xab",
"\xc3\x8c" => "\xc3\xac", "\xc3\x8d" => "\xc3\xad",
"\xc3\x8e" => "\xc3\xae", "\xc3\x8f" => "\xc3\xaf",
"\xc3\x90" => "\xc3\xb0", "\xc3\x91" => "\xc3\xb1",
"\xc3\x92" => "\xc3\xb2", "\xc3\x93" => "\xc3\xb3",
"\xc3\x94" => "\xc3\xb4", "\xc3\x95" => "\xc3\xb5",
"\xc3\x96" => "\xc3\xb6", "\xc3\x98" => "\xc3\xb8",
"\xc3\x99" => "\xc3\xb9", "\xc3\x9a" => "\xc3\xba",
"\xc3\x9b" => "\xc3\xbb", "\xc3\x9c" => "\xc3\xbc",
"\xc3\x9d" => "\xc3\xbd", "\xc3\x9e" => "\xc3\xbe",
"\xc3\x9f" => "ss",
## U+0100
"\xc4\x80" => "\xc4\x81", "\xc4\x82" => "\xc4\x83",
"\xc4\x84" => "\xc4\x85", "\xc4\x86" => "\xc4\x87",
"\xc4\x88" => "\xc4\x89", "\xc4\x8a" => "\xc4\x8b",
"\xc4\x8c" => "\xc4\x8d", "\xc4\x8e" => "\xc4\x8f",
"\xc4\x90" => "\xc4\x91", "\xc4\x92" => "\xc4\x93",
"\xc4\x94" => "\xc4\x95", "\xc4\x96" => "\xc4\x97",
"\xc4\x98" => "\xc4\x99", "\xc4\x9a" => "\xc4\x9b",
"\xc4\x9c" => "\xc4\x9d", "\xc4\x9e" => "\xc4\x9f",
"\xc4\xa0" => "\xc4\xa1", "\xc4\xa2" => "\xc4\xa3",
"\xc4\xa4" => "\xc4\xa5", "\xc4\xa6" => "\xc4\xa7",
"\xc4\xa8" => "\xc4\xa9", "\xc4\xaa" => "\xc4\xab",
"\xc4\xac" => "\xc4\xad", "\xc4\xae" => "\xc4\xaf",
"\xc4\xb0" => "i\xcc\x87", "\xc4\xb2" => "\xc4\xb3",
"\xc4\xb4" => "\xc4\xb5", "\xc4\xb6" => "\xc4\xb7",
"\xc4\xb9" => "\xc4\xba", "\xc4\xbb" => "\xc4\xbc",
"\xc4\xbd" => "\xc4\xbe", "\xc4\xbf" => "\xc5\x80",
## U+0140
"\xc5\x81" => "\xc5\x82", "\xc5\x83" => "\xc5\x84",
"\xc5\x85" => "\xc5\x86", "\xc5\x87" => "\xc5\x88",
"\xc5\x89" => "\xca\xbcn", "\xc5\x8a" => "\xc5\x8b",
"\xc5\x8c" => "\xc5\x8d", "\xc5\x8e" => "\xc5\x8f",
"\xc5\x90" => "\xc5\x91", "\xc5\x92" => "\xc5\x93",
"\xc5\x94" => "\xc5\x95", "\xc5\x96" => "\xc5\x97",
"\xc5\x98" => "\xc5\x99", "\xc5\x9a" => "\xc5\x9b",
"\xc5\x9c" => "\xc5\x9d", "\xc5\x9e" => "\xc5\x9f",
"\xc5\xa0" => "\xc5\xa1", "\xc5\xa2" => "\xc5\xa3",
"\xc5\xa4" => "\xc5\xa5", "\xc5\xa6" => "\xc5\xa7",
"\xc5\xa8" => "\xc5\xa9", "\xc5\xaa" => "\xc5\xab",
"\xc5\xac" => "\xc5\xad", "\xc5\xae" => "\xc5\xaf",
"\xc5\xb0" => "\xc5\xb1", "\xc5\xb2" => "\xc5\xb3",
"\xc5\xb4" => "\xc5\xb5", "\xc5\xb6" => "\xc5\xb7",
"\xc5\xb8" => "\xc3\xbf", "\xc5\xb9" => "\xc5\xba",
"\xc5\xbb" => "\xc5\xbc", "\xc5\xbd" => "\xc5\xbe",
"\xc5\xbf" => "s",
## U+0180
"\xc6\x81" => "\xc9\x93", "\xc6\x82" => "\xc6\x83",
"\xc6\x84" => "\xc6\x85", "\xc6\x86" => "\xc9\x94",
"\xc6\x87" => "\xc6\x88", "\xc6\x89" => "\xc9\x96",
"\xc6\x8a" => "\xc9\x97", "\xc6\x8b" => "\xc6\x8c",
"\xc6\x8e" => "\xc7\x9d", "\xc6\x8f" => "\xc9\x99",
"\xc6\x90" => "\xc9\x9b", "\xc6\x91" => "\xc6\x92",
"\xc6\x93" => "\xc9\xa0", "\xc6\x94" => "\xc9\xa3",
"\xc6\x96" => "\xc9\xa9", "\xc6\x97" => "\xc9\xa8",
"\xc6\x98" => "\xc6\x99", "\xc6\x9c" => "\xc9\xaf",
"\xc6\x9d" => "\xc9\xb2", "\xc6\x9f" => "\xc9\xb5",
"\xc6\xa0" => "\xc6\xa1", "\xc6\xa2" => "\xc6\xa3",
"\xc6\xa4" => "\xc6\xa5", "\xc6\xa6" => "\xca\x80",
"\xc6\xa7" => "\xc6\xa8", "\xc6\xa9" => "\xca\x83",
"\xc6\xac" => "\xc6\xad", "\xc6\xae" => "\xca\x88",
"\xc6\xaf" => "\xc6\xb0", "\xc6\xb1" => "\xca\x8a",
"\xc6\xb2" => "\xca\x8b", "\xc6\xb3" => "\xc6\xb4",
"\xc6\xb5" => "\xc6\xb6", "\xc6\xb7" => "\xca\x92",
"\xc6\xb8" => "\xc6\xb9", "\xc6\xbc" => "\xc6\xbd",
## U+01c0
"\xc7\x84" => "\xc7\x86", "\xc7\x85" => "\xc7\x86",
"\xc7\x87" => "\xc7\x89", "\xc7\x88" => "\xc7\x89",
"\xc7\x8a" => "\xc7\x8c", "\xc7\x8b" => "\xc7\x8c",
"\xc7\x8d" => "\xc7\x8e", "\xc7\x8f" => "\xc7\x90",
"\xc7\x91" => "\xc7\x92", "\xc7\x93" => "\xc7\x94",
"\xc7\x95" => "\xc7\x96", "\xc7\x97" => "\xc7\x98",
"\xc7\x99" => "\xc7\x9a", "\xc7\x9b" => "\xc7\x9c",
"\xc7\x9e" => "\xc7\x9f", "\xc7\xa0" => "\xc7\xa1",
"\xc7\xa2" => "\xc7\xa3", "\xc7\xa4" => "\xc7\xa5",
"\xc7\xa6" => "\xc7\xa7", "\xc7\xa8" => "\xc7\xa9",
"\xc7\xaa" => "\xc7\xab", "\xc7\xac" => "\xc7\xad",
"\xc7\xae" => "\xc7\xaf", "\xc7\xb0" => "j\xcc\x8c",
"\xc7\xb1" => "\xc7\xb3", "\xc7\xb2" => "\xc7\xb3",
"\xc7\xb4" => "\xc7\xb5", "\xc7\xb6" => "\xc6\x95",
"\xc7\xb7" => "\xc6\xbf", "\xc7\xb8" => "\xc7\xb9",
"\xc7\xba" => "\xc7\xbb", "\xc7\xbc" => "\xc7\xbd",
"\xc7\xbe" => "\xc7\xbf",
## U+0200
"\xc8\x80" => "\xc8\x81", "\xc8\x82" => "\xc8\x83",
"\xc8\x84" => "\xc8\x85", "\xc8\x86" => "\xc8\x87",
"\xc8\x88" => "\xc8\x89", "\xc8\x8a" => "\xc8\x8b",
"\xc8\x8c" => "\xc8\x8d", "\xc8\x8e" => "\xc8\x8f",
"\xc8\x90" => "\xc8\x91", "\xc8\x92" => "\xc8\x93",
"\xc8\x94" => "\xc8\x95", "\xc8\x96" => "\xc8\x97",
"\xc8\x98" => "\xc8\x99", "\xc8\x9a" => "\xc8\x9b",
"\xc8\x9c" => "\xc8\x9d", "\xc8\x9e" => "\xc8\x9f",
"\xc8\xa0" => "\xc6\x9e", "\xc8\xa2" => "\xc8\xa3",
"\xc8\xa4" => "\xc8\xa5", "\xc8\xa6" => "\xc8\xa7",
"\xc8\xa8" => "\xc8\xa9", "\xc8\xaa" => "\xc8\xab",
"\xc8\xac" => "\xc8\xad", "\xc8\xae" => "\xc8\xaf",
"\xc8\xb0" => "\xc8\xb1", "\xc8\xb2" => "\xc8\xb3",
"\xc8\xba" => "\xe2\xb1\xa5", "\xc8\xbb" => "\xc8\xbc",
"\xc8\xbd" => "\xc6\x9a", "\xc8\xbe" => "\xe2\xb1\xa6",
## U+0240
"\xc9\x81" => "\xc9\x82", "\xc9\x83" => "\xc6\x80",
"\xc9\x84" => "\xca\x89", "\xc9\x85" => "\xca\x8c",
"\xc9\x86" => "\xc9\x87", "\xc9\x88" => "\xc9\x89",
"\xc9\x8a" => "\xc9\x8b", "\xc9\x8c" => "\xc9\x8d",
"\xc9\x8e" => "\xc9\x8f",
## U+0345
"\xcd\x85" => "\xce\xb9",
## U+0380
"\xce\x86" => "\xce\xac", "\xce\x88" => "\xce\xad",
"\xce\x89" => "\xce\xae", "\xce\x8a" => "\xce\xaf",
"\xce\x8c" => "\xcf\x8c", "\xce\x8e" => "\xcf\x8d",
"\xce\x8f" => "\xcf\x8e", "\xce\x90" => "\xce\xb9\xcc\x88\xcc\x81",
"\xce\x91" => "\xce\xb1", "\xce\x92" => "\xce\xb2",
"\xce\x93" => "\xce\xb3", "\xce\x94" => "\xce\xb4",
"\xce\x95" => "\xce\xb5", "\xce\x96" => "\xce\xb6",
"\xce\x97" => "\xce\xb7", "\xce\x98" => "\xce\xb8",
"\xce\x99" => "\xce\xb9", "\xce\x9a" => "\xce\xba",
"\xce\x9b" => "\xce\xbb", "\xce\x9c" => "\xce\xbc",
"\xce\x9d" => "\xce\xbd", "\xce\x9e" => "\xce\xbe",
"\xce\x9f" => "\xce\xbf", "\xce\xa0" => "\xcf\x80",
"\xce\xa1" => "\xcf\x81", "\xce\xa3" => "\xcf\x83",
"\xce\xa4" => "\xcf\x84", "\xce\xa5" => "\xcf\x85",
"\xce\xa6" => "\xcf\x86", "\xce\xa7" => "\xcf\x87",
"\xce\xa8" => "\xcf\x88", "\xce\xa9" => "\xcf\x89",
"\xce\xaa" => "\xcf\x8a", "\xce\xab" => "\xcf\x8b",
"\xce\xb0" => "\xcf\x85\xcc\x88\xcc\x81",
## U+03c0
"\xcf\x82" => "\xcf\x83", "\xcf\x90" => "\xce\xb2",
"\xcf\x91" => "\xce\xb8", "\xcf\x95" => "\xcf\x86",
"\xcf\x96" => "\xcf\x80", "\xcf\x98" => "\xcf\x99",
"\xcf\x9a" => "\xcf\x9b", "\xcf\x9c" => "\xcf\x9d",
"\xcf\x9e" => "\xcf\x9f", "\xcf\xa0" => "\xcf\xa1",
"\xcf\xa2" => "\xcf\xa3", "\xcf\xa4" => "\xcf\xa5",
"\xcf\xa6" => "\xcf\xa7", "\xcf\xa8" => "\xcf\xa9",
"\xcf\xaa" => "\xcf\xab", "\xcf\xac" => "\xcf\xad",
"\xcf\xae" => "\xcf\xaf", "\xcf\xb0" => "\xce\xba",
"\xcf\xb1" => "\xcf\x81", "\xcf\xb4" => "\xce\xb8",
"\xcf\xb5" => "\xce\xb5", "\xcf\xb7" => "\xcf\xb8",
"\xcf\xb9" => "\xcf\xb2", "\xcf\xba" => "\xcf\xbb",
"\xcf\xbd" => "\xcd\xbb", "\xcf\xbe" => "\xcd\xbc",
"\xcf\xbf" => "\xcd\xbd",
## U+0400
"\xd0\x80" => "\xd1\x90", "\xd0\x81" => "\xd1\x91",
"\xd0\x82" => "\xd1\x92", "\xd0\x83" => "\xd1\x93",
"\xd0\x84" => "\xd1\x94", "\xd0\x85" => "\xd1\x95",
"\xd0\x86" => "\xd1\x96", "\xd0\x87" => "\xd1\x97",
"\xd0\x88" => "\xd1\x98", "\xd0\x89" => "\xd1\x99",
"\xd0\x8a" => "\xd1\x9a", "\xd0\x8b" => "\xd1\x9b",
"\xd0\x8c" => "\xd1\x9c", "\xd0\x8d" => "\xd1\x9d",
"\xd0\x8e" => "\xd1\x9e", "\xd0\x8f" => "\xd1\x9f",
"\xd0\x90" => "\xd0\xb0", "\xd0\x91" => "\xd0\xb1",
"\xd0\x92" => "\xd0\xb2", "\xd0\x93" => "\xd0\xb3",
"\xd0\x94" => "\xd0\xb4", "\xd0\x95" => "\xd0\xb5",
"\xd0\x96" => "\xd0\xb6", "\xd0\x97" => "\xd0\xb7",
"\xd0\x98" => "\xd0\xb8", "\xd0\x99" => "\xd0\xb9",
"\xd0\x9a" => "\xd0\xba", "\xd0\x9b" => "\xd0\xbb",
"\xd0\x9c" => "\xd0\xbc", "\xd0\x9d" => "\xd0\xbd",
"\xd0\x9e" => "\xd0\xbe", "\xd0\x9f" => "\xd0\xbf",
"\xd0\xa0" => "\xd1\x80", "\xd0\xa1" => "\xd1\x81",
"\xd0\xa2" => "\xd1\x82", "\xd0\xa3" => "\xd1\x83",
"\xd0\xa4" => "\xd1\x84", "\xd0\xa5" => "\xd1\x85",
"\xd0\xa6" => "\xd1\x86", "\xd0\xa7" => "\xd1\x87",
"\xd0\xa8" => "\xd1\x88", "\xd0\xa9" => "\xd1\x89",
"\xd0\xaa" => "\xd1\x8a", "\xd0\xab" => "\xd1\x8b",
"\xd0\xac" => "\xd1\x8c", "\xd0\xad" => "\xd1\x8d",
"\xd0\xae" => "\xd1\x8e", "\xd0\xaf" => "\xd1\x8f",
## U+0460
"\xd1\xa0" => "\xd1\xa1", "\xd1\xa2" => "\xd1\xa3",
"\xd1\xa4" => "\xd1\xa5", "\xd1\xa6" => "\xd1\xa7",
"\xd1\xa8" => "\xd1\xa9", "\xd1\xaa" => "\xd1\xab",
"\xd1\xac" => "\xd1\xad", "\xd1\xae" => "\xd1\xaf",
"\xd1\xb0" => "\xd1\xb1", "\xd1\xb2" => "\xd1\xb3",
"\xd1\xb4" => "\xd1\xb5", "\xd1\xb6" => "\xd1\xb7",
"\xd1\xb8" => "\xd1\xb9", "\xd1\xba" => "\xd1\xbb",
"\xd1\xbc" => "\xd1\xbd", "\xd1\xbe" => "\xd1\xbf",
## U+0480
"\xd2\x80" => "\xd2\x81", "\xd2\x8a" => "\xd2\x8b",
"\xd2\x8c" => "\xd2\x8d", "\xd2\x8e" => "\xd2\x8f",
"\xd2\x90" => "\xd2\x91", "\xd2\x92" => "\xd2\x93",
"\xd2\x94" => "\xd2\x95", "\xd2\x96" => "\xd2\x97",
"\xd2\x98" => "\xd2\x99", "\xd2\x9a" => "\xd2\x9b",
"\xd2\x9c" => "\xd2\x9d", "\xd2\x9e" => "\xd2\x9f",
"\xd2\xa0" => "\xd2\xa1", "\xd2\xa2" => "\xd2\xa3",
"\xd2\xa4" => "\xd2\xa5", "\xd2\xa6" => "\xd2\xa7",
"\xd2\xa8" => "\xd2\xa9", "\xd2\xaa" => "\xd2\xab",
"\xd2\xac" => "\xd2\xad", "\xd2\xae" => "\xd2\xaf",
"\xd2\xb0" => "\xd2\xb1", "\xd2\xb2" => "\xd2\xb3",
"\xd2\xb4" => "\xd2\xb5", "\xd2\xb6" => "\xd2\xb7",
"\xd2\xb8" => "\xd2\xb9", "\xd2\xba" => "\xd2\xbb",
"\xd2\xbc" => "\xd2\xbd", "\xd2\xbe" => "\xd2\xbf",
## U+04c0
"\xd3\x80" => "\xd3\x8f", "\xd3\x81" => "\xd3\x82",
"\xd3\x83" => "\xd3\x84", "\xd3\x85" => "\xd3\x86",
"\xd3\x87" => "\xd3\x88", "\xd3\x89" => "\xd3\x8a",
"\xd3\x8b" => "\xd3\x8c", "\xd3\x8d" => "\xd3\x8e",
"\xd3\x90" => "\xd3\x91", "\xd3\x92" => "\xd3\x93",
"\xd3\x94" => "\xd3\x95", "\xd3\x96" => "\xd3\x97",
"\xd3\x98" => "\xd3\x99", "\xd3\x9a" => "\xd3\x9b",
"\xd3\x9c" => "\xd3\x9d", "\xd3\x9e" => "\xd3\x9f",
"\xd3\xa0" => "\xd3\xa1", "\xd3\xa2" => "\xd3\xa3",
"\xd3\xa4" => "\xd3\xa5", "\xd3\xa6" => "\xd3\xa7",
"\xd3\xa8" => "\xd3\xa9", "\xd3\xaa" => "\xd3\xab",
"\xd3\xac" => "\xd3\xad", "\xd3\xae" => "\xd3\xaf",
"\xd3\xb0" => "\xd3\xb1", "\xd3\xb2" => "\xd3\xb3",
"\xd3\xb4" => "\xd3\xb5", "\xd3\xb6" => "\xd3\xb7",
"\xd3\xb8" => "\xd3\xb9", "\xd3\xba" => "\xd3\xbb",
"\xd3\xbc" => "\xd3\xbd", "\xd3\xbe" => "\xd3\xbf",
## U+0500
"\xd4\x80" => "\xd4\x81", "\xd4\x82" => "\xd4\x83",
"\xd4\x84" => "\xd4\x85", "\xd4\x86" => "\xd4\x87",
"\xd4\x88" => "\xd4\x89", "\xd4\x8a" => "\xd4\x8b",
"\xd4\x8c" => "\xd4\x8d", "\xd4\x8e" => "\xd4\x8f",
"\xd4\x90" => "\xd4\x91", "\xd4\x92" => "\xd4\x93",
"\xd4\xb1" => "\xd5\xa1", "\xd4\xb2" => "\xd5\xa2",
"\xd4\xb3" => "\xd5\xa3", "\xd4\xb4" => "\xd5\xa4",
"\xd4\xb5" => "\xd5\xa5", "\xd4\xb6" => "\xd5\xa6",
"\xd4\xb7" => "\xd5\xa7", "\xd4\xb8" => "\xd5\xa8",
"\xd4\xb9" => "\xd5\xa9", "\xd4\xba" => "\xd5\xaa",
"\xd4\xbb" => "\xd5\xab", "\xd4\xbc" => "\xd5\xac",
"\xd4\xbd" => "\xd5\xad", "\xd4\xbe" => "\xd5\xae",
"\xd4\xbf" => "\xd5\xaf",
## U+0540
"\xd5\x80" => "\xd5\xb0", "\xd5\x81" => "\xd5\xb1",
"\xd5\x82" => "\xd5\xb2", "\xd5\x83" => "\xd5\xb3",
"\xd5\x84" => "\xd5\xb4", "\xd5\x85" => "\xd5\xb5",
"\xd5\x86" => "\xd5\xb6", "\xd5\x87" => "\xd5\xb7",
"\xd5\x88" => "\xd5\xb8", "\xd5\x89" => "\xd5\xb9",
"\xd5\x8a" => "\xd5\xba", "\xd5\x8b" => "\xd5\xbb",
"\xd5\x8c" => "\xd5\xbc", "\xd5\x8d" => "\xd5\xbd",
"\xd5\x8e" => "\xd5\xbe", "\xd5\x8f" => "\xd5\xbf",
"\xd5\x90" => "\xd6\x80", "\xd5\x91" => "\xd6\x81",
"\xd5\x92" => "\xd6\x82", "\xd5\x93" => "\xd6\x83",
"\xd5\x94" => "\xd6\x84", "\xd5\x95" => "\xd6\x85",
"\xd5\x96" => "\xd6\x86", "\xd6\x87" => "\xd5\xa5\xd6\x82"
));