Permalink
Fetching contributors…
Cannot retrieve contributors at this time
5783 lines (5100 sloc) 175 KB
<?php
// Copyright 2003-2010 Won-Kyu Park <wkpark at kldp.org> all rights reserved.
// distributable under GPL see COPYING
//
// many codes are imported from the MoinMoin
// some codes are reused from the Phiki
//
// * MoinMoin is a python based wiki clone based on the PikiPiki
// by Ju"rgen Hermann <jhs at web.de>
// * PikiPiki is a python based wiki clone by MartinPool
// * Phiki is a php based wiki clone based on the MoinMoin
// by Fred C. Yankowski <fcy at acm.org>
//
// $Id$
function _preg_escape($val) {
return preg_replace('/([\$\^\.\[\]\{\}\|\(\)\+\*\/\\\\!\?]{1})/','\\\\\1',$val);
}
function _preg_search_escape($val) {
return preg_replace('/([\/]{1})/','\\\\\1',$val);
}
function _mkdir_p($target,$mode=0777) {
// from php.net/mkdir user contributed notes
if (file_exists($target)) {
if (!is_dir($target)) return false;
else return true;
}
// recursivly create dirs.
return (_mkdir_p(dirname($target),$mode) and mkdir($target,$mode));
}
/**
* Check double slashes in the REQUEST_URI
* and try to get the PATH_INFO or parse the PHP_SELF.
*
* @author Won-Kyu Park <wkpark@gmail.com>
* @since 2015/12/14
* @since 1.2.5
*
* @return string
*/
function get_pathinfo() {
if (!isset($_SERVER['PATH_INFO'])) {
// the PATH_INFO not available.
// try to get the PATH_INFO from the PHP_SELF.
$path_parts = explode('/', $_SERVER['PHP_SELF']);
// remove all real path parts from PHP_SELF
$root = $_SERVER['DOCUMENT_ROOT'];
$path = $root;
foreach ($path_parts as $k=>$part) {
if ($part === '')
continue;
$path .= '/'.$part;
if (file_exists($path))
unset($path_parts[$k]);
else
break;
}
// combine remaining parts
$_SERVER['PATH_INFO'] = implode('/', $path_parts);
}
// if REQUEST_URI is not available.
if (!isset($_SERVER['REQUEST_URI']))
return $_SERVER['PATH_INFO'];
// check double slashes in the REQUEST_URI if it available
//
// from MediaWikiSrc:WebRequest.php source code
// by Apache 2.x, double slashes are converted to single slashes.
// and PATH_INFO is mangled due to https://bugs.php.net/bug.php?id=31892
$uri = $_SERVER['REQUEST_URI'];
if (($p = strpos($uri, '?')) !== false) {
// remove the query string part.
$uri = substr($uri, 0, $p);
}
// rawurldecode REQUEST_URI
$decoded_uri = rawurldecode($uri);
if (strpos($decoded_uri, '//') === false)
return $_SERVER['PATH_INFO'];
return guess_pathinfo($decoded_uri);
}
/**
* Try to get PATH_INFO from the REQUEST_URI
*
* @author Won-Kyu Park <wkpark@gmail.com>
* @since 2015/12/14
* @since 1.2.5
*
* @return string
*/
function guess_pathinfo($decoded_uri) {
// try to get PATH_INFO from the REQUEST_URI
// $uri = rawurldecode($_SERVER['REQUEST_URI']);
// split all parts of REQUEST_URI.
$parts = preg_split('@(/)@', $decoded_uri, -1, PREG_SPLIT_DELIM_CAPTURE);
// /foo//bar/foo => '','/','foo','/','','/','bar','/','foo'
// try to get the PATH_INFO path parts
if ($_SERVER['PATH_INFO'] == '/') {
$pos = count($parts) - 1;
} else {
$path = explode('/', $_SERVER['PATH_INFO']);
// search unmatch REQUEST_URI part
$pos = count($parts) - 1;
for (; $pos > 0; $pos--) {
if ($parts[$pos] == '' || $parts[$pos] == '/')
continue;
$part = end($path);
if ($parts[$pos] != $part)
break;
array_pop($path);
}
}
// skip all path components
for (; $pos > 0; $pos--) {
if ($parts[$pos] == '' || $parts[$pos] == '/')
continue;
else
break;
}
// remove non path components.
for (; $pos > 0; $pos--)
unset($parts[$pos]);
// merge all path components.
return implode('', $parts);
}
function get_scriptname() {
// Return full URL of current page.
// $_SERVER["SCRIPT_NAME"] has bad value under CGI mode
// set 'cgi.fix_pathinfo=1' in the php.ini under
// apache 2.0.x + php4.2.x Win32
// check mod_rewrite
if (strpos($_SERVER['REQUEST_URI'],$_SERVER['SCRIPT_NAME'])===false) {
if ($_SERVER['REQUEST_URI'][0] == '/' and ($p = strpos($_SERVER['REQUEST_URI'], '/', 1)) !== false) {
$prefix = substr($_SERVER['REQUEST_URI'], 0, $p);
if (($p = strpos($_SERVER['SCRIPT_NAME'], $prefix)) === 0)
return $prefix;
}
return '';
}
return $_SERVER['SCRIPT_NAME'];
}
/**
* get the number of lines in a file
*
* @author wkpark@kldp.org
* @since 2010/09/13
*
*/
function get_file_lines($filename) {
$fp = fopen($filename, 'r');
if (!is_resource($fp)) return 0;
// test \n or \r or \r\n
$i = 0;
while(($test = fgets($fp, 4096)) and !preg_match("/(\r|\r\n|\n)$/", $test, $match)) $i++;
$i = 1;
$bsz = 1024 * 8;
if (isset($match[1])) {
while ($chunk = fread($fp, $bsz))
$i += substr_count($chunk, $match[1]);
}
fclose($fp);
return $i;
}
/**
* counting add/del lines of a given diff
*
* @author wkpark@kldp.org
* @since 2015/06/08
* @param string $diff - diff -u output
* @return array - return added/deleted lines
*/
function diffcount_simple($diff) {
$retval = &$params['retval'];
$lines = explode("\n", $diff);
$lsz = sizeof($lines);
$add = 0;
$del = 0;
for ($i = 0; $i < $lsz; $i++) {
$marker = $lines[$i][0];
if (!in_array($marker, array('-','+'))) {
continue;
}
if ($marker == '-')
$del++;
else
$add++;
}
return array($add, $del, 0, 0);
}
/**
* counting add/del lines and chars of a given diff
*
* @author wkpark@kldp.org
* @since 2015/06/08
* @param string $diff - diff -u output
* @return array - return added/deleted chars and lines
*/
function diffcount_lines($diff, $charset) {
$lines = explode("\n", $diff);
$lsz = sizeof($lines);
if ($lines[$lsz - 1] == '') {
// trash last empty line
array_pop($lines);
$lsz--;
}
$add = 0;
$del = 0;
$add_chars = 0;
$del_chars = 0;
$minorfix = true;
$orig = array();
$new = array();
$om = false;
for ($i = 0; $i < $lsz; $i++) {
$line = &$lines[$i];
if (!isset($line[0])) break;
$mark = $line[0];
if (!$om && $mark == '-' && isset($line[3]) && substr($line, 0, 4) == '--- ') {
// trash first --- blah\n+++ blah\n lines
$i++;
continue;
}
$line = substr($line, 1);
if ($mark == '@') {
continue;
} else if ($mark == '-') {
$om = true;
$orig[] = $line;
$del++;
continue;
} else if ($mark == '+') {
$om = true;
$new[] = $line;
$add++;
continue;
} else if ($om) {
$om = false;
$diffchars = diffcount_chars($orig, $new, $charset);
if ($diffchars === false) {
// simply check the difference of strlen
$nc = mb_strlen(implode("\n", $new), $charset);
$oc = mb_strlen(implode("\n", $orig), $charset);
$added = $nc - $oc;
if ($added > 0)
$add_chars+= $added;
else
$del_chars+= -$added;
} else {
$add_chars+= $diffchars[0];
$del_chars+= $diffchars[1];
}
// is it minorfix ?
if (!$diffchars[2]) $minorfix = false;
$orig = array();
$new = array();
}
}
if (!empty($orig) or !empty($new)) {
$diffchars = diffcount_chars($orig, $new, $charset);
if ($diffchars === false) {
// simply check the difference of strlen
$nc = mb_strlen(implode("\n", $new), $charset);
$oc = mb_strlen(implode("\n", $orig), $charset);
$added = $nc - $oc;
if ($added > 0)
$add_chars+= $added;
else
$del_chars+= -$added;
} else {
$add_chars+= $diffchars[0];
$del_chars+= $diffchars[1];
}
// is it minorfix ?
if (!$diffchars[2]) $minorfix = false;
}
return array($add, $del, $add_chars, $del_chars, $minorfix);
}
/**
* counting add/del chars of a given array
*
* @author wkpark@kldp.org
* @since 2015/06/08
* @param array $orig - original lines
* @param array $new - modified lines
* @param string $charet - character set
* @return array added,deleted chars
*/
function diffcount_chars($orig, $new, $charset) {
$oc = count($orig);
$nc = count($new);
if ($oc > 200 or $nc > 200) {
// too big to call WordLevelDiff.
return false;
}
include_once('lib/difflib.php');
$add_chars = 0;
$del_chars = 0;
$minorfix = true;
$result = new WordLevelDiff($orig, $new, $charset);
foreach ($result->edits as $edit) {
if (is_a($edit, '_DiffOp_Copy')) {
continue;
} elseif (is_a($edit, '_DiffOp_Add')) {
$chunk = str_replace('&nbsp;', "\n", implode('', $edit->_final));
$chunk = preg_replace('@(\n|\s)+@m', '', $chunk);
$add = mb_strlen($chunk, $charset);
if ($add > 3) $minorfix = false;
$add_chars+= $add;
} elseif (is_a($edit, '_DiffOp_Delete')) {
$del = mb_strlen(implode('', $edit->orig), $charset);
if ($del > 3) $minorfix = false;
$del_chars+= $del;
} elseif (is_a($edit, '_DiffOp_Change')) {
$del_change = mb_strlen(implode('', $edit->orig), $charset);
$add_change = mb_strlen(implode('', $edit->_final), $charset);
if (abs($add_change - $del_change) > 5) $minorfix = false;
$del_chars+= $del_change;
$add_chars+= $add_change;
}
}
return array($add_chars, $del_chars, $minorfix);
}
/**
* Extracted from Gallery Plugin
*
* make pagelist to paginate.
*
* @author wkpark@kldp.org
* @since 2003/08/10
* @param integer $pages - the number of pages
* @param string $action - link to page action
* @param integer $curpage - current page
* @param integer $listcount - the number of pages to show
*/
function get_pagelist($formatter,$pages,$action,$curpage=1,$listcount=10,$bra="[",$cat="]",$sep="|",$prev="&#171;",$next="&#187;",$first="",$last="",$ellip="...") {
if ($curpage >=0)
if ($curpage > $pages)
$curpage=$pages;
if ($curpage <= 0)
$curpage=1;
$startpage=intval(($curpage-1) / $listcount)*$listcount +1;
$pnut="";
if ($startpage > 1) {
$prevref=$startpage-1;
if (!$first) {
$prev_l=$formatter->link_tag('',$action.$prevref,$prev);
$prev_1=$formatter->link_tag('',$action."1","1");
$pnut="$prev_l".$bra.$prev_1.$cat.$ellip.$bar;
}
} else {
$pnut=$prev.$bra."";
}
for ($i=$startpage;$i < ($startpage + $listcount) && $i <=$pages; $i++) {
if ($i != $startpage)
$pnut.=$sep;
if ($i != $curpage) {
$link=$formatter->link_tag('',$action.$i,$i);
$pnut.=$link;
} else
$pnut.="<b>$i</b>";
}
if ($i <= $pages) {
if (!$last) {
$next_l=$formatter->link_tag('',$action.$pages,$pages);
$next_i=$formatter->link_tag('',$action.$i,$next);
$pnut.=$cat.$ellip.$bra.$next_l.$cat.$next_i;
}
} else {
$pnut.="".$cat.$next;
}
return $pnut;
}
function _html_escape($string) {
return preg_replace(array("@<(?=/?\s*\w+[^<>]*)@", '@"@', '@&(?!#?[a-zA-Z0-9]+;)@'), array("&lt;", '&quot;', '&amp;'), $string);
}
function _rawurlencode($url) {
$name=rawurlencode($url);
$urlname = str_replace(array('%2F', '%7E', '%3A'), array('/', '~', ':'), $name);
$urlname= preg_replace('#:+#',':',$urlname);
return $urlname;
}
/**
* do not encode already urlencoded chars.
*
* @author wkpark at gmail.com
* @since 2015/07/03
*/
function _urlencode($url) {
$url = preg_replace('#:+#', ':', $url);
$chunks = preg_split("@([a-zA-Z0-9/?.~#&:;=%_-]+)@", $url, -1, PREG_SPLIT_DELIM_CAPTURE);
for ($i = 0, $sz = count($chunks); $i < $sz; $i++) {
if ($i % 2 == 0) {
$chunks[$i] = strtr(rawurlencode($chunks[$i]), array(
'%23'=>'#',
'%26'=>'&',
'%2F'=>'/',
'%3A'=>':',
'%3B'=>';',
'%3D'=>'=',
'%3F'=>'?',
)
);
}
}
return preg_replace("/%(?![a-fA-Z0-9]{2})/", '%25', implode('', $chunks));
}
/**
* auto detect the encoding of a given URL and fix it
*
* @since 2014/03/21
*/
function _autofixencode($str) {
global $DBInfo;
if (isset($DBInfo->url_encodings)) {
$charset = mb_detect_encoding($str, $DBInfo->url_encodings);
if ($encode !== false) {
$tmp = iconv($charset, $DBInfo->charset, $str);
if ($tmp !== false) return $tmp;
}
}
return $str;
}
if (!function_exists('_stripslashes')) {
function _stripslashes($str) {
return get_magic_quotes_gpc() ? stripslashes($str):$str;
}
}
/**
* get random string to test regex
* from http://stackoverflow.com/questions/4356289/php-random-string-generator
*/
function _str_random($len, $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ;:%#@",`abcdefghijklmnopqrstuvwxyz1234567890') {
$clen = strlen($chars);
$str = '';
for ($i = 0; $i < $len; $i++) {
$str.= $chars[rand(0, $clen - 1)];
}
return $str;
}
function qualifiedUrl($url) {
if (substr($url,0,7)=='http://' or substr($url,0,8) == 'https://')
return $url;
$port= ($_SERVER['SERVER_PORT'] != 80) ? ':'.$_SERVER['SERVER_PORT']:'';
$proto= 'http';
if (!empty($_SERVER['HTTPS'])) $proto= 'https';
else $proto= strtolower(strtok($_SERVER['SERVER_PROTOCOL'],'/'));
if (empty($url[0]) or $url[0] != '/') $url='/'.$url; // XXX
if (strpos($_SERVER['HTTP_HOST'],':') !== false)
$port = '';
return $proto.'://'.$_SERVER['HTTP_HOST'].$port.$url;
}
function find_needle($body,$needle,$exclude='',$count=0) {
if (!$body) return '';
$test=@preg_match("/$needle/","",$match);
if ($test === false) {
return '';
}
$lines=explode("\n",$body);
$out="";
$matches=preg_grep("/($needle)/i",$lines);
if ($exclude)
if (preg_grep("/($exclude)/i",$matches)) return '';
if (count($matches) > $count) $matches=array_slice($matches,0,$count);
foreach ($matches as $line) {
$line=preg_replace("/($needle)/i","<strong>\\1</strong>",str_replace("<","&lt;",$line));
$out.="<br />\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;".$line;
}
return $out;
}
function normalize($title) {
if (strpos($title," "))
#return preg_replace("/[\?!$%\.\^;&\*()_\+\|\[\] ]/","",ucwords($title));
return str_replace(" ","",ucwords($title));
return $title;
}
function normalize_word($word,$group='',$pagename='',$nogroup=0,$islink=1) {
if ($word[0]=='[') $word=substr($word,1,-1);
if ($word[0]=='"') $word=substr($word,1,-1);
$page=$word;
$text='';
$main_page='';
# User namespace extension
if ($page[0]=='~' and ($p=strpos($page,'/'))) {
# change ~User/Page to User~Page
$main_page=$page;
$page=$text=substr($page,1,$p-1).'~'.substr($page,$p+1);
return array($page,$text,$main_page);
}
if ($page[0]=='.' and preg_match('/^(\.{1,2})\//',$page,$match)) {
if ($match[1] == '..') {
if (($pos = strrpos($pagename,'/')) > 0) {
$upper=substr($pagename,0,$pos);
$page=substr($page,2);
if ($page == '/') $page=$upper;
else $page=$upper.$page;
} else {
$page=substr($page,3);
if ($page == '') $page=substr($pagename,strlen($group));
else if ($group) $page=$group.$page;
}
} else {
$page=substr($page,1);
if ($page == '/') $page='';
$page=$pagename.$page;
}
return array($page,$text,$main_page);
}
#if ($nogroup and $page[0]=='/') { # SubPage without group support. XXX disabled
if ($page[0]=='/') { # SubPage
$page=$pagename.$page;
} else if (!empty($islink) && $tok=strtok($page,'.')) {
# print $tok;
if ($tok=='Main') {
# Main.MoniWiki => MoniWiki
$page=$text=strtok('');
return array($page,$text,$main_page);
} else if (strpos($tok,'~') === false and strpos($tok,'/') === false) {
# Ko~Hello.World =x=> Ko~Hello~World
# Ko.Hello => Ko~Hello
#$page=preg_replace('/\./','~',$page,1);
$npage=preg_replace('/(?<!\\\\)\./','~',$page,1);
if ($npage == $page) $page=preg_replace('/(\\\.)/','.',$page,1);
else $page=$npage;
$text=$main_page=strtok('');
}
}
if (!$nogroup and $group and !strpos($page,'~')) {
# UserNameSpace pages: e.g.) Ko~MoniWiki etc.
if ($page[0]=='/') {
# /MoniWiki => MoniWiki
$page=$text=substr($page,1);
} else {
$main_page=$text=$page;
$page=$group.$page;
}
}
if (preg_match("/^wiki:/", $page)) { # wiki:
$text=$page=substr($page,5);
if (preg_match("/^\"([^\"]+)\"\s?(.*)$/", $page, $m)) {
// [[wiki:"Page with space" goto Page]] case
list($page, $text) = array($m[1], $m[2]);
} else if (strpos($page,' ')) { # have a space ?
list($page,$text)= explode(' ',$page,2);
}
if ($page[0]=='/') $page= $pagename.$page;
}
return array($page,$text,$main_page);
}
if (function_exists('str_getcsv')) {
function get_csv($str) {
return str_getcsv($str);
}
} else {
function get_csv($str) {
// csv_regex from Mastering regular expressions p480, 481
$csv_regex = '{
\G(?:^|\s*,)\s* # spaces are added
(?:
# Either a double quoted filed
" # field opening quote
( [^"]*+ (?: "" [^"]*+ )*+ )
" # closing quote
| # .. or ...
# ... some non-quote/non-comma text...
( [^",]*+ )
)
}x';
preg_match_all($csv_regex, $str, $all_matches);
$ret = array();
for ($i = 0; $i < count($all_matches[0]); $i++) {
if (strlen($all_matches[2][$i]) > 0)
$ret[] = $all_matches[2][$i];
else
// a quoted value.
$ret[] = preg_replace('/""/', '"', $all_matches[1][$i]);
}
return $ret;
}
}
/**
* get aliases from alias file
*
* @author wkpark@kldp.org
* @since 2010/08/12
*
*/
function get_aliases($file) {
$lines = array();
if (file_exists($file)) $lines = file($file);
if (empty($lines))
return array();
$alias = array();
foreach ($lines as $line) {
$line=trim($line);
if (empty($line) or $line[0]=='#') continue;
# support three types of aliases
#
# dest<alias1,alias2,...
# dest,alias1,alias2,...
# alias>dest1,dest2,dest3,...
#
if (($p=strpos($line,'>')) !== false) {
list($key, $list) = explode('>',$line,2);
$vals = get_csv($list);
$alias[$key] = $vals;
} else {
if (($p = strpos($line, '<')) !== false) {
list($val, $keys) = explode('<', $line, 2);
$keys = get_csv($keys);
} else {
$keys = get_csv($line);
$val = array_shift($keys);
}
foreach ($keys as $k) {
if (!isset($alias[$k])) $alias[$k] = array();
$alias[$k][] = $val;
}
}
}
return $alias;
}
/**
* Store aliases
*
* @author Won-Kyu Park <wkpark@gmail.com>
*/
function store_aliases($pagename, $aliases) {
$cache = new Cache_Text('alias');
$cur = $cache->fetch($pagename);
if (!is_array($cur)) $cur = array();
if (empty($cur) and empty($aliases))
return;
// inverted index
$icache = new Cache_Text('aliasname');
if (key($cur) == $pagename)
$cur = $cur[$pagename];
$add = array_diff($aliases, $cur);
$del = array_diff($cur, $aliases);
// merge new aliases
foreach ($add as $a) {
if (!isset($a[0])) continue;
$i = $icache->fetch($a);
if (!is_array($i)) $i = array();
$i = array_merge($i, array($pagename));
$i = array_unique($i);
$icache->update($a, $i);
}
// remove deleted aliases
foreach ($del as $d) {
if (!isset($d[0])) continue;
$i = $icache->fetch($d);
if (!is_array($i)) $i = array();
$i = array_diff($i, array($pagename));
if (empty($i))
$icache->remove($d);
else
$icache->update($d, $i);
}
// update pagealiases
if (!empty($aliases))
$cache->update($pagename, array($pagename => $aliases));
else
$cache->remove($pagename);
}
/**
* Store pagelinks
*
* @author Won-Kyu Park <wkpark@gmail.com>
*/
function store_pagelinks($pagename, $pagelinks) {
global $DBInfo;
$bcache = new Cache_Text('backlinks');
$cache = new Cache_Text('pagelinks');
unset($pagelinks['TwinPages']);
$cur = $cache->fetch($pagename);
if (!is_array($cur)) $cur = array();
$add = array_diff($pagelinks, $cur);
$del = array_diff($cur, $pagelinks);
// merge new backlinks
foreach ($add as $a) {
if (!isset($a[0])) continue;
$bl = $bcache->fetch($a);
if (!is_array($bl)) $bl = array();
$bl = array_merge($bl, array($pagename));
$bl = array_unique($bl);
sort($bl);
$bcache->update($a, $bl);
}
// remove deleted backlinks
foreach ($del as $d) {
if (!isset($d[0])) continue;
$bl = $bcache->fetch($d);
if (!is_array($bl)) $bl = array();
$bl = array_diff($bl, array($pagename));
sort($bl);
$bcache->update($d, $bl);
}
if (!empty($pagelinks))
$cache->update($pagename, $pagelinks);
else
$cache->remove($pagename);
}
/**
* Get pagelinks from the wiki text
*
* @author Won-Kyu Park <wkpark@gmail.com>
*/
function get_pagelinks($formatter, $text) {
// split into chunks
$chunk = preg_split("/({{{
(?:(?:[^{}]+|
{[^{}]+}(?!})|
(?<!{){{1,2}(?!{)|
(?<!})}{1,2}(?!}))|(?1)
)++}}})/x",$text,-1,PREG_SPLIT_DELIM_CAPTURE);
$inline = array(); // save inline nowikis
if (count($chunk) > 1) {
// protect inline nowikis
$nc = '';
$k = 1;
$idx = 1;
foreach ($chunk as $c) {
if ($k % 2) {
$nc.= $c.' ';
}
$k++;
}
$text = $nc;
}
// check wordrule
if (empty($formatter->wordrule)) $formatter->set_wordrule();
preg_match_all("/(".$formatter->wordrule.")/", $text, $match);
$words = array();
foreach ($match[0] as $k=>$v) {
if (preg_match('/^\!/', $v)) continue;
if (preg_match('/^\?/', $v)) {
$words[] = substr($v, 1);
} else if (preg_match('/^\[?wiki:[^`\'\{\]\^\*\(]/', $v) || !preg_match('/^\[?'.$formatter->urls.':/', $v)) {
$extended = false;
$creole = false;
$word = rtrim($v, '`'); // XXX
if (preg_match('/^\[\[(.*)\]\]$/', $word, $m)) {
// MediaWiki/WikiCreole like links
$creole = true;
$word = $m[1];
} else if (preg_match('/^\[(.*)\]$/', $word, $m)) {
$word = $m[1];
}
if (preg_match('/^(wiki:)?/', $word, $m)) {
if (!empty($m[1])) $word = substr($word, 5);
$word = ltrim($word); // ltrim wikiwords
if (preg_match("/^\"([^\"]*)\"\s?/", $word, $m1)) {
$extended = true;
$word = $m1[1];
} else if (!empty($m[1]) and ($p = strpos($word, " ")) !== false) {
$word = substr($word, 0, $p);
}
} else if ($creole and ($p = strpos($word, '|')) !== false) {
$word = substr($word, 0, $p);
}
if (!$extended and empty($formatter->mediawiki_style) and strpos($word, " ") !== false) {
$word = normalize($word);
}
if (preg_match("/^([^\(:]+)(\((.*)\))?$/", $word, $m)) {
if (isset($m[1])) {
$name = $m[1];
} else {
$name = $word;
}
// check macro
$myname = getPlugin($name);
if (!empty($myname)) {
// this is macro
continue;
}
}
$word = strtok($word, '#?'); // trim anchor tag
$words[] = $word;
}
}
return array_values(array_unique($words));
}
/**
* Update redirect cache and it's index
*
* @author Won-Kyu Park <wkpark at gmail.com>
* @param timestamp $timestamp lastmodified time of the cache file
* @return void
*/
function update_redirects($pagename, $redirect, $refresh = false) {
// update #redirect cache
$rd = new Cache_Text('redirect');
$old = $rd->fetch($pagename);
// FIXME for legacy case
if (is_array($old)) $old = $old[0];
if ($old === false && !isset($redirect[0]))
return;
// update invert redirect index
$rds = new Cache_Text('redirects');
if (!$refresh || $old != $redirect) {
// update direct cache
$rd->update($pagename, array($redirect));
$nr = $redirect;
if (($p = strpos($nr, '#')) > 0) {
// get pagename only
//$anchor = substr($nr, $p);
$nr = substr($nr, 0, $p);
}
if (!isset($nr[0])) {
$rd->remove($pagename);
} else if (!preg_match('@^https?://@', $nr)) { // not a URL redirect
// add redirect links
$redirects = $rds->fetch($nr);
if (empty($redirects)) $redirects = array();
$redirects = array_merge($redirects, array($pagename));
$rds->update($nr, $redirects);
}
while ($old != '' and $old != false) {
// get pagename only
if (($p = strpos($old, '#')) > 0) {
//$anchor = substr($old, $p);
$old = substr($old, 0, $p);
}
if ($nr == $old) break; // same redirect check A#s-1 ~ A#s-2 redirects
// delete redirect links
$l = $rds->fetch($old);
if ($l !== false and is_array($l)) {
$redirects = array_diff($l, array($pagename));
if (empty($redirects)) $rds->remove($old);
else $rds->update($old, $redirects);
}
break;
}
}
}
/**
* Checks and sets HTTP headers for conditional HTTP requests
* slightly modified to set $etag separatly by wkpark@kldp.org
*
* @author Simon Willison <swillison@gmail.com>
* @link http://simon.incutio.com/archive/2003/04/23/conditionalGet
* @param timestamp $timestamp lastmodified time of the cache file
* @returns void or exits with previously header() commands executed
*/
function http_need_cond_request($mtime, $last_modified = '', $etag = '') {
// A PHP implementation of conditional get, see
// http://fishbowl.pastiche.org/archives/001132.html
if (empty($last_modified)) // is it timestamp ?
$last_modified = substr(gmdate('r', $mtime), 0, -5).'GMT';
if (empty($etag)) // pseudo etag
$etag = md5($last_modified);
if ($etag[0] != '"')
$etag = '"' . $etag . '"';
// See if the client has provided the required headers
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
// fix broken IEx
$if_modified_since = preg_replace('/;.*$/', '', _stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']));
}else{
$if_modified_since = false;
}
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
$if_none_match = _stripslashes($_SERVER['HTTP_IF_NONE_MATCH']);
}else{
$if_none_match = false;
}
if (!$if_modified_since && !$if_none_match) {
return true;
}
// At least one of the headers is there - check them
while ($if_none_match && $if_none_match != $etag) {
// it is weak ETag ?
if (preg_match('@^W/(.*)@', $if_none_match, $m)) {
if ($m[1] == $etag)
break;
}
return true; // etag is there but doesn't match
}
if ($if_modified_since) {
// calculate time
$mytime = @strtotime( $if_modified_since );
if ( $mtime > $mytime) {
header('X-Check: '.$mtime.' '.$mytime);
return true; // if-modified-since is there but doesn't match
}
}
// Nothing has changed since their last request
return false;
}
/**
* find the extension of given mimetype using the mime.types
*
* @author Won-Kyu Park <wkpark@gmail.com>
*/
function get_extension($mime_types = 'mime.types', $mime) {
if (!file_exists($mime_types)) return 'bin';
$mimetypes = file_get_contents($mime_types);
if (preg_match('@(^'.$mime.'\s+.*$)@m', $mimetypes, $match)) {
$tmp = preg_split('/\s+/', $match[1]);
return $tmp[1];
}
return 'bin';
}
/**
* get hased prefix for given name
*
* @author Won-Kyu Park <wkpark@gmail.com>
*/
function get_hashed_prefix($key, $level = 2) {
$hash = md5($key);
$prefix = '';
for ($i = 0; $i < $level; $i++) {
$prefix.= substr($hash, 0, $i + 1) . '/';
}
return $prefix;
}
/**
* abuse filter wrapper
*/
function call_abusefilter($filter, $action, $params = array()) {
require_once(dirname(__FILE__).'/plugin/abuse/'.$filter.'.php');
$filtername = 'abusefilter_'.$filter;
return $filtername($action, $params);
}
/**
* static content action
*/
function is_static_action($params) {
if (isset($params['action']) and $params['action'] == 'raw')
return true;
// pre defined etag found. force static page
if (isset($params['etag'][0]))
return true;
return false;
}
/**
* Deprecated
*/
function is_mobile() {
global $DBInfo;
if (!empty($DBInfo->mobile_agents)) {
$re = '/'.$DBInfo->mobile_agents.'/i';
} else {
$re = '/android|iphone/i';
}
if (preg_match($re, $_SERVER['HTTP_USER_AGENT']))
return true;
if (!empty($DBInfo->mobile_referer_re) and preg_match($DBInfo->mobile_referer_re, $_SERVER['HTTP_REFERER']))
return true;
return false;
}
/**
* Get the real IP address for proxy
*
* @author Won-Kyu Park <wkpark@gmail.com>
*/
function realIP() {
global $Config;
if (!empty($Config['use_cloudflare']) && !empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
return $_SERVER['HTTP_CF_CONNECTING_IP'];
}
$REMOTE_ADDR = $_SERVER['REMOTE_ADDR'];
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
else if (!empty($_SERVER['HTTP_X_REAL_IP']))
$ip = $_SERVER['HTTP_X_REAL_IP'];
else
return $_SERVER['REMOTE_ADDR'];
if (strpos($ip, ',') === false && $ip == $REMOTE_ADDR)
return $ip;
if (!empty($Config['use_x_forwarded_for'])) {
require_once('lib/clientip.php');
return clientIP();
}
return $_SERVER['REMOTE_ADDR'];
}
/**
* check X-Forwarded-For and get the pass-by IP addresses to log
*
* @author wkpark at kldp.org
*
* @return X-Forwarded-For address list + Remote Address if it needed
*/
function get_log_addr() {
$REMOTE_ADDR = $_SERVER['REMOTE_ADDR'];
if (!empty($Config['use_cloudflare']) && !empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
return $_SERVER['HTTP_CF_CONNECTING_IP'];
}
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) and $REMOTE_ADDR != $_SERVER['HTTP_X_FORWARDED_FOR']) {
// XFF contains the REMOTE_ADDR ?
$xff = str_replace(' ', '', $_SERVER['HTTP_X_FORWARDED_FOR']);
$tmp = explode(',', $xff);
// Real IP == REMOTE_ADDR case. (mod_remoteip etc.)
if ($tmp[0] == $REMOTE_ADDR)
return $REMOTE_ADDR;
require_once('lib/clientip.php');
$filtered = clientIP(false);
$tmp = explode(',', $filtered);
$last = array_pop($tmp);
if ($last == $REMOTE_ADDR)
$REMOTE_ADDR = $filtered;
else
// append REMOTE_ADDR
$REMOTE_ADDR = $filtered.','.$REMOTE_ADDR;
}
return $REMOTE_ADDR;
}
/**
* get default cols of textarea
*
*/
function get_textarea_cols($is_mobile = false) {
$COLS_MSIE = 80;
$COLS_OTHER = 85;
if (preg_match('/MSIE/', $_SERVER['HTTP_USER_AGENT'])) {
$cols = $COLS_MSIE;
} else if ($is_mobile) {
$cols = 30;
} else {
$cols = $COLS_OTHER;
}
return $cols;
}
/**
* get description of content.
* strip wikitags etc.
*
* @author wkpark at gmail.com
*
*/
function get_description($raw) {
$baserule = array(
"/(?<!')'''((?U)(?:[^']|(?<!')'(?!')|'')*)?'''(?!')/",
"/(?<!')''((?:[^']|[^']'(?!'))*)''(?!')/",
"/`(?<!\s)(?!`)([^`']+)(?<!\s)'(?=\s|$)/",
"/`(?<!\s)(?U)(.*)(?<!\s)`/",
"/^(={4,})$/",
"/,,([^,]{1,40}),,/",
"/\^([^ \^]+)\^(?=\s|$)/",
"/\^\^(?<!\s)(?!\^)(?U)(.+)(?<!\s)\^\^/",
"/__(?<!\s)(?!_)(?U)(.+)(?<!\s)__/",
"/--(?<!\s)(?!-)(?U)(.+)(?<!\s)--/",
"/~~(?<!\s)(?!~)(?U)(.+)(?<!\s)~~/",
);
// check summary
$chunks = preg_split('@^((?:={1,2})\s+.*\s+(?:={1,2}))\s*$@m', $raw, -1,
PREG_SPLIT_OFFSET_CAPTURE | PREG_SPLIT_DELIM_CAPTURE);
if (sizeof($chunks) > 2 && strlen($chunks[2][0]) > 20) {
// get the first == blah blah == section
$raw = $chunks[2][0];
}
$lines = explode("\n", $raw);
// trash PIs
for ($i = 0; $i < sizeof($lines); $i++) {
if ($lines[$i][0] == '#')
continue;
break;
}
$out = '';
for (;$i < sizeof($lines); $i++) {
// FIXME
$line = preg_replace('@^(={1,6})\s+(.*)\s+(?1)\s*$@', '\\2', $lines[$i]);
$line = preg_replace('@</?[^>]+>@', '', $line); // strip HTML like tags
$line = preg_replace('@^((?:>\s*)+)@', '', $line); // strip quotes
$line = preg_replace('@(\|{2})+@', '', $line); // strip table tags
$line = preg_replace($baserule, '\\1', $line); // strip all base tags
$out.= trim($line).' ';
}
$out = trim($out);
if (empty($out))
return false;
return $out;
}
function get_title($page,$title='') {
global $DBInfo;
if (!empty($DBInfo->use_titlecache)) {
$cache = new Cache_text('title');
$title = $cache->fetch($page);
$title = $title ? $title : $page;
} else
$title=$title ? $title: $page;
#return preg_replace("/((?<=[a-z0-9]|[B-Z]{2}|A)([A-Z][a-z]|A))/"," \\1",$title);
if (empty($DBInfo->use_camelcase)) return $title;
if ($DBInfo->title_rule)
return preg_replace('/'.$DBInfo->title_rule.'/'," \\1",$title);
return preg_replace("/((?<=[a-z0-9]|[B-Z]{2})([A-Z][a-z]))/"," \\1",$title);
}
function _mask_hostname($addr,$opt=1,$mask='&loz;') {
$tmp=explode('.',$addr);
switch($sz=sizeof($tmp)) {
case 4:
if ($opt >= 1)
$tmp[$sz-1]=str_repeat($mask,strlen($tmp[$sz-1]));
if ($opt == 2)
$tmp[$sz-2]=str_repeat($mask,strlen($tmp[$sz-2]));
else if ($opt == 3)
$tmp[$sz-3]=str_repeat($mask,strlen($tmp[$sz-3]));
break;
default:
$tmp[0]=str_repeat($mask,strlen($tmp[0]));
}
return implode('.',$tmp);
}
function _load_php_vars($filepath, $vars=array())
{
# foreach ($vars as $key=>$val) $$key=$val;
# unset($key,$val,$vars);
extract($vars);
unset($vars);
ob_start();
include $filepath;
unset($filepath);
$vars=get_defined_vars();
ob_end_clean();
return $vars;
}
// from php.net
//
// It seems that the best solution would be to use HMAC-MD5.
// An implementation of HMAC-SHA1 was posted by mark on 30-Jan-2004 02:28
// as a user comment to sha1() function
// (-> http://php.net/manual/function.sha1.php#39492).
// Here's how it would look like
// (some other optimizations/modifications are included as well):
// Calculate HMAC according to RFC2104
// http://www.ietf.org/rfc/rfc2104.txt
//
function hmac($key, $data, $hash = 'md5', $blocksize = 64) {
if (strlen($key)>$blocksize) {
$key = pack('H*', $hash($key));
}
$key = str_pad($key, $blocksize, chr(0));
$ipad = str_repeat(chr(0x36), $blocksize);
$opad = str_repeat(chr(0x5c), $blocksize);
return $hash(($key^$opad) . pack('H*', $hash(($key^$ipad) . $data)));
}
/**
* return an obfuscated email address in line from dokuwiki
*
* @author Harry Fuecks <hfuecks@gmail.com>
* @author Christopher Smith <chris@jalakai.co.uk>
*/
function email_guard($email,$mode='hex') {
switch ($mode) {
case 'visible' :
$obfuscate = array('@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] ');
return strtr($email, $obfuscate);
case 'hex' :
$encode = '';
$sz=strlen($email);
for ($i=0; $i<$sz; $i++)
$encode .= '&#x' . bin2hex($email{$i}).';';
return $encode;
case 'none' :
default :
return $email;
}
}
// Remember to initialize MT (using mt_srand() ) if required
function pw_encode($password) {
$seed = substr('00' . dechex(mt_rand()), -3) .
substr('00' . dechex(mt_rand()), -3) .
substr('0' . dechex(mt_rand()), -2);
return hmac($seed, $password, 'md5', 64) . $seed;
}
function getTicket($seed,$extra='',$size=0,$flag=0) {
global $DBInfo, $Config;
# make the site specific ticket based on the variables in the config.php
if (empty($Config))
$configs = getConfig("config.php");
else
$configs = $Config;
$siteticket = '';
foreach ($configs as $config) {
if (is_array($config)) $siteticket.=md5(base64_encode(serialize($config)));
else $siteticket.=md5($config);
}
if ($size>3) {
$ticket= md5($siteticket.$seed.$extra);
$n=0;$passwd='';
for ($i=0,$n=0;$n<$size;$i++) {
$j=ord($ticket[$i])-48;
if (0<=$j and $j<=9) {
$passwd.="$j"; $n++;
}
}
return $passwd;
}
if ($flag)
# change user's ticket
return md5($siteticket.$seed.$extra.time());
return md5($siteticket.$seed.$extra);
}
function getTokens($string, $params = null) {
$words = array();
// strip macros, entities
$raw = preg_replace("/&[^;\s]+;|\[\[[^\[]+\]\]/", ' ', $string);
// strip comments
$raw = preg_replace("/^##.*$/m", ' ', $raw);
// strip puncts.
$raw = preg_replace("/([;\"',`\\\\\/\.:@#\!\?\$%\^&\*\(\)\{\}\[\]\~\-_\+=\|<>])/",
' ', strip_tags($raw));
// split wiki words
$raw = preg_replace("/((?<=[a-z0-9]|[B-Z]{2})([A-Z][a-z]))/", " \\1", $raw);
$raw = strtolower($raw);
$raw = preg_replace("/\b/", ' ', $raw);
//$raw=preg_replace("/\b([0-9a-zA-Z'\"])\\1+\s*/",' ',$raw);
// split hangul syllable bloundries
$raw = preg_replace('/([\x{AC00}-\x{D7AF}]+)/u', " \\1 ", $raw);
// split ASCII punctuation boundries U+00A0 ~ U+00BF
// split General punctuation boundries U+2000 ~ U+206F
// split CJK punctuation boundries U+3001 ~ U+303F
$words = preg_split("/[\s\n\x{A0}-\x{BF}\x{3000}\x{3001}-\x{303F}\x{2000}-\x{206F}]+/u", trim($raw));
$words = array_unique($words);
asort($words);
return $words;
}
function log_referer($referer,$page) {
global $DBInfo;
if (!$referer) return;
$ignore=array("http://".$_SERVER['HTTP_HOST']);
foreach ($ignore as $str)
if (($p=strpos($referer,$str)) !== false) return;
if (!file_exists($DBInfo->cache_dir."/referer")) {
umask(000);
mkdir($DBInfo->cache_dir."/referer",0777);
umask(011);
touch($DBInfo->cache_dir."/referer/referer.log");
}
$fp=fopen($DBInfo->cache_dir."/referer/referer.log",'a');
$date=gmdate("Y-m-d\TH:i:s",time());
fwrite($fp,"$date\t$page\t$referer\n");
fclose($fp);
}
function toutf8($uni) {
$utf[0]=0xe0 | ($uni >> 12);
$utf[1]=0x80 | (($uni >> 6) & 0x3f);
$utf[2]=0x80 | ($uni & 0x3f);
return chr($utf[0]).chr($utf[1]).chr($utf[2]);
}
function load_ruleset($ruleset_file) {
require_once 'lib/ruleset.php';
// cache settings
$settings = new Cache_text('settings', array('depth'=>0));
// get cached ruleset
if (!($ruleset = $settings->fetch('ruleset'))) {
$deps = array();
$rdeps = array($ruleset_file);
$deps['deps'] = &$rdeps;
$validator = array(
'blacklist'=>'ip_ruleset',
'whitelist'=>'ip_ruleset',
'trustedproxy'=>'ip_ruleset',
'internalproxy'=>'ip_ruleset',
);
$ruleset = parse_ruleset($ruleset_file, $validator, $deps);
// somewhat bigger blacklist ?
if (isset($ruleset['blacklist']) && count($ruleset['blacklist']) > 50) {
require_once (dirname(__FILE__).'/lib/checkip.php');
$ranges = make_ip_ranges($ruleset['blacklist']);
// save blacklist separately
$settings->update('blacklist', $ruleset['blacklist']);
// unset blacklist array
unset($ruleset['blacklist']);
// set blacklist.ranges array
$ruleset['blacklist.ranges'] = $ranges;
}
$settings->update('ruleset', $ruleset, 0, $deps);
}
return $ruleset;
}
function is_allowed_robot($rules, $name) {
global $Config;
if (in_array($name, $rules))
return true;
$rule = implode('|', array_map('preg_quote', $rules));
if (preg_match('!'.$rule.'!i', $name))
return true;
return false;
}
function getSmileys() {
global $DBInfo;
static $smileys = null;
if ($smileys) return $smileys;
if (!empty($DBInfo->smiley))
include_once($DBInfo->smiley.'.php');
# set smileys
if (!empty($DBInfo->shared_smileymap) and file_exists($DBInfo->shared_smileymap)) {
$myicons=array();
$lines=file($DBInfo->shared_smileymap);
foreach ($lines as $l) {
if ($l[0] != ' ') continue;
if (!preg_match('/^ \*\s*([^ ]+)\s(.*)$/',$l,$m)) continue;
$name=_preg_escape($m[1]);
if (($pos = strpos($m[2], ' ')) !== false)
list($img,$extra)=explode(' ',$m[2]);
else
$img = trim($m[2]);
if (preg_match('/^(http|ftp):.*\.(png|jpg|jpeg|gif)/',$img)) {
$myicons[$name]=array(16,16,0,$img);
} else {
continue;
}
}
$smileys=array_merge($smileys,$myicons);
}
return $smileys;
}
class UserDB {
var $users=array();
function UserDB($conf) {
if (is_array($conf)) {
$this->user_dir = $conf['user_dir'];
$this->strict = $conf['login_strict'];
if (!empty($conf['user_class']))
$this->user_class = 'User_'.$conf['user_class'];
else
$this->user_class = 'WikiUser';
} else {
$this->user_dir=$conf->user_dir;
$this->strict = $conf->login_strict;
if (!empty($conf->user_class))
$this->user_class = 'User_'.$conf->user_class;
else
$this->user_class = 'WikiUser';
}
}
function _pgencode($m) {
// moinmoin 1.0.x style internal encoding
return '_'.sprintf("%02s", strtolower(dechex(ord(substr($m[1],-1)))));
}
function _id_to_key($id) {
return preg_replace_callback("/([^a-z0-9]{1})/i",
array($this, '_pgencode'), $id);
}
function _key_to_id($key) {
return rawurldecode(strtr($key,'_','%'));
}
function getUserList($options = array()) {
if ($this->users) return $this->users;
$type='';
if ($options['type'] == 'del') $type = 'del-';
elseif ($options['type'] == 'wait') $type = 'wait-';
// count users
$handle = opendir($this->user_dir);
$j = 0;
while ($file = readdir($handle)) {
if (is_dir($this->user_dir."/".$file)) continue;
if (preg_match('/^'.$type.'wu\-([^\.]+)$/', $file,$match)) {
$j++;
}
}
closedir($handle);
if (is_array($options['retval']))
$options['retval']['count'] = $j;
$offset = !empty($options['offset']) ? intval($options['offset']) : 0;
$limit = !empty($options['limit']) ? intval($options['limit']) : 1000;
$q = !empty($options['q']) ? trim($options['q']) : '[^\.]+';
// Anonymous user with editing information
$rawid = false;
if (preg_match('/^(\d{1,3}\.){3}\d{1,3}$/', $q))
$rawid = true;
$users = array();
if (!empty($options['q'])) {
// search exact matched user
if (($mtime = $this->_exists($q, $type != '')) !== false) {
$users[$q] = $mtime;
return $users;
}
}
$handle = opendir($this->user_dir);
$j = 0;
while ($file = readdir($handle)) {
if (is_dir($this->user_dir."/".$file)) continue;
if (preg_match('/^'.$type.'wu\-(.*)$/', $file, $match)) {
if ($offset > 0) {
$offset--;
continue;
}
if (!$rawid)
$id = $this->_key_to_id($match[1]);
else
$id = $match[1];
if (!empty($q) and !preg_match('/'.$q.'/i', $id)) continue;
$users[$id] = filemtime($this->user_dir.'/'.$file);
$j++;
if ($j >= $limit)
break;
}
}
closedir($handle);
$this->users=$users;
return $users;
}
function getPageSubscribers($pagename) {
$users=$this->getUserList();
$subs=array();
foreach ($users as $id) {
$usr=$this->getUser($id);
if ($usr->hasSubscribePage($pagename)) $subs[]=$usr->info['email'];
}
return $subs;
}
function addUser($user, $options = array()) {
if ($this->_exists($user->id) || $this->_exists($user->id, true))
return false;
$this->saveUser($user, $options);
return true;
}
function isNotUser($user) {
if ($this->_exists($user->id) || $this->_exists($user->id, true))
return false;
return true;
}
function saveUser($user,$options=array()) {
$config = array("regdate",
"email",
"name",
"nick",
"home",
"password",
"last_login",
"last_updated",
"login_fail",
"remote",
"login_success",
"ticket",
"eticket",
"idtype",
"npassword",
"nticket",
"edit_count",
"edit_add_lines",
"edit_del_lines",
"edit_add_chars",
"edit_del_chars",
"groups", // user groups
"strike",
"strike_total",
"strikeout",
"strikeout_total",
"join_agreement",
"join_agreement_version",
"tz_offset",
"avatar",
"theme",
"css_url",
"bookmark",
"scrapped_pages",
"subscribed_pages",
"quicklinks",
"language", // not used
"datetime_fmt", // not used
"wikiname_add_spaces", // not used
"status", // user status for IP user
);
$date=gmdate('Y/m/d H:i:s', time());
$data="# Data saved $date\n";
if ($user->id == 'Anonymous') {
if (!empty($user->info['remote']))
$wu = 'wu-'.$user->info['remote'];
else
$wu = 'wu-'.$_SERVER['REMOTE_ADDR'];
} else {
$wu = 'wu-'.$this->_id_to_key($user->id);
if (!empty($options['suspended'])) $wu = 'wait-'.$wu;
}
// new user ?
if (!file_exists("$this->user_dir/$wu") && empty($user->info['regdate'])) {
$user->info['regdate'] = $date;
}
$user->info['last_updated'] = $date;
if (!empty($user->ticket))
$user->info['ticket']=$user->ticket;
ksort($user->info);
foreach ($user->info as $k=>$v) {
if (in_array($k, $config)) {
$data.= $k.'='.$v."\n";
} else {
// undefined local config
if ($k[0] != '_')
$k = '_'.$k;
$data.= $k.'='.$v."\n";
}
}
$fp=fopen("$this->user_dir/$wu","w+");
if (!is_resource($fp))
return;
fwrite($fp,$data);
fclose($fp);
}
function _exists($id, $suspended = false) {
if (empty($id) || $id == 'Anonymous') {
if ($suspended) return false;
$wu = 'wu-'.$_SERVER['REMOTE_ADDR'];
} else if (preg_match('/^(\d{1,3}\.){3}\d{1,3}$/', $id)) {
if ($suspended) return false;
$wu = 'wu-'.$id;
} else {
$prefix = $suspended ? 'wait-wu-' : 'wu-';
$wu = $prefix . $this->_id_to_key($id);
}
if (file_exists($this->user_dir.'/'.$wu))
return filemtime($this->user_dir.'/'.$wu);
if ($suspended) {
// deletede user ?
$prefix = 'del-wu-';
$wu = $prefix . $this->_id_to_key($id);
if (file_exists($this->user_dir.'/'.$wu))
return filemtime($this->user_dir.'/'.$wu);
}
return false;
}
function checkUser(&$user) {
if (!empty($user->info['ticket']) and $user->info['ticket'] != $user->ticket) {
if ($this->strict > 0)
$user->id='Anonymous';
return 1;
}
return 0;
}
function getInfo($id, $suspended = false) {
if (empty($id) || $id == 'Anonymous') {
$wu = 'wu-'.$_SERVER['REMOTE_ADDR'];
} else if (preg_match('/^(\d{1,3}\.){3}\d{1,3}$/', $id)) {
$wu = 'wu-'.$id;
} else {
$prefix = $suspended ? 'wait-wu-' : 'wu-';
$wu = $prefix . $this->_id_to_key($id);
}
if (file_exists($this->user_dir.'/'.$wu)) {
$data = file($this->user_dir.'/'.$wu);
} else {
return array();
}
$info=array();
foreach ($data as $line) {
#print "$line<br/>";
if ($line[0]=="#" and $line[0]==" ") continue;
$p=strpos($line,"=");
if ($p === false) continue;
$key=substr($line,0,$p);
$val=substr($line,$p+1,-1);
$info[$key]=$val;
}
return $info;
}
function getUser($id, $suspended = false) {
$user = new WikiUser($id);
$info = $this->getInfo($id, $suspended);
$user->info = $info;
// read group infomation
if (!empty($info['groups'])) {
$groups = explode(',', $info['groups']);
// already has group information ?
if (!empty($user->groups))
$user->groups = array_merge($user->groups, $groups);
else
$user->groups = $groups;
}
// set default timezone
if (isset($info['tz_offset']))
$user->tz_offset = $info['tz_offset'];
else
$user->info['tz_offset'] = date('Z');
$user->ticket = !empty($info['ticket']) ? $info['ticket'] : null;
return $user;
}
function delUser($id) {
$id = trim($id);
if (empty($id) || $id == 'Anonymous')
return false;
if (preg_match('/^(\d{1,3}\.){3}\d{1,3}$/', $id)) {
// change user status
$info = $this->getInfo($id);
$user = new WikiUser($id);
$info['status'] = 'deleted';
$info['remote'] = $id;
$user->info = $info;
$this->saveUser($user);
return true;
} else {
$key = $this->_id_to_key($id);
$u = 'wu-'. $key;
}
$du = 'del-'.$u;
if ($this->_exists($id)) {
return rename($this->user_dir.'/'.$u,$this->user_dir.'/'.$du);
} else if ($this->_exists($id, true)) {
// delete suspended user
$u = 'wait-'. $u;
return rename($this->user_dir.'/'.$u, $this->user_dir.'/'.$du);
} if (file_exists($this->user_dir.'/'.$du)) {
// already deleted
return true;
}
return false;
}
function activateUser($id, $suspended = false) {
$id = trim($id);
if (empty($id) || $id == 'Anonymous')
return false;
if (preg_match('/^(\d{1,3}\.){3}\d{1,3}$/', $id)) {
// activate or suspend IP user
$info = $this->getInfo($id);
$user = new WikiUser($id);
if ($suspended)
$info['status'] = 'suspended';
else
unset($info['status']);
$info['remote'] = $id;
$user->info = $info;
$this->saveUser($user);
return true;
} else {
$u = $wu = 'wu-'. $this->_id_to_key($id);
}
$states = array('wait', 'del');
if ($suspended) {
$wu = 'wait-'.$u;
$states = array('del', '');
}
if (file_exists($this->user_dir.'/'.$wu)) return true;
foreach ($states as $state) {
if (!empty($state))
$uu = $state.'-'.$u;
else
$uu = $u;
if (file_exists($this->user_dir.'/'.$uu))
return rename($this->user_dir.'/'.$uu, $this->user_dir.'/'.$wu);
}
return false;
}
}
class WikiUser {
var $cookie_expires = 2592000; // 60 * 60 * 24 * 30; // default 30 days
function WikiUser($id="") {
global $Config;
if (!empty($Config['cookie_expires']))
$this->cookie_expires = $Config['cookie_expires'];
if ($id && $id != 'Anonymous') {
$this->setID($id);
return;
}
$id = '';
if (isset($_COOKIE['MONI_ID'])) {
$this->ticket=substr($_COOKIE['MONI_ID'],0,32);
$id=urldecode(substr($_COOKIE['MONI_ID'],33));
}
$ret = $this->setID($id);
if ($ret) $this->getGroup();
$this->css=isset($_COOKIE['MONI_CSS']) ? $_COOKIE['MONI_CSS']:'';
$this->theme=isset($_COOKIE['MONI_THEME']) ? $_COOKIE['MONI_THEME']:'';
$this->bookmark=isset($_COOKIE['MONI_BOOKMARK']) ? $_COOKIE['MONI_BOOKMARK']:'';
$this->trail=isset($_COOKIE['MONI_TRAIL']) ? _stripslashes($_COOKIE['MONI_TRAIL']):'';
$this->tz_offset=isset($_COOKIE['MONI_TZ']) ?_stripslashes($_COOKIE['MONI_TZ']):'';
$this->nick=isset($_COOKIE['MONI_NICK']) ?_stripslashes($_COOKIE['MONI_NICK']):'';
$this->verified_email = isset($_COOKIE['MONI_VERIFIED_EMAIL']) ? _stripslashes($_COOKIE['MONI_VERIFIED_EMAIL']) : '';
if ($this->tz_offset =='') $this->tz_offset=date('Z');
}
// get ACL group
function getGroup() {
global $DBInfo;
if ($this->id == 'Anonymous') return;
// get groups
if (isset($DBInfo->security) && method_exists($DBInfo->security, 'get_acl_group'))
$this->groups = $DBInfo->security->get_acl_group($this->id);
}
// check group Information
function checkGroup() {
global $DBInfo;
if ($this->id == 'Anonymous') return;
// a user of members
$this->is_member = in_array($this->id, $DBInfo->members);
// check ACL admin groups
if (!empty($DBInfo->acl_admin_groups)) {
foreach ($this->groups as $g) {
if (in_array($g, $DBInfo->acl_admin_groups)) {
$this->is_member = true;
break;
}
}
}
}
function setID($id) {
if ($id and $this->checkID($id)) {
$this->id=$id;
return true;
}
$this->id='Anonymous';
$this->ticket='';
return false;
}
function getID($name) {
$name = trim($name);
if (strpos($name, ' ') !== false) {
$dum=explode(" ",$name);
$new=array_map("ucfirst",$dum);
return implode('', $new);
}
return $name;
}
function setCookie() {
global $Config;
if ($this->id == "Anonymous") return false;
if (($sessid = session_id()) == '') {
// no session used. IP dependent.
$ticket = getTicket($this->id, $_SERVER['REMOTE_ADDR']);
} else {
// session enabled case. use session.
$ticket = md5($this->id.$sessid);
}
$this->ticket=$ticket;
# set the fake cookie
$_COOKIE['MONI_ID']=$ticket.'.'.urlencode($this->id);
if (!empty($this->info['nick'])) $_COOKIE['MONI_NICK']=$this->info['nick'];
$domain = '';
if (!empty($Config['cookie_domain'])) {
$domain = '; Domain='.$Config['cookie_domain'];
} else {
$domain = '; Domain='.$_SERVER['SERVER_NAME'];
}
if (!empty($Config['cookie_path']))
$path = '; Path='.$Config['cookie_path'];
else
$path = '; Path='.dirname(get_scriptname());
return "Set-Cookie: MONI_ID=".$ticket.'.'.urlencode($this->id).
'; expires='.gmdate('l, d-M-Y H:i:s', time() + $this->cookie_expires).' GMT '.$path.$domain;
}
function unsetCookie() {
global $Config;
# set the fake cookie
$_COOKIE['MONI_ID']="Anonymous";
$domain = '';
if (!empty($Config['cookie_domain'])) {
$domain = '; Domain='.$Config['cookie_domain'];
} else {
$domain = '; Domain='.$_SERVER['SERVER_NAME'];
}
if (!empty($Config['cookie_path']))
$path = '; Path='.$Config['cookie_path'];
else
$path = '; Path='.dirname(get_scriptname());
return "Set-Cookie: MONI_ID=".$this->id."; expires=Tuesday, 01-Jan-1999 12:00:00 GMT; Path=".$path.$domain;
}
function setPasswd($passwd,$passwd2="",$rawmode=0) {
if (!$passwd2) $passwd2=$passwd;
$ret=$this->validPasswd($passwd,$passwd2);
if ($ret > 0) {
if ($rawmode)
$this->info['password']=$passwd;
else
$this->info['password']=crypt($passwd);
}
# else
# $this->info[password]="";
return $ret;
}
function checkID($id) {
$SPECIAL='\\,;\$\|~`#\+\*\?!"\'\?%&\(\)\[\]\{\}\=';
preg_match("/[$SPECIAL]/",$id,$match);
if (!$id || $match)
return false;
if (preg_match('/^\d/', $id)) return false;
return true;
}
function checkPasswd($passwd,$chall=0) {
if (strlen($passwd) < 3)
return false;
if ($chall) {
if (hmac($chall,$this->info['password']) == $passwd)
return true;
} else {
if (crypt($passwd,$this->info['password']) == $this->info['password'])
return true;
}
return false;
}
function validPasswd($passwd,$passwd2) {
if (strlen($passwd)<4)
return 0;
if ($passwd2!="" and $passwd!=$passwd2)
return -1;
$LOWER='abcdefghijklmnopqrstuvwxyz';
$UPPER='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$DIGIT='0123456789';
$SPECIAL=',.;:-_#+*?!"\'?%&/()[]{}\=~^|$@`';
$VALID=$LOWER.$UPPER.$DIGIT.$SPECIAL;
$ok=0;
for ($i=0;$i<strlen($passwd);$i++) {
if (strpos($VALID,$passwd[$i]) === false)
return -2;
if (strpos($LOWER,$passwd[$i]))
$ok|=1;
if (strpos($UPPER,$passwd[$i]))
$ok|=2;
if (strpos($DIGIT,$passwd[$i]))
$ok|=4;
if ($ok==7 and strlen($passwd)>10) return $ok+1;
// sufficiently safe password
if (strpos($SPECIAL,$passwd[$i]))
$ok|=8;
}
return $ok;
}
function hasSubscribePage($pagename) {
if (!$this->info['email'] or !$this->info['subscribed_pages']) return false;
$page_list=_preg_search_escape($this->info['subscribed_pages']);
if (!trim($page_list)) return false;
$page_lists=explode("\t",$page_list);
$page_rule='^'.join("$|^",$page_lists).'$';
if (preg_match('/('.$page_rule.')/',$pagename))
return true;
return false;
}
}
function macro_EditText($formatter,$value,$options) {
global $DBInfo;
# simple == 1 : do not use EditTextForm, simple == 2 : do not use GUI/Preview
$has_form = false;
$form = '';
if (empty($options['simple']) or $options['simple']!=1) {
if (!empty($DBInfo->editform) and file_exists($DBInfo->editform)) {
$form = file_get_contents($DBInfo->editform);
} else if ($DBInfo->hasPage('EditTextForm')) {
$p = $DBInfo->getPage('EditTextForm');
$form = $p->get_raw_body();
}
}
$tmpls = '';
if (isset($form[0])) {
$form=preg_replace('/\[\[EditText\]\]/i','#editform',$form);
ob_start();
$opi=$formatter->pi; // save pi
$formatter->pi = array('#linenum'=>0); // XXX override pi
$save = $formatter->auto_linebreak;
$formatter->auto_linebreak = 0;
$formatter->send_page("#format wiki\n".rtrim($form),$options);
$formatter->auto_linebreak = $save;
$formatter->pi=$opi; // restore pi
$form= ob_get_contents();
ob_end_clean();
preg_match('@(</form>)@i', $form, $m);
if (isset($options['has_form']))
$has_form = &$options['has_form'];
if (isset($m[1])) $has_form = true;
$options['tmpls'] = &$tmpls;
$editform= macro_Edit($formatter,'nohints,nomenu',$options);
$new=str_replace("#editform",$editform,$form); // XXX
if ($form == $new) $form.=$editform;
else $form=$new;
} else {
$form = macro_Edit($formatter,$value,$options);
}
$js = '';
$css = '';
if (empty($DBInfo->edit_with_sidebar))
$sidebar_style="#wikiSideMenu { display: none; }\n";
if ($has_form and !empty($DBInfo->use_jsbuttons)) {
$css=<<<CSS
<style type='text/css'>
/*<![CDATA[*/
#mycontent input.save-button { display: none; }
#mycontent input.preview-button { display: none; }
input.save-button { display: none; }
$sidebar_style
/*]]>*/
</style>
CSS;
$js=<<<JS
<script type='text/javascript'>
/*<![CDATA[*/
function submit_all_forms() {
var form = document.getElementById('editform'); // main edit form
var all = document.getElementById('all-forms');
var all_forms = all.getElementsByTagName('form'); // all extra forms
for (var i=0; i < all_forms.length; i++) {
if (all_forms[i] == form) continue;
if (all_forms[i].encoding == "multipart/form-data" || all_forms[i].enctype == "multipart/form-data") {
form.encoding = "multipart/form-data";
form.encoding = "multipart/form-data";
}
for (var j=0; j < all_forms[i].elements.length; j++) {
if (all_forms[i].elements[j].type == 'button' || all_forms[i].elements[j].type == 'submit') continue;
if (all_forms[i].elements[j].name == 'action' || all_forms[i].elements[j].name == '') continue;
var newopt = all_forms[i].elements[j];
//newopt.setAttribute('style', 'display:none');
form.appendChild(newopt);
}
}
form.elements['button_preview'].value = '';
form.submit();
}
function check_uploadform(obj) {
var form = document.getElementById('editform'); // main edit form
var all = document.getElementById('all-forms');
var all_forms = all.getElementsByTagName('form'); // all extra forms
for (var i=0; i < all_forms.length; i++) {
if (all_forms[i].encoding == "multipart/form-data" || all_forms[i].enctype == "multipart/form-data") {
for (var j=0; j < all_forms[i].elements.length; j++) {
if (all_forms[i].elements[j].type == 'file' && all_forms[i].elements[j].value != '') {
alert("Please upload your files first!");
return;
}
}
}
}
if (obj.name != "") {
var newopt = document.createElement('input');
newopt.setAttribute('name', obj.name);
newopt.setAttribute('value','dummy');
newopt.setAttribute('type','hidden');
form.appendChild(newopt);
}
form.submit();
}
/*]]>*/
</script>\n
JS;
} else if (!empty($sidebar_style)) {
$css=<<<CSS
<style type='text/css'>
/*<![CDATA[*/
$sidebar_style
/*]]>*/
</style>\n
CSS;
}
if (!empty($DBInfo->use_jsbuttons)) {
$js.= <<<JS
<script data-cfasync="false" type='text/javascript'>
/*<![CDATA[*/
function init_editor() {
var form = document.getElementById('editform'); // main edit form
if (form.elements['button_preview']) {
var save_onclick = form.elements['button_preview'].onclick;
form.elements['button_preview'].onclick = function(ev) {
try { save_onclick(ev); } catch(e) {};
return submit_preview(ev);
};
if (form.elements['button_changes'])
form.elements['button_changes'].onclick = function(ev) {
return submit_preview(ev);
};
}
}
function submit_preview(e) {
e = e || window.event;
var form = document.getElementById('editform'); // main edit form
var textarea = form.getElementsByTagName('textarea')[0];
var wikitext = textarea.value;
var action = 'markup';
var datestamp = form.elements['datestamp'].value;
var section = form.elements['section'] ? form.elements['section'].value : null;
// preview
var toSend = 'action=markup/ajax&preview=1' +
'&value=' + encodeURIComponent(wikitext);
var location = self.location + '';
var markup = HTTPPost(location, toSend);
// set preview
var preview = document.getElementById('wikiPreview');
preview.style.display = 'block';
preview.innerHTML = markup;
// get diffpreview
var diffview = document.getElementById('wikiDiffPreview');
var node = e.target || e.srcElement;
if (node.name == "button_changes") {
var toSend = 'action=diff/ajax' +
'&value=' + encodeURIComponent(wikitext) + '&rev=' + datestamp;
if (section)
toSend+= '&section=' + section;
var diff = HTTPPost(location, toSend);
if (!diffview) {
diffview = document.createElement('div');
diffview.setAttribute('id', 'wikiDiffPreview');
preview.parentNode.insertBefore(diffview, preview);
}
if (diffview) {
diffview.style.display = 'block';
diffview.innerHTML = diff;
}
} else {
if (diffview) {
diffview.style.display = 'none';
diffview.innerHTML = '';
}
}
return false;
}
(function(){
// onload
var oldOnload = window.onload;
window.onload = function() {
try { oldOnload(); } catch(e) {};
init_editor();
};
})();
/*]]>*/
</script>\n
JS;
}
return $css.$js.'<div id="all-forms">'.$form.'</div>'.$tmpls;
}
function do_edit($formatter,$options) {
global $DBInfo;
if (!$DBInfo->security->writable($options)) {
$formatter->preview=1;
$options['msg'] = _("You are not allowed to edit this page !");
}
$formatter->send_header("",$options);
$sec = '';
if (!empty($options['section']))
$sec=' (Section)';
$options['msgtype'] = isset($options['msgtype']) ? $options['msgtype'] : 'warn';
$formatter->send_title(sprintf(_("Edit %s"),$options['page']).$sec,"",$options);
//print '<div id="editor_area">'.macro_EditText($formatter,$value,$options).'</div>';
$has_form = false;
$options['has_form'] = &$has_form;
$options['comment'] = ''; // do not accept comment from _GET[] ?action=edit&comment=blahblah
$value = '';
echo macro_EditText($formatter,$value,$options);
echo $formatter->get_javascripts();
if ($DBInfo->use_wikiwyg>=2) {
$js=<<<JS
<script type='text/javascript'>
/*<![CDATA[*/
sectionEdit(null,true,null);
/*]]>*/
</script>
JS;
if (!$DBInfo->hasPage($options['page'])) print $js;
else {
$pi=$formatter->page->get_instructions($dum);
if (in_array($pi['#format'],array('wiki','monimarkup')) )
print $js;
}
}
if ($has_form and !empty($DBInfo->use_jsbuttons)) {
$msg = _("Save");
$onclick=' onclick="submit_all_forms()"';
$onclick1=' onclick="check_uploadform(this)"';
echo "<div id='save-buttons'>\n";
echo "<button type='button'$onclick tabindex='10'><span>$msg</span></button>\n";
echo "<button type='button'$onclick1 tabindex='11' name='button_preview' value='1'><span>".
_("Preview").'</span></button>';
if ($formatter->page->exists())
echo "\n<button type='button'$onclick1 tabindex='12' name='button_changes' value='1'><span>".
_("Show changes").'</span></button>';
if (!empty($formatter->preview))
echo ' '.$formatter->link_to('#preview',_("Skip to preview"),' class="preview-anchor"');
echo "</div>\n";
}
echo "<div id='wikiDiffPreview' style='display:none;'>\n</div>\n";
echo "<div id='wikiPreview' style='display:none;'>\n</div>\n";
$formatter->send_footer('',$options);
}
function ajax_edit($formatter,$options) {
global $DBInfo;
if (!$DBInfo->security->writable($options)) {
$formatter->preview=0;
return ajax_invalid($formatter,$options);
}
if ($options['section'])
$sec=' (Section)';
$options['simple']=1;
$options['nohints']=1;
$options['nomenu']=1;
$options['nocategories']=1;
$options['noresizer']=1;
$options['rows']=12;
$formatter->header('Content-type:text/html;charset='.$DBInfo->charset);
print macro_EditText($formatter,$value,$options);
}
function _get_sections($body,$lim=5) {
$tmp = preg_split("/({{{
(?:(?:[^{}]+|
{[^{}]+}(?!})|
(?<!{){{1,2}(?!{)|
(?<!})}{1,2}(?!}))|(?1)
)++}}})/x", $body, -1, PREG_SPLIT_DELIM_CAPTURE);
// fix for inline {{{foobar}}} in the headings.
$chunks = array();
$i = $j = 0;
$c = count($tmp);
while ($i < $c) {
if ($i % 2) {
if (strpos($tmp[$i],"\n") === false) {
$chunks[$j-1].= $tmp[$i].$tmp[$i+1];
$i+=2;
} else {
$chunks[$j++] = $tmp[$i++];
}
} else {
$chunks[$j++] = $tmp[$i++];
}
}
unset($tmp);
$sects=array();
$sects[]='';
if ($lim > 1 and $lim < 5) $lim=','.$lim;
else if ($lim == 5) $lim = ',';
else $lim='';
for ($jj=0,$ii=0,$ss=count($chunks); $ii<$ss; $ii++) {
if (($ii%2)) {
$sec=array_pop($sects);
$sects[]=$sec.$chunks[$ii];
continue;
}
$parts=array();
$parts=preg_split("/^((?!\n)[ ]*={1$lim}\s#?.*\s+={1$lim}\s?)$/m",$chunks[$ii],
-1, PREG_SPLIT_DELIM_CAPTURE);
for ($j=0,$i=0,$s=count($parts); $i<$s; $i++) {
if (!($i%2)) {
$sec=array_pop($sects);
$sects[]=$sec.$parts[$i];
continue;
}
if (preg_match("/^\s*(={1$lim})\s#?.*\s+\\1\s?/",$parts[$i])) {
$sects[]=$parts[$i];
} else {
$sec=array_pop($sects);
$sects[]=$sec.$parts[$i];
}
}
}
return $sects;
}
function macro_Edit($formatter,$value,$options='') {
global $DBInfo;
$options['mode'] = !empty($options['mode']) ? $options['mode'] : '';
$edit_rows=$DBInfo->edit_rows ? $DBInfo->edit_rows: 16;
$cols= get_textarea_cols($options['is_mobile']);
$use_js= preg_match('/Lynx|w3m|links/',$_SERVER['HTTP_USER_AGENT']) ? 0:1;
$rows= (!empty($options['rows']) and $options['rows'] > 5) ? $options['rows']: $edit_rows;
$rows= $rows < 60 ? $rows: $edit_rows;
$cols= (!empty($options['cols']) and $options['cols'] > 60) ? $options['cols']: $cols;
$text= !empty($options['savetext']) ? $options['savetext'] : '';
$editlog= !empty($options['editlog']) ? $options['editlog'] : "";
if (empty($editlog) and !empty($options['comment']))
$editlog=_stripslashes($options['comment']);
$editlog = _html_escape($editlog);
$args= explode(',',$value);
if (in_array('nohints',$args)) $options['nohints']=1;
if (in_array('nomenu',$args)) $options['nomenu']=1;
$preview= !empty($options['preview']) ? $options['preview'] : 0;
if ($options['action']=='edit') $saveaction='savepage';
else $saveaction=$options['action'];
$extraform=!empty($formatter->_extra_form) ? $formatter->_extra_form:'';
$options['notmpl']=isset($options['notmpl']) ? $options['notmpl']:0;
$form = '';
if (!$options['notmpl'] and (!empty($options['template']) or !$formatter->page->exists()) and !$preview) {
$options['linkto']="?action=edit&amp;template=";
$options['limit'] = -1;
$tmpls= macro_TitleSearch($formatter,$DBInfo->template_regex,$options);
if ($tmpls) {
$tmpls = '<div>'._("Use one of the following templates as an initial release :\n").$tmpls;
$tmpls.= sprintf(_("To create your own templates, add a page with '%s' pattern."),$DBInfo->template_regex)."\n</div>\n";
}
if (isset($options['tmpls'])) {
$options['tmpls'] = $tmpls;
$tmpls = '';
}
}
$merge_btn=_("Merge");
$merge_btn2=_("Merge manually");
$merge_btn3=_("Ignore conflicts");
$extra = '';
if (!empty($options['conflict'])) {
$extra='<span class="button"><input type="submit" class="button" name="button_merge" value="'.$merge_btn.'" /></span>';
if ($options['conflict']==2) {
$extra.=' <span class="button"><input type="submit" class="button" name="manual_merge" value="'.$merge_btn2.'" /></span>';
if ($DBInfo->use_forcemerge)
$extra.=' <span class="button"><input type="submit" class="button" name="force_merge" value="'.$merge_btn3.'" /></span>';
}
}
$hidden = '';
if (!empty($options['section']))
$hidden='<input type="hidden" name="section" value="'.$options['section'].
'" />';
if (!empty($options['mode']))
$hidden='<input type="hidden" name="mode" value="'.$options['mode'].'" />';
# make a edit form
if (empty($options['simple']))
$form.= "<a id='editor'></a>\n";
if (isset($DBInfo->use_preview_anchor))
$preview_anchor = '#preview';
else
$preview_anchor = '';
if (isset($options['page'][0]))
$previewurl=$formatter->link_url(_rawurlencode($options['page']), $preview_anchor);
else
$previewurl=$formatter->link_url($formatter->page->urlname, $preview_anchor);
$menu= ''; $sep= '';
if (empty($DBInfo->use_resizer) and (empty($options['noresizer']) or !$use_js)) {
$sep= ' | ';
$menu= $formatter->link_to("?action=edit&amp;rows=".($rows-3),_("ReduceEditor"));
$menu.= $sep.$formatter->link_to("?action=edit&amp;rows=".($rows+3),_("EnlargeEditor"));
}
if (empty($options['nomenu'])) {
$menu.= $sep.$formatter->link_tag('InterWiki',"",_("InterWiki"));
$sep= ' | ';
$menu.= $sep.$formatter->link_tag('HelpOnEditing',"",_("HelpOnEditing"));
}
$form.=$menu;
$ajax = '';
$js = '';
if (!empty($options['action_mode']) and $options['action_mode']=='ajax') {
$ajax=" onsubmit='savePage(this);return false'";
}
$formh= sprintf('<form id="editform" method="post" action="%s"'.$ajax.'>',
$previewurl);
if ($text) {
$raw_body = preg_replace("/\r\n|\r/", "\n", $text);
} else if (!empty($options['template'])) {
$p= new WikiPage($options['template']);
$raw_body = preg_replace("/\r\n|\r/", "\n", $p->get_raw_body());
} else if (isset($formatter->_raw_body)) {
# low level XXX
$raw_body = preg_replace("/\r\n|\r/", "\n", $formatter->_raw_body);
} else if ($options['mode']!='edit' and $formatter->page->exists()) {
$raw_body = preg_replace("/\r\n|\r/", "\n", $formatter->page->_get_raw_body());
if (isset($options['section'])) {
$sections= _get_sections($raw_body);
if ($sections[$options['section']])
$raw_body = $sections[$options['section']];
#else ignore
}
} else {
$raw_body = '';
if (!empty($options['orig_pagename'])) {
$raw_body="#title $options[orig_pagename]\n";
}
if (strpos($options['page'],' ') > 0) {
#$raw_body="#title $options[page]\n";
$options['page']='["'.$options['page'].'"]';
}
$guide = sprintf(_("Describe %s here"), $options['page']);
if (empty($DBInfo->use_edit_placeholder)) {
$raw_body.= $guide;
$guide = '';
} else {
$guide = ' placeholder="'._html_escape($guide).'"';
}
$js=<<<EOF
<script type="text/javascript">
/*<![CDATA[*/
(function() {
function selectGuide() {
var txtarea = document.getElementById('editor-textarea');
if (!txtarea) return;
txtarea.focus();
var txt = txtarea.value;
var pos = 0;
if (txt.indexOf('#title ') == 0) {
pos = txt.indexOf("\\n") + 1;
}
var end = txt.length;
if (txtarea.selectionStart || txtarea.selectionStart == '0') {
// goto
txtarea.selectionStart = pos;
txtarea.selectionEnd = end;
} else if (document.selection && !is_gecko && !is_opera) {
// IE
var r = document.selection.createRange();
var range = r.duplicate();
range.moveStart('character', pos);
range.moveEnd('character', end - pos);
r.setEndPoint('StartToStart', range);
range.select();
}
}
var oldOnLoad = window.onLoad;
window.onload = function() {
try { oldOnLoad() } catch(e) {};
selectGuide();
}
})();
/*]]>*/
</script>\n
EOF;
}
$summary_guide = '';
if (!empty($options['.minorfix']))
$summary_guide = _("This ia a minor edit.");
if (empty($DBInfo->use_edit_placeholder)) {
$summary_guide = '';
} else {
$summary_guide = ' placeholder="'._html_escape($summary_guide).'"';
}
# for conflict check
if (!empty($options['datestamp']))
$datestamp= $options['datestamp'];
else if (!empty($formatter->_mtime))
# low level control XXX
$datestamp= $formatter->_mtime;
else
$datestamp= $formatter->page->mtime();
if (!empty($DBInfo->use_savepage_hash)) {
// generate hash
$ticket = getTicket($datestamp.$DBInfo->user->id, $_SERVER['REMOTE_ADDR']);
$hash = md5($ticket);
$hidden .=
"\n<input type=\"hidden\" name=\"hash\" value=\"".$hash."\" />\n";
}
$raw_body = str_replace(array("&","<"),array("&amp;","&lt;"),$raw_body);
# get categories
$select_category = '';
if (!empty($DBInfo->use_category) and empty($options['nocategories'])) {
$categories = $DBInfo->getLikePages($DBInfo->category_regex, -1);
if ($categories) {
$select_category="<label for='category-select'>"._("Category")."</label><select id='category-select' name='category' tabindex='4'>\n";
$mlen = 0;
$opts = '';
foreach ($categories as $category) {
$len = mb_strwidth($category);
$category = _html_escape($category);
if ($len > $mlen) $mlen = $len;
$opts .= "<option value=\"$category\">$category</option>\n";
}
$lab = _(" Select ");
$len = intval(($mlen - mb_strwidth($lab)) / 2);
$pad = str_repeat('-', $len);
$select_category.= "<option value=''>".$pad.$lab.$pad."</option>\n".$opts;
$select_category.="</select>\n";
}
}
$extra_check = '';
if (empty($options['minor']) and !empty($DBInfo->use_minoredit)) {
$user=&$DBInfo->user; # get from COOKIE VARS
if (!empty($DBInfo->owners) and in_array($user->id,$DBInfo->owners)) {
$extra_check=' '._("Minor edit")."<input type='checkbox' tabindex='3' name='minor' />";
}
}
$captcha='';
if ($use_js and !empty($DBInfo->use_ticket) and $options['id'] == 'Anonymous') {
$msg = _("Refresh");
$seed=md5(base64_encode(time()));
$ticketimg=$formatter->link_url($formatter->page->urlname,'?action=ticket&amp;__seed='.$seed.'&amp;t=');
$onclick = " onclick=\"document.getElementById('captcha_img').src ='".$ticketimg."'+ Math.random()\"";
$captcha=<<<EXTRA
<div class='captcha' style='float:right'><div><span class='captchaImg'><img id="captcha_img" src="$ticketimg" alt="captcha" /></span></div>
<button type='button' class='refresh-icon'$onclick><span>$msg</span></button><input type="text" tabindex="2" size="10" name="check" />
<input type="hidden" name="__seed" value="$seed" /></div>
EXTRA;
}
$summary_msg=_("Summary");
$wysiwyg_btn = '';
$skip_preview = '';
if (empty($options['simple'])) {
$preview_btn='<span class="button"><input type="submit" tabindex="6" name="button_preview" class="button preview-button" value="'.
_("Preview").'" /></span>';
$changes_btn = '';
if ($formatter->page->exists())
$changes_btn=' <span class="button"><input type="submit" tabindex="6" name="button_changes" class="button preview-button" value="'.
_("Show changes").'" /></span>';
if ($preview and empty($options['conflict']))
$skip_preview= ' '.$formatter->link_to('#preview',_("Skip to preview"),' class="preview-anchor"');
if (!empty($DBInfo->use_wikiwyg)) {
$confirm = 'false';
if (!empty($DBInfo->wikiwyg_confirm)) $confirm = 'null';
$wysiwyg_msg=_("GUI");
$wysiwyg_btn.='&nbsp;<button type="button" tabindex="7"'.
' onclick="javascript:sectionEdit(null,'.$confirm .',null)" ><span>'.
$wysiwyg_msg.'</span></button>';
}
$summary=<<<EOS
<span id='edit-summary'><label for='input-summary'>$summary_msg</label><input name="comment" id='input-summary' value="$editlog" size="60" maxlength="128" tabindex="2" $summary_guide />$extra_check</span>
EOS;
$emailform = '';
if (!empty($DBInfo->anonymous_friendly) and $options['id'] == 'Anonymous') {
$useremail = isset($DBInfo->user->verified_email) ? $DBInfo->user->verified_email : '';
if ($useremail) {
$email_msg = _("E-Mail");
$send_msg = sprintf(_("Send mail to %s"), "<span class='email'>".$useremail."</span>");
#<label for='input-email'>$email_msg</label>
#<span id='edit-email'><label for='input-email'>$email_msg</label><input name="email" id='input-email' value="$useremail" size="40" maxlength="60" tabindex="3" /></span>
$emailform = <<<EOS
$send_msg <input type='checkbox' tabindex='3' checked='checked' name='cc' />
EOS;
}
}
// show contributor license agreement form
$ok_agreement = true;
if (!empty($DBInfo->use_agreement)) {
if ($options['id'] != 'Anonymous') {
$ok_agreement = !empty($DBInfo->user->info['join_agreement']) && $DBInfo->user->info['join_agreement'] == 'agree';
if ($ok_agreement && !empty($DBInfo->agreement_version))
$ok_agreement = $DBInfo->user->info['join_agreement_version'] == $DBInfo->agreement_version;
} else {
$ok_agreement = false;
}
}
if (!$ok_agreement) {
if ($options['id'] != 'Anonymous') {
if (!empty($DBInfo->contributor_license_agreement))
$agree_msg = $DBInfo->contributor_license_agreement;
else
$agree_msg = _("Agree to the contributor license agreement on this wiki");
} else {
if (!empty($DBInfo->irrevocable_contribution_agreement))
$agree_msg = $DBInfo->irrevocable_contribution_agreement;
else
$agree_msg = _("Agree to the contribution agreement for Anonymous doner");
}
$emailform.= <<<EOS
$agree_msg <input type='checkbox' tabindex='3' checked='checked' name='license_agree' />
EOS;
}
if (isset($emailform[0]))
$emailform = '<div id="contribution_agreement">'.$emailform.'</div>';
}
$save_msg=_("Save");
if ($use_js and !empty($DBInfo->use_resizer)) {
if ($DBInfo->use_resizer==1) {
$resizer=<<<EOS
<script type="text/javascript" language='javascript'>
/*<![CDATA[*/
function resize(obj,val) {
rows= obj.savetext.rows;
rows+=val;
if (rows > 60) rows=16;
else if (rows < 5) rows=16;
obj.savetext.rows=rows;
}
var resizer=document.createElement('div');
resizer.setAttribute('id','wikiResize');
resizer.innerHTML="<input type='button' class='inc' value='+' onclick='resize(this.form,3)' />\\n<input type='button' class='dec' value='-' onclick='resize(this.form,-3)' />";
var toolbar=document.getElementById('toolbar');
if (toolbar) {
toolbar.insertBefore(resizer, toolbar.firstChild);
} else {
var editor=document.getElementById('wikiEditor');
editor.insertBefore(resizer, editor.firstChild);
}
/*]]>*/
</script>
EOS;
} else {
$formatter->register_javascripts('textarea.js');
}
}
$form.=<<<EOS
<div id="editor_area">
$formh
<div class="resizable-textarea" style='position:relative'><!-- IE hack -->
<div id="save_state"></div>
<textarea id="editor-textarea" wrap="virtual" name="savetext" tabindex="1"
rows="$rows" cols="$cols" class="wiki resizable"$guide>$raw_body</textarea>
$captcha
</div>
$extraform
<div id="editor_info">
<ul>
<