Permalink
Fetching contributors…
Cannot retrieve contributors at this time
6838 lines (6043 sloc) 224 KB
<?php
// Copyright 2003-2015 Won-Kyu Park <wkpark at kldp.org> all rights reserved.
// distributable under GPLv2 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: wiki.php,v 1.639 2011/08/09 13:51:53 wkpark Exp $
//
$_revision = substr('$Revision: 1.2000 $',1,-1);
$_release = '1.2.6-GIT';
#ob_start("ob_gzhandler");
error_reporting(E_ALL ^ E_NOTICE);
#error_reporting(E_ALL);
/**
* get macro/action plugins
*
* @param macro/action name
* @return a basename of the plugin or null or false(disabled)
*/
function getPlugin($pluginname) {
static $plugins=array();
if (is_bool($pluginname) and $pluginname)
return sizeof($plugins);
$pname = strtolower($pluginname);
if (!empty($plugins)) return isset($plugins[$pname]) ? $plugins[$pname]:'';
global $DBInfo;
$cp = new Cache_text('settings', array('depth'=>0));
if (empty($DBInfo->manual_plugin_admin)) {
if (!empty($DBInfo->include_path))
$dirs=explode(':',$DBInfo->include_path);
else
$dirs=array('.');
$updated=false;
$mt=$cp->mtime('plugins');
foreach ($dirs as $d) {
if (is_dir($d.'/plugin/')) {
$ct=filemtime($d.'/plugin/.'); // XXX mtime fix
$updated=$ct > $mt ? true:$updated;
}
}
if ($updated) {
$cp->remove('plugins');
$cp->remove('processors');
}
}
if ($plugins = $cp->fetch('plugins')) {
if (!empty($DBInfo->myplugins) and is_array($DBInfo->myplugins))
$plugins=array_merge($plugins,$DBInfo->myplugins);
return isset($plugins[$pname]) ? $plugins[$pname]:'';
}
if (!empty($DBInfo->include_path))
$dirs=explode(':',$DBInfo->include_path);
else
$dirs=array('.');
foreach ($dirs as $dir) {
$handle= @opendir($dir.'/plugin');
if (!$handle) continue;
while ($file= readdir($handle)) {
if (is_dir($dir."/plugin/$file")) continue;
$name= substr($file,0,-4);
$plugins[strtolower($name)]= $name;
}
}
// get predefined macros list
$tmp = get_defined_functions();
foreach ($tmp['user'] as $u) {
if (preg_match('/^macro_(.*)$/', $u, $m)) {
$n = strtolower($m[1]);
if (!isset($plugins[$n])) $plugins[$n] = $m[1];
}
}
if (!empty($plugins))
$cp->update('plugins',$plugins);
if (!empty($DBInfo->myplugins) and is_array($DBInfo->myplugins))
$plugins=array_merge($plugins,$DBInfo->myplugins);
return isset($plugins[$pname]) ? $plugins[$pname]:'';
}
function getProcessor($pro_name) {
static $processors=array();
if (is_bool($pro_name) and $pro_name)
return sizeof($processors);
$prog = strtolower($pro_name);
if (!empty($processors)) return isset($processors[$prog]) ? $processors[$prog]:'';
global $DBInfo;
$cp = new Cache_text('settings', array('depth'=>0));
if ($processors=$cp->fetch('processors')) {
if (is_array($DBInfo->myprocessors))
$processors=array_merge($processors,$DBInfo->myprocessors);
return isset($processors[$prog]) ? $processors[$prog]:'';
}
if (!empty($DBInfo->include_path))
$dirs=explode(':',$DBInfo->include_path);
else
$dirs=array('.');
foreach ($dirs as $dir) {
$handle= @opendir($dir.'/plugin/processor');
if (!$handle) continue;
while ($file= readdir($handle)) {
if (is_dir($dir."/plugin/processor/$file")) continue;
$name= substr($file,0,-4);
$processors[strtolower($name)]= $name;
}
}
if ($processors)
$cp->update('processors', $processors);
if (is_array($DBInfo->myprocessors))
$processors=array_merge($processors,$DBInfo->myprocessors);
return isset($processors[$prog]) ? $processors[$prog]:'';
}
function getFilter($filtername) {
static $filters=array();
if ($filters) return $filters[strtolower($filtername)];
global $DBInfo;
if (!empty($DBInfo->include_path))
$dirs=explode(':',$DBInfo->include_path);
else
$dirs=array('.');
foreach ($dirs as $dir) {
$handle= @opendir($dir.'/plugin/filter');
if (!$handle) continue;
while ($file= readdir($handle)) {
if (is_dir($dir."/plugin/filter/$file")) continue;
$name= substr($file,0,-4);
$filters[strtolower($name)]= $name;
}
}
if (!empty($DBInfo->myfilters) and is_array($DBInfo->myfilters))
$filters=array_merge($filters,$DBInfo->myfilters);
return $filters[strtolower($filtername)];
}
if (!function_exists ('bindtextdomain')) {
$_locale = array();
function gettext ($text) {
global $_locale,$locale;
if (sizeof($_locale) == 0) $_locale=&$locale;
if (!empty ($_locale[$text]))
return $_locale[$text];
return $text;
}
function _ ($text) {
return gettext($text);
}
}
function _t ($text) {
return gettext($text);
}
function goto_form($action,$type="",$form="") {
if ($type==1) {
return "
<form id='go' method='get' action='$action'>
<div>
<span title='TitleSearch'>
<input type='radio' name='action' value='titlesearch' />
Title</span>
<span title='FullSearch'>
<input type='radio' name='action' value='fullsearch' />
Contents</span>&nbsp;
<input type='text' name='value' class='goto' accesskey='s' size='20' />
<input type='submit' name='status' value='Go' style='width:23px' />
</div>
</form>
";
} else if ($type==2) {
return "
<form id='go' method='get' action='$action'>
<div>
<select name='action' style='width:60px'>
<option value='goto'>goto</option>
<option value='titlesearch'>TitleSearch</option>
<option value='fullsearch'>FullSearch</option>
</select>
<input type='text' name='value' class='goto' accesskey='s' size='20' />
<input type='submit' name='status' value='Go' />
</div>
</form>
";
} else if ($type==3) {
return "
<form id='go' method='get' action='$action'>
<table class='goto'>
<tr><td nowrap='nowrap' style='width:220px'>
<input type='text' name='value' size='28' accesskey='s' style='width:110px' />
<input type='submit' name='status' value='Go' class='goto' style='width:23px' />
</td></tr>
<tr><td>
<span title='TitleSearch' class='goto'>
<input type='radio' name='action' value='titlesearch' class='goto' />
Title(?)</span>
<span title='FullSearch' class='goto'>
<input type='radio' name='action' value='fullsearch' accesskey='s' class='goto'/>
Contents(/)</span>&nbsp;
</td></tr>
</table>
</form>
";
} else {
return <<<FORM
<form id='go' method='get' action='$action' onsubmit="moin_submit(this);">
<div>
<input type='text' name='value' size='20' accesskey='s' class='goto' style='width:100px' />
<input type='hidden' name='action' value='goto' />
<input type='submit' name='status' value='Go' style='width:23px;' />
</div>
</form>
FORM;
}
}
function kbd_handler($prefix = '') {
global $Config;
if (!$Config['kbd_script']) return '';
$prefix ? null : $prefix = get_scriptname();
$sep= $Config['query_prefix'];
return <<<EOS
<script type="text/javascript">
/*<![CDATA[*/
url_prefix="$prefix";
_qp="$sep";
FrontPage= "$Config[frontpage]";
/*]]>*/
</script>
<script type="text/javascript" src="$Config[kbd_script]"></script>\n
EOS;
}
class MetaDB {
function MetaDB() {
return;
}
function getSisterSites($pagename,$mode=1) {
if ($mode) return '';
return false;
}
function getTwinPages($pagename,$mode=1) {
if ($mode) return array();
return false;
}
function hasPage($pgname) {
return false;
}
function getAllPages() {
return array();
}
function getLikePages($needle, $count = 1) {
return array();
}
function close() {
}
}
class Counter_dba {
var $counter = null;
var $dba_type;
var $owners;
var $data_dir;
var $dbname = 'counter';
function Counter_dba($DB, $dbname='counter') {
if (!function_exists('dba_open')) return;
$this->dba_type = $DB->dba_type;
$this->owners = $DB->owners;
$this->data_dir = $DB->data_dir;
$this->dbname = $dbname;
if (!file_exists($this->data_dir.'/'.$dbname.'.db')) {
// create
$db = dba_open($this->data_dir.'/'.$dbname.'.db', 'n', $this->dba_type);
dba_close($db);
}
$this->counter = @dba_open($this->data_dir.'/'.$dbname.'.db', 'r', $this->dba_type);
}
function incCounter($pagename,$options="") {
if ($this->owners and in_array($options['id'],$this->owners))
return;
$count=dba_fetch($pagename,$this->counter);
if (!$count) $count=0;
$count++;
// increase counter without locking
$db = dba_open($this->data_dir.'/'.$this->dbname.'.db', 'w-', $this->dba_type);
dba_replace($pagename, $count, $db);
dba_close($db);
return $count;
}
function pageCounter($pagename) {
$count = dba_fetch($pagename,$this->counter);
return $count ? $count: 0;
}
function getPageHits($perpage = 200, $page = 0, $cutoff = 0) {
$k = dba_firstkey($this->counter);
if ($k !== false && $page > 0) {
$i = $perpage * $page;
while ($i > 0 && $k !== false) {
$i--;
$k = dba_nextkey($this->counter);
}
}
$hits = array();
$i = $perpage;
if ($perpage == -1)
$i = 2147483647; // PHP_INT_MAX
for (; $k !== false && $i > 0; $k = dba_nextkey($this->counter)) {
$v = dba_fetch($k, $this->counter);
if ($v > $cutoff)
$hits[$k] = $v;
$i--;
}
return $hits;
}
function close() {
if ($this->counter)
dba_close($this->counter);
}
}
class Counter {
function Counter($DB="") { }
function incCounter($page,$options="") { }
function pageCounter($page) { return 1; }
function close() { }
}
class Security_base {
var $DB;
function Security_base($DB = '') {
$this->DB=$DB;
}
# $options[page]: pagename
# $options[id]: user id
function readable($options="") {
return 1;
}
function writable($options="") {
if (!isset($options['page'][0])) return 0; # XXX
return $this->DB->_isWritable($options['page']);
}
function validuser($options="") {
return 1;
}
function is_allowed($action="read",&$options) {
return 1;
}
function is_protected($action="read",$options) {
# password protected POST actions
$protected_actions=array(
"deletepage","deletefile","rename","rcspurge","rcs","chmod","backup","restore","rcsimport","revert","userinfo", 'merge');
$action=strtolower($action);
if (in_array($action,$protected_actions)) {
return 1;
}
return 0;
}
function is_valid_password($passwd,$options) {
return
$this->DB->admin_passwd==crypt($passwd,$this->DB->admin_passwd);
}
}
function getConfig($configfile, $options=array()) {
extract($options);
unset($key,$val,$options);
// ignore BOM and garbage characters
ob_start();
$myret = @include($configfile);
ob_get_contents();
ob_end_clean();
if ($myret === false) {
if (!empty($init)) {
$script= preg_replace("/\/([^\/]+)\.php$/",'/monisetup.php',
$_SERVER['SCRIPT_NAME']);
if (is_string($init)) $script .= '?init='.$init;
header("Location: $script");
exit;
}
return array();
}
unset($configfile);
unset($myret);
$config=get_defined_vars();
if (isset($config['include_path']))
ini_set('include_path',ini_get('include_path').PATH_SEPARATOR.$config['include_path']);
return $config;
}
class WikiDB {
function WikiDB($config) {
// set configurations
if (is_object($config)) {
$conf = get_object_vars($config); // merge default settings to $config
} else {
$conf = &$config;
}
foreach ($conf as $key=>$val) {
if ($key[0]=='_') continue; // internal variables
$this->$key=$val;
}
$this->initEnv();
$this->initModules();
register_shutdown_function(array(&$this,'Close'));
}
function initEnv() {
if (!empty($this->path))
putenv("PATH=".$this->path);
if (!empty($this->rcs_user))
putenv('LOGNAME='.$this->rcs_user);
if (!empty($this->timezone))
putenv('TZ='.$this->timezone);
if (function_exists('date_default_timezone_set')) {
// suppress date() warnings for PHP5.x
date_default_timezone_set(@date_default_timezone_get());
}
}
function initModules() {
if (!empty($this->use_counter)) {
$this->counter = new Counter_dba($this);
if ($this->counter->counter == null) {
$this->use_counter = 0;
$this->counter = null;
}
}
#$this->interwiki=null;
// pagekey class
if (!empty($this->pagekey_class)) {
include_once('lib/pagekey.'.$this->pagekey_class.'.php');
$pagekey_class = 'PageKey_'.$this->pagekey_class;
} else {
include_once('lib/pagekey.compat.php');
$pagekey_class = 'PageKey_compat';
}
$this->pagekey = new $pagekey_class($this);
if (!empty($this->security_class)) {
include_once("plugin/security/$this->security_class.php");
$class='Security_'.$this->security_class;
$this->security=new $class ($this);
} else
$this->security=new Security_base($this);
}
function initAlias() {
// parse the aliaspage
if (!empty($this->use_alias) and file_exists($this->aliaspage)) {
$ap = new Cache_text('settings');
$aliases = $ap->fetch('alias');
if (empty($aliases) or $ap->mtime() < filemtime($this->aliaspage)) {
$aliases = get_aliases($this->aliaspage);
$ap->update('alias', $aliases);
}
}
if (!empty($aliases)) {
require_once(dirname(__FILE__).'/lib/metadb.text.php');
$this->alias= new MetaDB_text($aliases);
} else {
$this->alias= new MetaDB();
}
}
function initMetaDB() {
if (empty($this->alias)) $this->initAlias();
if (!empty($this->shared_metadb)) {
if (!empty($this->shared_metadb_type) &&
in_array($this->shared_metadb_type, array('dba', 'compact'))) {
// new
$type = $this->shared_metadb_type;
$dbname = $this->shared_metadb_dbname;
} else {
// old
$type = 'dba';
$dbname = $this->shared_metadb;
}
$class = 'MetaDB_'.$type;
require_once(dirname(__FILE__).'/lib/metadb.'.$type.'.php');
$this->metadb = new $class($dbname, $this->dba_type);
}
if (empty($this->metadb->metadb)) {
if (is_object($this->alias)) $this->metadb=$this->alias;
else $this->metadb= new MetaDB();
} else {
$this->metadb->attachDB($this->alias);
}
}
function Close() {
if (!empty($this->metadb) and is_object($this->metadb))
$this->metadb->close();
if (!empty($this->counter) and is_object($this->counter))
$this->counter->close();
}
function _getPageKey($pagename) {
return $this->pagekey->_getPageKey($pagename);
}
function getPageKey($pagename) {
return $this->pagekey->getPageKey($pagename);
}
function pageToKeyname($pagename) {
return $this->pagekey->_getPageKey($pagename);
}
function keyToPagename($key) {
return $this->pagekey->keyToPagename($key);
}
function hasPage($pagename) {
if (!isset($pagename[0])) return false;
$name=$this->getPageKey($pagename);
return @file_exists($name);
}
function getPage($pagename,$options="") {
return new WikiPage($pagename,$options);
}
function mtime() {
// workaround to check the dir mtime of the text_dir
if ($this->use_fakemtime)
return @filemtime($this->editlog_name);
return @filemtime($this->text_dir);
}
function checkUpdated($time, $delay = 1800) {
return $this->mtime() <= $time + $delay;
}
/**
* support lazy loading
*
*/
function &lazyLoad($name) {
if (empty($this->$name)) {
// get extra args
$tmp = func_get_args();
array_shift($tmp);
$params = array();
for ($i = 0, $num = count($tmp); $i < $num; $i++) {
if (is_array($tmp[$i]))
$params = array_merge($params, $tmp[$i]);
else
$params[] = $tmp[$i];
}
if (count($params) == 1) $params = $params[0];
$classname = $name.'_class';
// get $this->foobar_class
if (!empty($this->$classname)) {
// classname provided like as 'type' and the real classname is 'foobar_type'
$file = $name.'.'.$this->$classname; // foobar.type.php
// full classname provided like as Foobar_Type
$file1 = strtr($this->$classname, '_', '.');
$class0 = $name.'_'.$this->$classname; // foobar_type class
if (class_exists($class0)) {
$class = $class0;
} else if ((@include_once('lib/'.$file.'.php')) || (@include_once('lib/'.strtolower($file).'.php'))) {
$class = $name.'_'.$this->$classname; // foobar_type class
} else if ((@include_once('lib/'.$file1.'.php')) || (@include_once('lib/'.strtolower($file1).'.php'))) {
$class = $this->$classname;
} else if (class_exists($this->$classname)) {
$class = $this->$classname;
} else {
trigger_error(sprintf(_("File '%s' or '%s' does not exist."), $file, $file1), E_USER_ERROR);
exit;
}
// create
if (!empty($params))
$this->$name = new $class($params);
else
$this->$name = new $class();
// init module
if (method_exists($this->$name, 'init_module')) {
call_user_func(array($this->$name, 'init_module'));
}
}
}
return $this->$name;
}
function getPageLists($options = array()) {
$indexer = $this->lazyLoad('titleindexer');
return $indexer->getPages($options);
}
function getLikePages($needle,$count=100,$opts='') {
$pages= array();
if (!$needle) return false;
$m = @preg_match("/$needle/".$opts,'dummy');
if ($m===false) return array();
$indexer = $this->lazyLoad('titleindexer');
return $indexer->getLikePages($needle, $count);
}
function getCounter() {
$indexer = $this->lazyLoad('titleindexer');
return $indexer->pageCount();
}
function addLogEntry($page_name, $remote_name,$comment,$action="SAVE") {
$user=&$this->user;
$key_name = $this->_getPageKey($page_name);
$myid=$user->id;
if ($myid == 'Anonymous' and !empty($user->verified_email))
$myid.= '-'.$user->verified_email;
$comment = trim($comment);
$comment=strtr(strip_tags($comment),
array("\r\n"=>' ', "\r"=>' ',"\n"=>' ', "\t"=>' '));
$fp_editlog = fopen($this->editlog_name, 'a+');
$time= time();
if ($this->use_hostname) $host= gethostbyaddr($remote_name);
else $host= $remote_name;
$key_name=trim($key_name);
$msg="$key_name\t$remote_name\t$time\t$host\t$myid\t$comment\t$action\n";
fwrite($fp_editlog, $msg);
fclose($fp_editlog);
$params = array('pagename'=>$page_name,
'remote_addr'=>$remote_name,
'timestamp'=>$time,
'hostname'=>$host,
'id'=>$user->id,
'comment'=>$comment,
);
if (function_exists('local_logger')) local_logger($action, $params);
}
function editlog_raw_lines($days,$opts=array()) {
global $Config;
$ruleset = array();
if (isset($Config['ruleset']['hidelog']) && !empty($this->members) && !in_array($this->user->id, $this->members))
$ruleset = $Config['ruleset']['hidelog'];
$fz = filesize($this->editlog_name);
$lines=array();
$time_current= time();
$secs_per_day= 24*60*60;
if (!empty($opts['ago'])) {
$date_from= $time_current - ($opts['ago'] * $secs_per_day);
$date_to= $date_from + ($days * $secs_per_day);
$seek_start = null;
} else if (!empty($opts['from'])) {
$from = strtotime($opts['from']);
if ($time_current > $from)
$date_from= $from;
else
$date_from = $time_current - ($from - $time_current);
$date_to= $date_from + ($days * $secs_per_day);
$seek_start = null;
} else {
if (!empty($opts['items'])) {
$date_from= $time_current - (365 * $secs_per_day);
} else {
$date_from= $time_current - ($days * $secs_per_day);
}
$date_to= $time_current;
$seek_start = 0;
}
// check start timestamp
if (!empty($opts['start']) && is_numeric($opts['start'])) {
$time_seek = $opts['start'];
if ($time_seek < $time_current && $time_seek > $date_from) {
$date_to = $time_seek;
$seek_start = null;
}
}
if ($date_to > $time_current) {
$seek_start = 0;
$date_to = $time_current;
}
$check=$date_to;
// seek $date_to
if ($seek_start === null) {
require_once(dirname(__FILE__).'/plugin/editlogbin.php');
$seek = _editlog_seek($this->editlog_name, $date_to);
if ($seek < 0) {
// fail to seek
return array();
}
$seek_start = $fz - $seek;
}
$itemnum=!empty($opts['items']) ? $opts['items']:200;
$fp= fopen($this->editlog_name, 'r');
while (is_resource($fp) && $fz > 0){
if ($fz <= 1024) {
fseek($fp,0);
$ll=rtrim(fread($fp,1024));
$lines=array_reverse(explode("\n",$ll));
break;
}
$a = $seek_start - 1; // hack, don't read last \n char.
$last='';
fseek($fp, $seek_start, SEEK_END);
while($date_from < $check and !feof($fp)){
$rlen=$fz + $a;
if ($rlen > 1024) { $rlen=1024;}
else if ($rlen <= 0) break;
$a-=$rlen;
fseek($fp,$a,SEEK_END);
$l=fread($fp,$rlen);
if ($rlen != 1024) $l="\n".$l; // hack, for the first log entry.
while(($p=strrpos($l,"\n"))!==false) {
$line=substr($l,$p+1).$last;
$last='';
$l=substr($l,0,$p);
$dumm=explode("\t",$line,4);
$check=$dumm[2];
if ($date_from>$check) break;
if ($date_to>$check) {
if (!empty($ruleset)) {
$page_name = $this->keyToPagename($dumm[0]);
if (in_array($page_name, $ruleset))
continue;
}
$lines[]=$line;
$pages[$dumm[0]]=1;
if (sizeof($pages) >= $itemnum) { $check=0; break; }
}
$last='';
}
$last=$l.$last;
}
#echo $a;
#echo sizeof($lines);
#print_r($lines);
fclose($fp);
break;
}
if (!empty($opts['quick'])) {
$out = array();
foreach($lines as $line) {
$dum=explode("\t",$line,2);
if (!empty($dum[0]) and !empty($keys[$dum[0]])) continue;
$keys[$dum[0]]=1;
$out[]=$line;
}
$lines=$out;
}
return $lines;
}
function _replace_variables($body,$options) {
if ($this->template_regex
&& preg_match("/$this->template_regex/",$options['page']))
return $body;
$time=gmdate("Y-m-d\TH:i:s");
if ($options['id'] == 'Anonymous') {
$id=!empty($options['name']) ?
_stripslashes($options['name']):$_SERVER['REMOTE_ADDR'];
} else {
$id=!empty($options['nick']) ? $options['nick']:$options['id'];
if (!preg_match('/([A-Z][a-z0-9]+){2,}/',$id)) $id='['.$id.']';
}
$body=preg_replace("/@DATE@/","[[Date($time)]]",$body);
$body=preg_replace("/@USERNAME@/","$id",$body);
$body=preg_replace("/@TIME@/","[[DateTime($time)]]",$body);
$body=preg_replace("/@SIG@/","-- $id [[DateTime($time)]]",$body);
$body=preg_replace("/@PAGE@/",$options['page'],$body);
$body=preg_replace("/@date@/","$time",$body);
return $body;
}
function _savePage($pagename,$body,$options=array()) {
$keyname = $this->_getPageKey($pagename);
$filename = $this->text_dir.'/'.$keyname;
$dir=dirname($filename);
if (!is_dir($dir)) {
$om=umask(~$this->umask);
_mkdir_p($dir, 0777);
umask($om);
}
$is_new = false;
if (!file_exists($filename)) $is_new = true;
$fp=@fopen($filename,"a+b");
if (!is_resource($fp))
return -1;
flock($fp, LOCK_EX); // XXX
ftruncate($fp, 0);
fwrite($fp, $body);
flock($fp, LOCK_UN);
fclose($fp);
$ret = 0;
if (!empty($this->version_class)) {
$om=umask(~$this->umask);
$ver = $this->lazyLoad('version', $this);
// get diff
if (!$is_new) {
$diff = $ver->diff($pagename);
// count diff lines, chars
$changes = diffcount_lines($diff, $this->charset);
// set return values
$retval = &$options['retval'];
$retval['add'] = $changes[0];
$retval['del'] = $changes[1];
$retval['add_chars'] = $changes[2];
$retval['del_chars'] = $changes[3];
} else {
// new file.
// set return values
$retval = &$options['retval'];
$retval['add'] = get_file_lines($filename);
$retval['del'] = 0;
$retval['add_chars'] = mb_strlen($body, $this->charset);
$retval['del_chars'] = 0;
}
$force = $is_new || $options['.force'];
// FIXME fix for revert+create cases for clear
if ($is_new && preg_match('@;;{REVERT}@', $options['log'])) {
$tmp = preg_replace('@;;{REVERT}:@', ';;{CREATE}{REVERT}:', $options['log']);
if ($tmp !== null)
$options['log'] = $tmp;
}
$ret = $ver->_ci($filename,$options['log'], $force);
if ($ret == -1)
$options['retval']['msg'] = _("Fail to save version information");
chmod($filename,0666 & $this->umask);
umask($om);
}
return $ret;
}
function savePage(&$page,$comment="",$options=array()) {
if (empty($options['.force']) && !$this->_isWritable($page->name)) {
return -1;
}
$user=&$this->user;
if ($user->id == 'Anonymous' and !empty($this->anonymous_log_maxlen))
if (strlen($comment)>$this->anonymous_log_maxlen) $comment=''; // restrict comment length for anon.
if (!empty($this->use_x_forwarded_for))
$REMOTE_ADDR = get_log_addr();
else
$REMOTE_ADDR = $_SERVER['REMOTE_ADDR'];
$myid=$user->id;
if (!empty($user->info['nick'])) {
$myid.=' '.$user->info['nick'];
$options['nick']=$user->info['nick'];
} else if ($myid == 'Anonymous' and !empty($user->verified_email)) {
$myid.= '-'.$user->verified_email;
}
$options['myid']=$myid;
$keyname=$this->_getPageKey($page->name);
$key=$this->text_dir."/$keyname";
$body=$this->_replace_variables($page->body,$options);
if (file_exists($key)) {
$action = 'SAVE';
} else {
$action = 'CREATE';
}
if ($user->id == 'Anonymous' && $action == 'CREATE' &&
empty($this->anomymous_allow_create_without_backlink)) {
$bc = new Cache_Text('backlinks');
if (!$bc->exists($page->name)) {
$options['retval']['msg'] = _("Anonymous users can not create new pages.");
return -1;
}
}
if (!empty($options['.reverted']))
$action = 'REVERT';
// check abusing FIXME
if (!empty($this->use_abusefilter)) {
$params = array();
$params['retval'] = &$options['retval'];
$params['id'] = ($user->id == 'Anonymous') ? $REMOTE_ADDR : $user->id;
$params['ip'] = $REMOTE_ADDR;
$params['action'] = $options['action'];
$params['editinfo'] = !empty($options['editinfo']) ? $options['editinfo'] : false;
if (is_string($this->use_abusefilter))
$filtername = $this->use_abusefilter;
else
$filtername = 'default';
$ret = call_abusefilter($filtername, $action, $params);
if ($ret === false) return -1;
}
if ($action == 'SAVE' && !empty($options['.minorfix'])) {
$action = 'MINOR';
}
$comment = trim($comment);
$comment = strtr(strip_tags($options['comment']),
array("\r\n"=>' ', "\r"=>' ',"\n"=>' ', "\t"=>' '));
// strip out all action flags FIXME
$comment = preg_replace('@^{(SAVE|CREATE|DELETE|RENAME|REVERT|UPLOAD|ATTDRW|FORK|REVOKE|MINOR|BOTFIX)}:?@', '', $comment);
if ($action != 'SAVE') {
$tag = '{'.$action.'}';
if (!empty($comment))
$comment = $tag.': '.$comment;
else
$comment = $tag;
}
$log=$REMOTE_ADDR.';;'.$myid.';;'.$comment;
$options['log']=$log;
$options['pagename']=$page->name;
$is_new = false;
if (!file_exists($key)) $is_new = true;
// get some edit info;
$retval = array();
$options['retval'] = &$retval;
$ret = $this->_savePage($page->name, $body, $options);
if ($ret == -1) return -1;
#
$page->write($body);
# check minor edits XXX
$minor=0;
if (!empty($this->use_minorcheck) or !empty($options['minorcheck'])) {
$info = $page->get_info();
if (!empty($info[0][1])) {
eval('$check='.$info[1].';');
if (abs($check) < 3) $minor=1;
}
}
if (empty($options['.nolog']) && empty($options['minor']) && !$minor)
$this->addLogEntry($page->name, $REMOTE_ADDR,$comment,$action);
if ($user->id != 'Anonymous' || !empty($this->use_anonymous_editcount)) {
// save editing information
if (!isset($user->info['edit_count']))
$user->info['edit_count'] = 0;
$user->info['edit_count']++;
// added/deleted lines
if (!isset($user->info['edit_add_lines']))
$user->info['edit_add_lines'] = 0;
if (!isset($user->info['edit_del_lines']))
$user->info['edit_del_lines'] = 0;
if (!isset($user->info['edit_add_chars']))
$user->info['edit_add_chars'] = 0;
if (!isset($user->info['edit_del_chars']))
$user->info['edit_del_chars'] = 0;
// added/deleted lines
$user->info['edit_add_lines']+= $retval['add'];
$user->info['edit_del_lines']+= $retval['del'];
// added/deleted chars
$user->info['edit_add_chars']+= $retval['add_chars'];
$user->info['edit_del_chars']+= $retval['del_chars'];
// save user
$this->udb->saveUser($user);
}
$indexer = $this->lazyLoad('titleindexer');
if ($is_new) $indexer->addPage($page->name);
else $indexer->update($page->name); // just update mtime
return 0;
}
function deletePage($page,$options='') {
if (empty($options['.force']) && !$this->_isWritable($page->name)) {
return -1;
}
if (!empty($this->use_x_forwarded_for))
$REMOTE_ADDR = get_log_addr();
else
$REMOTE_ADDR = $_SERVER['REMOTE_ADDR'];
$comment=$options['comment'];
$user=&$this->user;
$action = 'DELETE';
if (!empty($options['.revoke']))
$action = 'REVOKE';
// check abusing FIXME
if (!empty($this->use_abusefilter)) {
$params = array();
$params['retval'] = &$options['retval'];
$params['id'] = ($user->id == 'Anonymous') ? $REMOTE_ADDR : $user->id;
if (is_string($this->use_abusefilter))
$filtername = $this->use_abusefilter;
else
$filtername = 'default';
$ret = call_abusefilter($filtername, 'delete', $params);
if ($ret === false) return -1;
}
$comment = trim($comment);
$comment = strtr(strip_tags($options['comment']),
array("\r\n"=>' ', "\r"=>' ',"\n"=>' ', "\t"=>' '));
// strip out all action flags FIXME
$comment = preg_replace('@^{(SAVE|CREATE|DELETE|RENAME|REVERT|UPLOAD|ATTDRW|FORK|REVOKE|MINOR|BOTFIX)}:?@', '', $comment);
$tag = '{'.$action.'}';
if (!empty($comment))
$comment = $tag.': '.$comment;
else
$comment = $tag;
$keyname=$this->_getPageKey($page->name);
$deleted = false;
if (file_exists($this->text_dir.'/'.$keyname)) {
$deleted = @unlink($this->text_dir.'/'.$keyname);
// fail to delete
if (!$deleted)
return -1;
}
if (!empty($this->version_class)) {
$version = $this->lazyLoad('version', $this);
if ($deleted && !empty($this->log_deletion)) {
// make a empty file to log deletion
touch($this->text_dir.'/'.$keyname);
$log = $REMOTE_ADDR.';;'.$user->id.';;'.$comment;
$ret = $version->ci($page->name,$log, true); // force
}
// delete history
if (!empty($this->delete_history) && in_array($options['id'], $this->owners)
&& !empty($options['history']))
$version->delete($page->name);
// delete the empty file again
if ($deleted)
@unlink($this->text_dir.'/'.$keyname);
}
// history deletion case by owners
if (!$deleted) return 0;
if (empty($options['.nolog']))
$this->addLogEntry($page->name, $REMOTE_ADDR, $comment, $action);
$indexer = $this->lazyLoad('titleindexer');
$indexer->deletePage($page->name);
// remove pagelinks and backlinks
store_pagelinks($page->name, array());
// remove aliases
if (!empty($this->use_alias))
store_aliases($page->name, array());
// remove redirects
update_redirects($page->name, null);
$handle= opendir($this->cache_dir);
$permanents = array('backlinks', 'keywords', 'aliases', 'wordindex', 'redirect');
while ($file= readdir($handle)) {
if ($file[0] != '.' and is_dir("$this->cache_dir/$file") and is_file($this->cache_dir.'/'.$file.'/.info')) {
// do not delete permanent caches
if (in_array($file, $permanents)) continue;
$cache= new Cache_text($file);
$cache->remove($page->name);
# blog cache
if ($file == 'blogchanges') {
$files = array();
$cache->_caches($files, array('prefix'=>1));
foreach ($files as $file) {
#echo $keyname.';'.$fcache."\n";
if (preg_match("/\d+_2e$keyname$/", $file))
unlink($this->cache_dir.'/'.$file);
}
} # for blog cache
}
}
return 0;
}
function renamePage($pagename, $new, $options = array()) {
if (!$this->_isWritable($pagename)) {
return -1;
}
if (!empty($this->use_x_forwarded_for))
$REMOTE_ADDR = get_log_addr();
else
$REMOTE_ADDR = $_SERVER['REMOTE_ADDR'];
// setup log
$user = &$this->user;
$myid = $user->id;
if ($myid == 'Anonymous' and !empty($user->verified_email))
$myid.= '-'.$user->verified_email;
$renamed = sprintf("Rename [[%s]] to [[%s]]", $pagename, $new);
$comment = trim($comment);
$comment = strtr(strip_tags($options['comment']),
array("\r\n"=>' ', "\r"=>' ',"\n"=>' ', "\t"=>' '));
// strip out all action flags FIXME
$comment = preg_replace('@^{(SAVE|CREATE|DELETE|RENAME|REVERT|UPLOAD|ATTDRW|FORK|REVOKE|MINOR|BOTFIX)}:?@', '', $comment);
if (isset($comment[0]))
$renamed.= ': '.$comment;
else
$renamed.= '.';
$log = $REMOTE_ADDR.';;'.$myid.';;{RENAME}: '.$renamed;
$options['log'] = $log;
$options['pagename'] = $pagename;
$with_history = false;
$ret = 0;
if (!empty($this->rename_with_history) || !empty($options['history']))
$with_history = true;
$okey = $this->getPageKey($pagename);
$nkey = $this->getPageKey($new);
$ret = rename($okey, $nkey);
if (!$ret)
return -1;
if ($ret && $with_history && $this->version_class) {
$version = $this->lazyLoad('version', $this);
$ret = $version->rename($pagename, $new, $options);
// fail to rename
if ($ret < 0 || $ret === false)
return -1;
}
// remove pagelinks and backlinks
store_pagelinks($pagename, array());
// remove aliases
if (!empty($this->use_alias))
store_aliases($pagename, array());
$okeyname=$this->_getPageKey($pagename);
$keyname=$this->_getPageKey($new);
$newdir=$this->upload_dir.'/'.$keyname;
$olddir=$this->upload_dir.'/'.$this->_getPageKey($pagename);
if (!file_exists($newdir) and file_exists($olddir))
rename($olddir,$newdir);
$renameas = sprintf(_("Renamed as [[%s]]"), $new);
$renamefrom = sprintf(_("Renamed from [[%s]]"), $pagename);
$this->addLogEntry($pagename, $REMOTE_ADDR, $renameas, 'RENAME');
$this->addLogEntry($new, $REMOTE_ADDR, $renamefrom, 'RENAME');
$indexer = $this->lazyLoad('titleindexer');
$indexer->renamePage($pagename, $new);
}
function _isWritable($pagename) {
$key=$this->getPageKey($pagename);
$dir=dirname($key);
# global lock
if (@file_exists($this->text_dir.'/.lock')) return false;
if (@file_exists($dir.'/.lock')) return false;
# True if page can be changed
return @is_writable($key) or !@file_exists($key);
}
function getPerms($pagename) {
$key=$this->getPageKey($pagename);
if (file_exists($key))
return fileperms($key);
return 0666;
}
function setPerms($pagename,$perms) {
$om=umask(0700);
$key=$this->getPageKey($pagename);
if (file_exists($key)) chmod($key,$perms);
umask($om);
}
}
class WikiPage {
var $fp;
var $filename;
var $pi = null;
var $rev;
var $body;
function WikiPage($name,$options="") {
if (!empty($options['rev']))
$this->rev=$options['rev'];
else
$this->rev=0; # current rev.
$this->name= $name;
$this->filename= $this->_filename($name);
$this->urlname= _rawurlencode($name);
$this->body= "";
$this->title=get_title($name);
#$this->title=preg_replace("/((?<=[A-Za-z0-9])[A-Z][a-z0-9])/"," \\1",$name);
}
function _filename($pagename) {
# have to be factored out XXX
# Return filename where this word/page should be stored.
global $DBInfo;
return $DBInfo->getPageKey($pagename);
}
function exists() {
# Does a page for the given word already exist?
return @file_exists($this->filename);
}
# function writable() {
# # True if page can be changed
# return is_writable($this->filename) or !$this->exists();
# }
function mtime () {
return @filemtime($this->filename);
}
function etag($params = array()) {
global $DBInfo;
$dep = '';
$tag = '';
if (!empty($DBInfo->etag_seed))
$tag.= $DBInfo->etag_seed;
// check some parameters
foreach (array('action', 'lang', 'theme') as $k)
if (isset($params[$k])) $tag.= $params[$k];
if (!empty($params['deps'])) {
foreach ($params['deps'] as $d) {
!empty($params[$d]) ? $tag.= $params[$d] : true;
}
}
if ($params['action'] != 'raw' || empty($params['nodep']))
$dep.= $DBInfo->mtime();
return md5($this->mtime().$dep.$tag.$this->name);
}
function size() {
if ($this->fsize) return $this->fsize;
$this->fsize=@filesize($this->filename);
return $this->fsize;
}
function lines() {
return get_file_lines($this->filename);
}
function get_raw_body($options='') {
global $DBInfo;
if ($this->body && empty($options['rev']))
return $this->body;
$rev= !empty($options['rev']) ? $options['rev']:(!empty($this->rev) ? $this->rev:'');
if (!empty($rev)) {
if (!empty($DBInfo->version_class)) {
$version = $DBInfo->lazyLoad('version', $DBInfo);
$out = $version->co($this->name,$rev, $options);
return $out;
} else {
return _("Version info does not supported in this wiki");
}
}
$fp=@fopen($this->filename,"r");
if (!is_resource($fp)) {
if (file_exists($this->filename)) {
$out="You have no permission to see this page.\n\n";
$out.="See MoniWiki/AccessControl\n";
return $out;
}
$out=_("File does not exist");
return $out;
}
$this->fsize=filesize($this->filename);
if ($this->fsize > 0)
$body=fread($fp,$this->fsize);
fclose($fp);
$this->body=$body;
return $body;
}
function _get_raw_body() {
$fp=@fopen($this->filename,"r");
if (is_resource($fp)) {
$size=filesize($this->filename);
if ($size >0)
$this->body=fread($fp,$size);
fclose($fp);
} else
return '';
return $this->body;
}
function set_raw_body($body) {
$this->body=$body;
}
function update() {
if ($this->body)
$this->write($this->body);
}
function write($body) {
#if ($body)
$this->body=$body;
}
function get_rev($mtime="",$last=0) {
global $DBInfo;
if (!empty($DBInfo->version_class)) {
$version = $DBInfo->lazyLoad('version', $DBInfo);
$rev= $version->get_rev($this->name,$mtime,$last);
if (!empty($rev)) return $rev;
}
return '';
}
function get_info($rev='') {
global $DBInfo;
$infos = array();
if (empty($rev))
$rev=$this->get_rev('',1);
if (empty($rev)) return false;
if (!empty($DBInfo->version_class)) {
$opt = '';
$version = $DBInfo->lazyLoad('version', $DBInfo);
$out = $version->rlog($this->name,$rev,$opt);
} else {
return false;
}
$state=0;
if (isset($out)) {
for ($line=strtok($out,"\n"); $line !== false;$line=strtok("\n")) {
if ($state == 0 and preg_match("/^date:\s.*$/",$line)) {
$info = array();
$tmp=preg_replace("/date:\s(.*);\s+author:.*;\s+state:.*;/","\\1",rtrim($line));
$tmp=explode('lines:',$tmp);
$info[0]=$tmp[0];
$info[1]=isset($tmp[1]) ? $tmp[1] : '';
$state=1;
} else if ($state) {
list($info[2],$info[3],$info[4])=explode(';;',$line,3);
$infos[] = $info;
$state = 0;
}
}
}
return $infos;
}
function get_redirect() {
$body = $this->get_raw_body();
if ($body[0] == '#' and ($p = strpos($body, "\n")) !== false) {
$line = substr($body, 0, $p);
if (preg_match('/#redirect\s/i', $line)) {
list($tag, $val) = explode(' ', $line, 2);
if (isset($val[0])) return $val;
}
}
}
function get_instructions($body = '', $params = array()) {
global $Config;
$pikeys=array('#redirect','#action','#title','#notitle','#keywords','#noindex',
'#format','#filter','#postfilter','#twinpages','#notwins','#nocomment','#comment',
'#language','#camelcase','#nocamelcase','#cache','#nocache','#alias', '#linenum', '#nolinenum',
'#description', '#image',
'#noads', // hide google ads
'#singlebracket','#nosinglebracket','#rating','#norating','#nodtd');
$pi=array();
$format='';
// get page format from $pagetype
if ( empty($this->pi['#format']) and !empty($Config['pagetype'])) {
preg_match('%(:|/)%',$this->name,$sep);
$key=strtok($this->name,':/');
if (isset($Config['pagetype'][$key]) and $f=$Config['pagetype'][$key]) {
$p=preg_split('%(:|/)%',$f);
$p2=strlen($p[0].$p[1])+1;
$p[1]=$p[1] ? $f{strlen($p[0])}.$p[1]:'';
$p[2]=$p[2] ? $f{$p2}.$p[2]:'';
$format=$p[0];
if ($sep[1]) { # have : or /
$format = ($sep[1]==$p[1]{0}) ? substr($p[1],1):
(($sep[1]==$p[2]{0}) ? substr($p[2],1):'plain');
}
} else if (isset($Config['pagetype']['*']))
$format=$Config['pagetype']['*']; // default page type
} else {
if (empty($body) and !empty($this->pi['#format']))
$format=$this->pi['#format'];
}
$update_pi = false;
if (empty($body)) {
if (!$this->exists()) return array();
if (isset($this->pi)) return $this->pi;
$pi_cache = new Cache_text('PI');
if (empty($params['refresh']) and $this->mtime() < $pi_cache->mtime($this->name)) {
$pi = $pi_cache->fetch($this->name);
if (!isset($pi['#format']))
$pi['#format'] = $Config['default_markup'];
return $pi;
}
$body=$this->get_raw_body();
$update_pi = true;
}
if (!empty($Config['use_metadata'])) {
// FIXME experimental
include_once('lib/metadata.php');
list($this->metas,$nbody)=_get_metadata($body);
if ($nbody!=null) $body=$nbody;
}
if (!$format and $body[0] == '<') {
list($line, $dummy)= explode("\n", $body,2);
if (substr($line,0,6) == '<?xml ')
#$format='xslt';
$format='xsltproc';
elseif (preg_match('/^<\?php(\s|\b)/',$line))
$format='php'; # builtin php detect
} else {
if ($body[0] == '#' and $body[1] =='!') {
list($format, $body) = explode("\n", $body, 2);
$format = rtrim(substr($format, 2));
}
// not parsed lines are comments
$notparsed=array();
$pilines=array();
$body_start = 0;
while ($body and $body[0] == '#') {
$body_start++;
# extract first line
list($line, $body)= explode("\n", $body,2);
if ($line=='#') break;
else if ($line[1]=='#') { $notparsed[]=$line; continue;}
$pilines[]=$line;
$val = '';
if (($pos = strpos($line, ' ')) !== false)
list($key,$val)= explode(' ',$line,2);
else
$key = trim($line);
$key=strtolower($key);
$val=trim($val);
if (in_array($key,$pikeys)) { $pi[$key]=$val ? $val:1; }
else {
$notparsed[]=$line;
array_pop($pilines);
}
}
$piline=implode("\n",$pilines);
$piline=$piline ? $piline."\n":'';
#
if (isset($pi['#notwins'])) $pi['#twinpages']=0;
if (isset($pi['#nocamelcase'])) $pi['#camelcase']=0;
if (isset($pi['#nocache'])) $pi['#cache']=0;
if (isset($pi['#nofilter'])) unset($pi['#filter']);
if (isset($pi['#nosinglebracket'])) $pi['#singlebracket']=0;
if (isset($pi['#nolinenum'])) $pi['#linenum']=0;
}
if (empty($pi['#format']) and !empty($format))
$pi['#format'] = $format; // override default
if (!empty($pi['#format']) and ($p = strpos($pi['#format'],' '))!== false) {
$pi['args'] = substr($pi['#format'],$p+1);
$pi['#format']= substr($pi['#format'],0,$p);
}
if (!empty($piline)) $pi['raw']= $piline;
if (!empty($body_start)) $pi['start_line'] = $body_start;
if ($update_pi) {
$pi_cache->update($this->name, $pi);
$this->cache_instructions($pi, $params);
}
if (!isset($pi['#format']))
$pi['#format']= $Config['default_markup'];
return $pi;
}
function cache_instructions($pi, $params = array()) {
global $Config;
global $DBInfo;
$pagename = $this->name;
// update aliases
if (!empty($Config['use_alias'])) {
$ac = new Cache_text('alias');
// is it removed ?
if ($ac->exists($pagename) and
empty($pi['#alias']) and empty($pi['#title'])) {
// remove aliases
store_aliases($pagename, array());
} else if (!$ac->exists($pagename) or
$ac->mtime($pagename) < $this->mtime() or !empty($_GET['update_alias'])) {
$as = array();
// parse #alias
if (!empty($pi['#alias']))
$as = get_csv($pi['#alias']);
// add #title as a alias
if (!empty($pi['#title']))
$as[] = $pi['#title'];
// update aliases
store_aliases($pagename, $as);
}
}
// update redirects cache
$redirect = isset($pi['#redirect'][0]) ? $pi['#redirect'] : null;
update_redirects($pagename, $redirect, $params['refresh']);
if (!empty($Config['use_keywords']) or !empty($Config['use_tagging']) or !empty($_GET['update_keywords'])) {
$tcache= new Cache_text('keyword');
$cache = new Cache_text('keywords');
$cur = $tcache->fetch($pagename);
if (empty($cur)) $cur = array();
$keys = array();
if (empty($pi['#keywords'])) {
$tcache->remove($pagename);
} else {
$keys = explode(',', $pi['#keywords']);
$keys = array_map('trim', $keys);
if (!$tcache->exists($pagename) or
$tcache->mtime($pagename) < $this->mtime() or
!empty($_GET['update_keywords'])) {
$tcache->update($pagename, $keys);
}
}
$adds = array_diff($keys, $cur);
$dels = array_diff($cur, $keys);
// merge new keywords
foreach ($adds as $a) {
if (!isset($a[0])) continue;
$l = $cache->fetch($a);
if (!is_array($l)) $l = array();
$l = array_merge($l, array($pagename));
$cache->update($a, $l);
}
// remove deleted keywords
foreach ($dels as $d) {
if (!isset($d[0])) continue;
$l = $cache->fetch($d);
if (!is_array($l)) $l = array();
$l = array_diff($l, array($pagename));
$cache->update($d, $l);
}
}
if (!empty($pi['#title']) and !empty($Config['use_titlecache'])) {
$tc = new Cache_text('title');
$old = $tc->fetch($pagename);
if (!isset($pi['#title']))
$tc->remove($pagename);
else if ($old != $pi['#title'] or !$tcache->exists($pagename) or !empty($_GET['update_title']))
$tc->update($pagename,$pi['#title']);
}
return;
}
}
class Formatter {
var $sister_idx=1;
var $group='';
var $use_purple=1;
var $purple_number=0;
var $java_scripts=array();
function Formatter($page="",$options=array()) {
global $DBInfo;
$this->page=$page;
$this->head_num=1;
$this->head_dep=0;
$this->sect_num=0;
$this->toc=0;
$this->toc_prefix='';
if (!empty($options['prefix'])) {
$this->prefix = $options['prefix'];
} else if (!empty($DBInfo->base_url_prefix)) {
// force the base url prefix
$this->prefix = $DBInfo->base_url_prefix;
} else {
// call get_scriptname() to get the base url prefix
$this->prefix = get_scriptname();
}
$this->self_query='';
$this->url_prefix= $DBInfo->url_prefix;
$this->imgs_dir= $DBInfo->imgs_dir;
$this->imgs_url_interwiki=$DBInfo->imgs_url_interwiki;
$this->imgs_dir_url=$DBInfo->imgs_dir_url;
$this->actions= $DBInfo->actions;
$this->inline_latex=
$DBInfo->inline_latex == 1 ? 'latex':$DBInfo->inline_latex;
$this->use_purple=$DBInfo->use_purple;
$this->section_edit=$DBInfo->use_sectionedit;
// check folding option
$this->use_folding = !empty($DBInfo->use_folding) ? $DBInfo->use_folding : 0;
$this->auto_linebreak=!empty($DBInfo->auto_linebreak) ? 1 : 0;
$this->nonexists=$DBInfo->nonexists;
$this->url_mappings=&$DBInfo->url_mappings;
$this->css_friendly=$DBInfo->css_friendly;
$this->use_smartdiff=!empty($DBInfo->use_smartdiff) ? $DBInfo->use_smartdiff : 0;
$this->use_easyalias=$DBInfo->use_easyalias;
$this->use_group=!empty($DBInfo->use_group) ? $DBInfo->use_group : 0;
$this->use_htmlcolor = !empty($DBInfo->use_htmlcolor) ? $DBInfo->use_htmlcolor : 0;
// strtr() old wiki markups
$this->trtags = !empty($DBInfo->trtags) ? $DBInfo->trtags : null;
$this->submenu=!empty($DBInfo->submenu) ? $DBInfo->submenu : null;
$this->email_guard=$DBInfo->email_guard;
$this->interwiki_target=!empty($DBInfo->interwiki_target) ?
' target="'.$DBInfo->interwiki_target.'"':'';
$this->filters=!empty($DBInfo->filters) ? $DBInfo->filters : null;
$this->postfilters=!empty($DBInfo->postfilters) ? $DBInfo->postfilter : null;
$this->use_rating=!empty($DBInfo->use_rating) ? $DBInfo->use_rating : 0;
$this->use_metadata=!empty($DBInfo->use_metadata) ? $DBInfo->use_metadata : 0;
$this->use_smileys=$DBInfo->use_smileys;
$this->use_namespace=!empty($DBInfo->use_namespace) ? $DBInfo->use_namespace : '';
// use mediawiki like built-in category support
if (!empty($DBInfo->use_builtin_category) && !empty($DBInfo->category_regex)) {
$this->use_builtin_category = true;
$this->category_regex = $DBInfo->category_regex;
} else {
$this->use_builtin_category = false;
}
$this->mediawiki_style=!empty($DBInfo->mediawiki_style) ? 1 : '';
$this->markdown_style = !empty($DBInfo->markdown_style) ? 1 : 0;
$this->lang=$DBInfo->lang;
$this->udb=&$DBInfo->udb;
$this->user=&$DBInfo->user;
$this->check_openid_url=!empty($DBInfo->check_openid_url) ? $DBInfo->check_openid_url : 0;
$this->register_javascripts($DBInfo->javascripts);
$this->fetch_action = !empty($DBInfo->fetch_action) ? $DBInfo->fetch_action : null;
$this->fetch_images = !empty($DBInfo->fetch_images) ? $DBInfo->fetch_images : 0;
$this->fetch_imagesize = !empty($DBInfo->fetch_imagesize) ? $DBInfo->fetch_imagesize : 0;
if (empty($this->fetch_action))
$this->fetch_action = $this->link_url('', '?action=fetch&amp;url=');
else
$this->fetch_action = $DBInfo->fetch_action;
// the original source site for mirror sites
$this->source_site = !empty($DBInfo->source_site) ? $DBInfo->source_site : null;
// call externalimage macro for these external images
$this->external_image_regex = !empty($DBInfo->external_image_regex) ? $DBInfo->external_image_regex : 0;
// use thumbnail by default
$this->use_thumb_by_default = !empty($DBInfo->use_thumb_by_default) ? $DBInfo->use_thumb_by_default : 0;
$this->thumb_width = !empty($DBInfo->thumb_width) ? $DBInfo->thumb_width : 320;
if ($this->use_group and ($p=strpos($page->name,"~")))
$this->group=substr($page->name,0,$p+1);
$this->sister_on=1;
$this->sisters=array();
$this->foots=array();
$this->pagelinks=array();
$this->aliases=array();
$this->icons="";
$this->quote_style= !empty($DBInfo->quote_style) ? $DBInfo->quote_style:'quote';
$this->themedir= !empty($DBInfo->themedir) ? $DBInfo->themedir:dirname(__FILE__);
$this->themeurl= !empty($DBInfo->themeurl) ? $DBInfo->themeurl:$DBInfo->url_prefix;
$this->set_theme(!empty($options['theme']) ? $options['theme'] : '');
// setup for html5
$this->tags = array();
if (!empty($DBInfo->html5) || !empty($this->html5)) {
$this->html5 = !empty($DBInfo->html5) ? $DBInfo->html5 : $this->html5;
$this->tags['article'] = 'article';
$this->tags['header'] = 'header';
$this->tags['footer'] = 'footer';
$this->tags['nav'] = 'nav';
} else {
$this->html5 = null;
$this->tags['article'] = 'div';
$this->tags['header'] = 'div';
$this->tags['footer'] = 'div';
$this->tags['nav'] = 'div';
}
$this->NULL='';
if(getenv("OS")!="Windows_NT") $this->NULL=' 2>/dev/null';
$this->_macrocache=0;
$this->wikimarkup=0;
$this->pi=array();
$this->external_on=0;
$this->external_target='';
if (!empty($DBInfo->external_target))
$this->external_target='target="'.$DBInfo->external_target.'"';
// set filter
if (!empty($this->filters)) {
if (!is_array($this->filters)) {
$this->filters=preg_split('/(\||,)/',$this->filters);
}
} else {
$this->filters = '';
}
if (!empty($this->postfilters)) {
if (!is_array($this->postfilters)) {
$this->postfilters=preg_split('/(\||,)/',$this->postfilters);
}
} else {
$this->postfilters = '';
}
$this->baserule=array("/(?<!\<)<(?=[^<>]*>)/",
"/&(?!([^&;]+|#[0-9]+|#x[0-9a-fA-F]+);)/",
"/(?<!')'''((?U)(?:[^']|(?<!')'(?!')|'')*)?'''(?!')/",
"/''''''/", // SixSingleQuote
"/(?<!')''((?:[^']|[^']'(?!'))*)''(?!')/",
"/`(?<!\s)(?!`)([^`']+)(?<!\s)'(?=\s|$)/",
"/`(?<!\s)(?U)(.*)(?<!\s)`/",
"/^(={4,})$/",
"/,,([^,]{1,40}),,/",
"/\^([^ \^]+)\^(?=\s|$)/",
"/\^\^(?<!\s)(?!\^)(?U)(.+)(?<!\s)\^\^/",
"/__(?<!\s)(?!_)(?U)(.+)(?<!\s)__/",
"/--(?<!\s)(?!-)(?U)(.+)(?<!\s)--/",
"/~~(?<!\s)(?!~)(?U)(.+)(?<!\s)~~/",
#"/(\\\\\\\\)/", # tex, pmWiki
);
$this->baserepl=array("&lt;",
"&amp;",
"<strong>\\1</strong>",
"<strong></strong>",
"<em>\\1</em>",
"&#96;\\1'","<code>\\1</code>",
"<br clear='all' />",
"<sub>\\1</sub>",
"<sup>\\1</sup>",
"<sup>\\1</sup>",
"<em class='underline'>\\1</em>",
"<del>\\1</del>",
"<del>\\1</del>",
#"<br />\n",
);
// set extra baserule
if (!empty($DBInfo->baserule)) {
foreach ($DBInfo->baserule as $rule=>$repl) {
$t = @preg_match($rule,$repl);
if ($t!==false) {
$this->baserule[]=$rule;
$this->baserepl[]=$repl;
}
}
}
// check and prepare $url_mappings
if (!empty($DBInfo->url_mappings)) {
if (!is_array($DBInfo->url_mappings)) {
$maps=explode("\n",$DBInfo->url_mappings);
$tmap=array();
foreach ($maps as $map) {
if (strpos($map,' ')) {
$key=strtok($map,' ');
$val=strtok('');
$tmap["$key"]=$val;
}
}
$this->url_mappings=$tmap;
}
}
# recursive footnote regex
$this->footrule='\[\*[^\[\]]*((?:[^\[\]]++|\[(?13)\])*)\]';
}
/**
* init Smileys
* load smileys and set smily_rule and smiley_repl
*/
function initSmileys() {
$this->smileys = getSmileys();
$tmp = array_keys($this->smileys);
$tmp = array_map('_preg_escape', $tmp);
$rule = implode('|', $tmp);
$this->smiley_rule = '/(?<=\s|^|>)('.$rule.')(?=\s|<|$)/';
}
function set_wordrule($pis=array()) {
global $DBInfo;
$single=''; # single bracket
$camelcase= isset($pis['#camelcase']) ? $pis['#camelcase']:
$DBInfo->use_camelcase;
if (!empty($pis['#singlebracket']) or !empty($DBInfo->use_singlebracket))
$single='?';
#$punct="<\"\'}\]\|;,\.\!";
#$punct="<\'}\]\)\|;\.\!"; # , is omitted for the WikiPedia
#$punct="<\'}\]\|\.\!"; # , is omitted for the WikiPedia
$punct="<\'}\]\|\.\!\010\006"; # , is omitted for the WikiPedia
$punct="<>\"\'}\]\|\.\!\010\006"; # " and > added
$url="wiki|http|https|ftp|nntp|news|irc|telnet|mailto|file|attachment";
if (!empty($DBInfo->url_schemas)) $url.='|'.$DBInfo->url_schemas;
$this->urls=$url;
$urlrule="((?:$url):\"[^\"]+\"[^\s$punct]*|(?:$url):(?:[^\s$punct]|(\.?[^\s$punct]))+(?<![,\.\):;\"\'>]))";
#$urlrule="((?:$url):(\.?[^\s$punct])+)";
#$urlrule="((?:$url):[^\s$punct]+(\.?[^\s$punct]+)+\s?)";
# solw slow slow
#(?P<word>(?:/?[A-Z]([a-z0-9]+|[A-Z]*(?=[A-Z][a-z0-9]|\b))){2,})
$this->wordrule=
# nowiki
"!?({{{(?:(?:[^{}]+|{[^{}]+}(?!})|(?<!{){{1,2}(?!{)|(?<!})}{1,2}(?!})|(?<=\\\\)[{}]{3}(?!}))|(?2))++}}})|".
# {{{{{{}}}, {{{}}}}}}, {{{}}}
"(?:(?!<{{{){{{}}}(?!}}})|{{{(?:{{{|}}})}}})|".
# single bracketed rule [http://blah.blah.com Blah Blah]
"(?:\[\^?($url):[^\s\]]+(?:\s[^\]]+)?\])|".
# InterWiki
# strict but slow
#"\b(".$DBInfo->interwikirule."):([^<>\s\'\/]{1,2}[^\(\)<>\s\']+\s{0,1})|".
#"\b([A-Z][a-zA-Z]+):([^<>\s\'\/]{1,2}[^\(\)<>\s\']+\s{0,1})|".
#"\b([A-Z][a-zA-Z]+):([^<>\s\'\/]{1,2}[^\(\)<>\s\']+[^\(\)<>\s\',\.:\?\!]+)|".
"(?:\b|\^?|!?)(?:[A-Z][a-zA-Z0-9]+):(?:\"[^\"]+\"|[^:\(\)<>\s\']?[^\s<\'\",\!\010\006]+(?:\s(?![\x21-\x7e]))?)(?<![,\.\)>])|".
#"(?:\b|\^?)(?:[A-Z][a-zA-Z]+):(?:[^:\(\)<>\s\']?[^\s<\'\",:\!\010\006]+(?:\s(?![\x21-\x7e]))?(?<![,\.\)>]))|".
#"(\b|\^?)([A-Z][a-zA-Z]+):([^:\(\)<>\s\']?[^<>\s\'\",:\?\!\010\006]*(\s(?![\x21-\x7e]))?)";
# for PR #301713
#
# new regex pattern for
# * double bracketted rule similar with MediaWiki [[Hello World]]
# * single bracketted words [Hello World] etc.
# * single bracketted words with double quotes ["Hello World"]
# * double bracketted words with double quotes [["Hello World"]]
"(?<!\[)\!?\[(\[)$single(\")?(?:[^\[\]\",<\s'\*]?[^\[\]]{0,255}[^\"])(?(5)\"(?:[^\"\]]*))(?(4)\])\](?!\])";
if ($camelcase)
$this->wordrule.='|'.
"(?<![a-zA-Z0-9#])\!?(?:((\.{1,2})?\/)?[A-Z]([A-Z]+[0-9a-z]|[0-9a-z]+[A-Z])[0-9a-zA-Z]*)+\b";
else
# only bangmeta syntax activated
$this->wordrule.='|'.
"(?<![a-zA-Z])\!(?:((\.{1,2})?\/)?[A-Z]([A-Z]+[0-9a-z]|[0-9a-z]+[A-Z])[0-9a-zA-Z]*)+\b";
# "(?<!\!|\[\[)\b(([A-Z]+[a-z0-9]+){2,})\b|".
# "(?<!\!|\[\[)((?:\/?[A-Z]([a-z0-9]+|[A-Z]*(?=[A-Z][a-z0-9]|\b))){2,})\b|".
# WikiName rule: WikiName ILoveYou (imported from the rule of NoSmoke)
# and protect WikiName rule !WikiName
#"(?:\!)?((?:\.{1,2}?\/)?[A-Z]([A-Z]+[0-9a-z]|[0-9a-z]+[A-Z])[0-9a-zA-Z]*)+\b|".
$this->wordrule.='|'.
# double bracketed rule similar with MediaWiki [[Hello World]]
#"(?<!\[)\!?\[\[([^\[:,<\s'][^\[:,>]{1,255})\]\](?!\])|".
# bracketed with double quotes ["Hello World"]
#"(?<!\[)\!?\[\\\"([^\\\"]+)\\\"\](?!\])|".
# "(?<!\[)\[\\\"([^\[:,]+)\\\"\](?!\])|".
"($urlrule)|".
# single linkage rule ?hello ?abacus
#"(\?[A-Z]*[a-z0-9]+)";
"(\?[A-Za-z0-9]+)";
#if ($sbracket)
# # single bracketed name [Hello World]
# $this->_wordrule.= "|(?<!\[)\!?\[([^\[,<\s'][^\[,>]{1,255})\](?!\])";
#else
# # only anchor [#hello], footnote [* note] allowed
# $this->wordrule.= "|(?<!\[)\!?\[([#\*\+][^\[:,>]{1,255})\](?!\])";
return $this->wordrule;
}
function header($args) {
header($args);
}
function set_theme($theme="") {
global $DBInfo;
if (!empty($theme)) {
$this->themedir.="/theme/$theme";
$this->themeurl.="/theme/$theme";
}
$data=array();
if (file_exists(dirname(__FILE__).'/theme.php')) {
$used=array('icons','icon');
$options['themedir']='.';
$options['themeurl']=$DBInfo->url_prefix;
$options['frontpage']=$DBInfo->frontpage;
$data=getConfig(dirname(__FILE__).'/theme.php',$options);
foreach ($data as $k=>$v)
if (!in_array($k, $used)) unset($data[$k]);
}
$options['themedir']=$this->themedir;
$options['themeurl']=$this->themeurl;
$options['frontpage']=$DBInfo->frontpage;
$this->icon=array();
if (file_exists($this->themedir."/theme.php")) {
$data0=getConfig($this->themedir."/theme.php",$options);
if (!empty($data0))
$data=array_merge($data0,$data);
}
if (!empty($data)) {
# read configurations
while (list($key,$val) = each($data)) $this->$key=$val;
}
if (!empty($DBInfo->icon))
$this->icon=array_merge($DBInfo->icon,$this->icon);
if (!isset($this->icon_bra)) {
$this->icon_bra=$DBInfo->icon_bra;
$this->icon_cat=$DBInfo->icon_cat;
$this->icon_sep=$DBInfo->icon_sep;
}
if (empty($this->menu)) {
$this->menu=&$DBInfo->menu;
}
if (!isset($this->menu_bra)) {
$this->menu_bra=!empty($DBInfo->menu_bra) ? $DBInfo->menu_bra : '';
$this->menu_cat=!empty($DBInfo->menu_cat) ? $DBInfo->menu_cat : '';
$this->menu_sep=!empty($DBInfo->menu_sep) ? $DBInfo->menu_sep : '';
}
if (!$this->icons)
$this->icons = array();
if (!empty($DBInfo->icons))
$this->icons = array_merge($DBInfo->icons,$this->icons);
if (empty($this->icon_list)) {
$this->icon_list=!empty($DBInfo->icon_list) ? $DBInfo->icon_list:null;
}
if (empty($this->purple_icon)) {
$this->purple_icon=$DBInfo->purple_icon;
}
if (empty($this->perma_icon)) {
$this->perma_icon=$DBInfo->perma_icon;
}
}
function include_theme($theme,$file='default',$params=array()) {
$theme=trim($theme,'.-_');
$theme=preg_replace(array('/\/+/','/\.+/'),array('/',''),$theme);
if (preg_match('/_tpl$/',$theme)) {
$type='tpl';
} else {
$type='php';
}
$theme_dir='theme/'.$theme;
if (file_exists($theme_dir."/theme.php")) {
$this->_vars['_theme']=_load_php_vars($theme_dir."/theme.php",$params);
}
$theme_path=$theme_dir.'/'.$file.'.'.$type;
if (!file_exists($theme_path)) {
trigger_error(sprintf(_("File '%s' does not exist."),$file),E_USER_NOTICE);
return '';
}
switch($type) {
case 'tpl':
$params['path']=$theme_path;
$out= $this->processor_repl('tpl_','',$params);
break;
case 'php':
global $Config;
$TPL_VAR=&$this->_vars;
if (isset($TPL_VAR['_theme']) and is_array($TPL_VAR['_theme']) and $TPL_VAR['_theme']['compat'])
extract($TPL_VAR);
if ($params['print']) {
$out=include $theme_path;
} else {
ob_start();
include $theme_path;
$out=ob_get_contents();
ob_end_clean();
}
break;
default:
break;
}
return $out;
}
function _diff_repl($arr) {
if ($arr[1]{0}=="\010") { $tag='ins'; $sty='added'; }
else { $tag='del'; $sty='removed'; }
if (strpos($arr[2],"\n") !== false)
return "<div class='diff-$sty'>".$arr[2]."</div>";
return "<$tag class='diff-$sty'>".$arr[2]."</$tag>";
}
function write($raw) {
echo $raw;
}
function _url_mappings_callback($m) {
return $this->url_mappings[$m[1]];
}
function link_repl($url,$attr='',$opts=array()) {
$nm = 0;
$force = 0;
$double_bracket = false;
if (is_array($url)) $url=$url[1];
#if ($url[0]=='<') { echo $url;return $url;}
$url=str_replace('\"','"',$url); // XXX
$bra = '';
$ket = '';
if ($url{0}=='[') {
$bra='[';
$ket=']';
$url=substr($url,1,-1);
$force=1;
}
// set nomacro option for callback
if (!empty($this->nomacro)) $opts['nomacro'] = 1;
switch ($url[0]) {
case '{':
$url=substr($url,3,-3);
if (empty($url))
return "<code class='nowiki'></code>"; # No link
if (preg_match('/^({([^{}]+)})/s',$url,$sty)) { # textile like styling
$url=substr($url,strlen($sty[1]));
$url = preg_replace($this->baserule, $this->baserepl, $url); // apply inline formatting rules
return "<span style='$sty[2]'>$url</span>";
}
if ($url[0]=='#' and ($p=strpos($url,' '))) {
$col=strtok($url,' '); $url=strtok('');
#$url = str_replace('<', '&lt;', $url);
if (!empty($this->use_htmlcolor) and !preg_match('/^#[0-9a-f]{6}$/i', $col)) {
$col = substr($col, 1);
return "<span style='color:$col'>$url</span>";
}
if (preg_match('/^#[0-9a-f]{6}$/i',$col))
return "<span style='color:$col'>$url</span>";
$url=$col.' '.$url;
} else if (preg_match('/^((?:\+|\-)([1-6]?))[ ](.*)$/',$url,$m)) {
$fsz=array(
'-6'=>'50%', '-5'=>'50%','-4'=>'60%','-3'=>'70%','-2'=>'80%','-1'=>'90%',
'+1'=>'120%','+2'=>'140%','+3'=>'160%','+4'=>'180%','+5'=>'200%', '+6'=>'250%');
return "<span style='font-size:".$fsz[$m[1]]."'>$m[3]</span>";
}
$url = str_replace("<","&lt;",$url);
if ($url[0]==' ' and in_array($url[1],array('#','-','+')) !==false)
$url='<span class="markup invisible"> </span>'.substr($url,1);
return "<code class='wiki'>".$url."</code>"; # No link
break;
case '<':
$nm = 1; // XXX <<MacroName>> support
$url=substr($url,2,-2);
preg_match("/^([^\(]+)(\((.*)\))?$/", $url, $match);
if (isset($match[1])) {
$myname = getPlugin($match[1]);
if (!empty($myname)) {
if (!empty($opts['nomacro'])) return ''; # remove macro
return $this->macro_repl($url); # valid macro
}
}
return '<<'.$url.'>>';
break;
case '[':
$bra.='[';
$ket.=']';
$url=substr($url,1,-1);
$double_bracket = true;
// mediawiki like built-in category support
if ($this->use_builtin_category && preg_match('@'.$this->category_regex.'@', $url)) {
return $this->macro_repl('Category', $url); # call category macro
} else if (preg_match("/^([^\(:]+)(\((.*)\))?$/", $url, $match)) {
if (isset($match[1])) {
$name = $match[1];
} else {
$name = $url;
}
// check alias
$myname = getPlugin($name);
if (!empty($myname)) {
if (!empty($opts['nomacro'])) return ''; # remove macro
return $this->macro_repl($url); # No link
}
}
break;
case '$':
#return processor_latex($this,"#!latex\n".$url);
$url=preg_replace('/<\/?sup>/','^',$url);
//if ($url[1] != '$') $opt=array('type'=>'inline');
//else $opt=array('type'=>'block');
$opt=array('type'=>'inline');
// revert &amp;
$url = preg_replace('/&amp;/i', '&', $url);
return $this->processor_repl($this->inline_latex,$url,$opt);
break;
case '*':
if (!empty($opts['nomacro'])) return ''; # remove macro
$url = preg_replace($this->baserule, $this->baserepl, $url); // apply inline formatting rules
return $this->macro_repl('FootNote',$url);
break;
case '!':
$url=substr($url,1);
return $url;
break;
default:
break;
}
if ($url[0] == '#') {
// Anchor syntax in the MoinMoin 1.1
$anchor = strtok($url,' |');
return ($word = strtok('')) ? $this->link_to($anchor, $word):
"<a id='".substr($anchor, 1)."'></a>";
}
//$url=str_replace('&lt;','<',$url); // revert from baserule
$url=preg_replace('/&(?!#?[a-z0-9]+;)/i','&amp;',$url);
// ':' could be used in the title string.
$urltest = $url;
$tmp = preg_split('/\s|\|/', $url); // [[foobar foo]] or [[foobar|foo]]
if (count($tmp) > 1) $urltest = $tmp[0];
if ($url[0] == '"') {
$url = preg_replace('/&amp;/i', '&', $url);
// [["Hello World"]], [["Hello World" Page Title]]
return $this->word_repl($bra.$url.$ket, '', $attr);
} else
if (($p = strpos($urltest, ':')) !== false and
(!isset($url{$p+1}) or (isset($url{$p+1}) and $url{$p+1}!=':'))) {
// namespaced pages
// [[한글:페이지]], [[한글:페이지 이름]]
// mixed name with non ASCII chars
if (preg_match('/^([^\^a-zA-Z0-9]+.*)\:/', $url))
return $this->word_repl($bra.$url.$ket, '', $attr);
if ($url[0]=='a') { # attachment:
$url=preg_replace('/&amp;/i','&',$url);
return $this->macro_repl('attachment',substr($url,11));
}
$external_icon='';
$external_link='';
if ($url[0] == '^') {
$attr.=' target="_blank" ';
$url=substr($url,1);
$external_icon=$this->icon['external'];
}
if (!empty($this->url_mappings)) {
if (!isset($this->url_mapping_rule))
$this->macro_repl('UrlMapping', '', array('init'=>1));
if (!empty($this->url_mapping_rule))
$url=
preg_replace_callback('/('.$this->url_mapping_rule.')/i',
array($this, '_url_mappings_callback'), $url);
}
// InterWiki Pages
if (preg_match("/^(:|w|[A-Z])/",$url)
or (!empty($this->urls) and !preg_match('/^('.$this->urls.')/',$url))) {
$url = preg_replace('/&amp;/i', '&', $url);
return $this->interwiki_repl($url,'',$attr,$external_icon);
}
if (preg_match("/^mailto:/",$url)) {
$email=substr($url,7);
$link=strtok($email,' ');
$myname=strtok('');
$link=email_guard($link,$this->email_guard);
$myname=!empty($myname) ? $myname:$link;
#$link=preg_replace('/&(?!#?[a-z0-9]+;)/i','&amp;',$link);
return $this->icon['mailto']."<a class='externalLink' href='mailto:$link' $attr>$myname</a>$external_icon";
}
if ($force or strstr($url, ' ') or strstr($url, '|')) {
if (($tok = strtok($url, ' |')) !== false) {
$text = strtok('');
$text = preg_replace($this->baserule, $this->baserepl, $text);
$text = str_replace('&lt;', '<', $text); // revert from baserule
$url = $tok;
}
#$link=str_replace('&','&amp;',$url);
$link=preg_replace('/&(?!#?[a-z0-9]+;)/i','&amp;',$url);
if (!isset($text[0])) $text=$url;
else {
$img_attr='';
$img_cls = '';
if (preg_match("/^attachment:/",$text)) {
$atext=$text;
if (($p=strpos($text,'?')) !== false) {
$atext=substr($text,0,$p);
parse_str(substr($text,$p+1),$attrs);
foreach ($attrs as $n=>$v) {
if ($n == 'align') $img_cls = ' img'.ucfirst($v);
else
$img_attr.="$n=\"$v\" ";
}
}
$msave = $this->_macrocache;
$this->_macrocache = 0;
$fname = $this->macro_repl('attachment', substr($text, 11), 1);
if (file_exists($fname))
$text = qualifiedUrl($this->url_prefix.'/'.$fname);
else
$text = $this->macro_repl('attachment', substr($text, 11));
$this->_macrocache = $msave; // restore _macrocache
}
$text = preg_replace('/&amp;/i', '&', $text);
if (preg_match("/^((?:https?|ftp).*\.(png|gif|jpeg|jpg))(?:\?|&(?!>amp;))?(.*?)?$/i",$text, $match)) {
// FIXME call externalimage macro for these external images
if (!empty($this->external_image_regex) and preg_match('@'.$this->external_image_regex.'@x', $match[0])) {
$res = $this->macro_repl('ExternalImage', $natch[0]);
if ($res !== false)
return $res;
}
$cls = 'externalImage';
$type = strtoupper($match[2]);
$atext=isset($atext[0]) ? $atext:$text;
$url = str_replace('&','&amp;',$match[1]);
// trash dummy query string
$url = preg_replace('@(\?|&)\.(png|gif|jpe?g)$@', '', $url);
$tmp = !empty($match[3]) ? preg_replace('/&amp;/', '&', $match[3]) : '';
$attrs = explode('&', $tmp);
$eattr = array();
foreach ($attrs as $a) {
$name = strtok($a, '=');
$val = strtok(' ');
if ($name == 'align') $cls.=' img'.ucfirst($val);
else if ($name and $val) $eattr[] = $name.'="'.urldecode($val).'"';
}
$fetch_url = $url;
$info = '';
// check internal links and fetch image
if (!empty($this->fetch_images) and !preg_match('@^https?://'.$_SERVER['HTTP_HOST'].'@', $url)) {
$fetch_url = $this->fetch_action. str_replace(array('&', '?'), array('%26', '%3f'), $url);
$size = '';
if (!empty($this->fetch_imagesize))
$size = '('.$this->macro_repl('ImageFileSize', $fetch_url).')';
// use thumbnails ?
if (!empty($this->use_thumb_by_default)) {
if (!empty($this->no_gif_thumbnails)) {
if ($type != 'GIF')
$fetch_url.= '&amp;thumbwidth='.$this->thumb_width;
} else {
$fetch_url.= '&amp;thumbwidth='.$this->thumb_width;
}
}
} else if (!empty($this->fetch_imagesize)) {
$size = '('.$this->macro_repl('ImageFileSize', $url).')';
}
$info = "<div class='info'><a href='$url'><span>[$type "._("external image")."$size]</span></a></div>";
$iattr = '';
if (isset($eattr[0]))
$iattr = implode(' ', $eattr);
return "<div class='$cls$img_cls'><div><a class='externalLink named' href='$link' $attr $this->external_target title='$link'><img $iattr alt='$atext' src='$fetch_url' $img_attr/></a>".$info.'</div></div>';
}
if (!empty($this->external_on))
$external_link='<span class="externalLink">('.$url.')</span>';
}
$icon = '';
if (substr($url,0,7)=='http://' and $url[7]=='?') {
$link=substr($url,7);
return "<a href='$link'>$text</a>";
} else if ($this->check_openid_url and preg_match("@^https?://@i",$url)) {
if (is_object($this->udb) and $this->udb->_exists($url)) {
$icon='openid';
$icon="<a class='externalLink' href='$link'><img class='url' alt='[$icon]' src='".$this->imgs_dir_url."$icon.png' /></a>";
$attr.=' title="'.$link.'"';
$link=$this->link_url(_rawurlencode($text));
}
}
if (empty($this->_no_urlicons) and empty($icon)) {
$icon= strtok($url,':');
$icon="<img class='url' alt='[$icon]' src='".$this->imgs_dir_url."$icon.png' />";
}
if ($text != $url) $eclass='named';
else $eclass='unnamed';
$link =str_replace(array('<','>'),array('&#x3c;','&#x3e;'),$link);
return $icon. "<a class='externalLink $eclass' $attr $this->external_target href='$link'>$text</a>".$external_icon.$external_link;
} # have no space
$link = str_replace(array('<','>'),array('&#x3c;','&#x3e;'),$url);
if (preg_match("/^(http|https|ftp)/",$url)) {
$url1 = preg_replace('/&amp;/','&',$url);
if (preg_match("/(^.*\.(png|gif|jpeg|jpg))(?:\?|&(?!>amp;))?(.*?)?$/i", $url1, $match)) {
// FIXME call externalimage macro for these external images
if (!empty($this->external_image_regex) and preg_match('@'.$this->external_image_regex.'@x', $url1)) {
$res = $this->macro_repl('ExternalImage', $url1);
if ($res !== false)
return $res;
}
$cls = 'externalImage';
$url=$match[1];
// trash dummy query string
$url = preg_replace('@(\?|&)\.(png|gif|jpe?g)$@', '', $url);
$type = strtoupper($match[2]);
$attrs = !empty($match[3]) ? explode('&', $match[3]) : array();
$eattr = array();
foreach ($attrs as $arg) {
$name=strtok($arg,'=');
$val=strtok(' ');
if ($name == 'align') $cls.=' img'.ucfirst($val);
else if ($name and $val) $eattr[] = $name.'="'.urldecode($val).'"';
}
$attr = '';
if (isset($eattr[0]))
$attr = implode(' ', $eattr);
// XXX fetch images
$fetch_url = $url;
$info = '';
// check internal images
if (!empty($this->fetch_images) and !preg_match('@^https?://'.$_SERVER['HTTP_HOST'].'@', $url)) {
$fetch_url = $this->fetch_action.
str_replace(array('&', '?'), array('%26', '%3f'), $url);
$size = '';
if (!empty($this->fetch_imagesize))
$size = '('.$this->macro_repl('ImageFileSize', $fetch_url).')';
// use thumbnails ?
if (!empty($this->use_thumb_by_default)) {
if (!empty($this->no_gif_thumbnails)) {
if ($type != 'GIF')
$fetch_url.= '&amp;thumbwidth='.$this->thumb_width;
} else {
$fetch_url.= '&amp;thumbwidth='.$this->thumb_width;
}
}
} else if (!empty($this->fetch_imagesize)) {
$size = '('.$this->macro_repl('ImageFileSize', $url).')';
}
$info = "<div class='info'><a href='$url'><span>[$type "._("external image")."$size]</span></a></div>";
return "<div class=\"$cls\"><div><img alt='$link' $attr src='$fetch_url' />".$info.'</div></div>';
}
}
if (substr($url,0,7)=='http://' and $url[7]=='?') {
$link=substr($url,7);
return "<a class='internalLink' href='$link'>$link</a>";
}
$url=urldecode($url);
// auto detect the encoding of a given URL
if (function_exists('mb_detect_encoding'))
$url = _autofixencode($url);
return "<a class='externalLink' $attr href='$link' $this->external_target>$url</a>";
} else {
if ($url{0}=='?')
$url=substr($url,1);
$url = preg_replace('/&amp;/i', '&', $url);
return $this->word_repl($bra.$url.$ket, '', $attr);
}
}
function interwiki_repl($url,$text='',$attr='',$extra='') {
global $DBInfo;
/**
* wiki: FrontPage => wiki:FrontPage (Rigveda fix) FIXME
* wiki:MoinMoin:FrontPage
* wiki:MoinMoin/FrontPage is not supported.
* wiki:"Hello World" or wiki:Hello_World, wiki:Hello%20World work
*
* wiki:MoinMoin:"Hello World"
* [wiki:"Hello World" hello world] - spaced
* [wiki:"Hello World"|hello world] - | separator
* [wiki:"Hello World"hello world] - no separator but separable
* [wiki:Hello|World hello world] == [wiki:Hello World hello world]
* [wiki:Hello World|hello world] == [wiki:"Hello" World|hello world] - be careful!!
*/
$wiki = '';
if (isset($url[0]) &&
/* unified interwiki regex */
preg_match('@^(wiki:\s*)?(?:([A-Z][a-zA-Z0-9]+):)?
(")?([^"|]+?)(?(3)")
(?(3)(?:\s+|\\|)?(.*)|(?:\s+|\\|)(.*))?$@x', $url, $m)) {
$wiki = $m[2];
$url = $m[4];
$text = isset($m[5][0]) ? $m[5] : $m[6];
}
if (empty($wiki)) {
# wiki:FrontPage (not supported in the MoinMoin)
# or [wiki:FrontPage Home Page]
return $this->word_repl($url,$text.$extra,$attr,1);
}
if (empty($DBInfo->interwiki)) {
$this->macro_repl('InterWiki', '', array('init'=>1));
}
// invalid InterWiki name
if (empty($DBInfo->interwiki[$wiki])) {
#$dum0=preg_replace("/(".$this->wordrule.")/e","\$this->link_repl('\\1')",$wiki);
#return $dum0.':'.($page?$this->link_repl($page,$text):'');
return $this->word_repl("$wiki:$url",$text.$extra,$attr,1);
}
$icon=$this->imgs_url_interwiki.strtolower($wiki).'-16.png';
$sx=16;$sy=16;
if (isset($DBInfo->intericon[$wiki])) {
$icon=$DBInfo->intericon[$wiki][2];
$sx=$DBInfo->intericon[$wiki][0];
$sy=$DBInfo->intericon[$wiki][1];
}
$page=$url;
$url=$DBInfo->interwiki[$wiki];
if (isset($page[0]) and $page[0]=='"') # "extended wiki name"
$page=substr($page,1,-1);
if ($page=='/') $page='';
$sep='';
if (substr($page,-1)==' ') {
$sep='<b></b>'; // auto append SixSingleQuotes
$page=rtrim($page);
}
$urlpage=_urlencode($page);
#$urlpage=trim($page);
if (strpos($url,'$PAGE') === false)
$url.=$urlpage;
else {
# GtkRef http://developer.gnome.org/doc/API/2.0/gtk/$PAGE.html
# GtkRef:GtkTreeView#GtkTreeView
# is rendered as http://...GtkTreeView.html#GtkTreeView
$page_only=strtok($urlpage,'#?');
$query= substr($urlpage,strlen($page_only));
#if ($query and !$text) $text=strtok($page,'#?');
$url=str_replace('$PAGE',$page_only,$url).$query;
}
$img="<a class=\"interwiki\" href='$url' $this->interwiki_target>".
"<img class=\"interwiki\" alt=\"$wiki:\" src='$icon' style='border:0' height='$sy' ".
"width='$sx' title='$wiki:' /></a>";
#if (!$text) $text=str_replace("%20"," ",$page);
if (!$text) $text=urldecode($page);
else if (preg_match("/^(http|ftp|attachment):.*\.(png|gif|jpeg|jpg)$/i",$text)) {
if (substr($text,0,11)=='attachment:') {
$fname=substr($text,11);
$ntext=$this->macro_repl('Attachment',$fname,1);
if (!file_exists($ntext))
$text=$this->macro_repl('Attachment',$fname);
else {
$text=qualifiedUrl($this->url_prefix.'/'.$ntext);
$text= "<img style='border:0' alt='$text' src='$text' />";
}
} else
$text= "<img style='border:0' alt='$text' src='$text' />";
$img='';
}
if (preg_match("/\.(png|gif|jpeg|jpg)$/i",$url))
return "<a href='".$url."' $attr title='$wiki:$page'><img style='vertical-align:middle;border:0px' alt='$text' src='$url' /></a>$extra";
if (!$text) return $img;
return $img. "<a href='".$url."' $attr title='$wiki:$page'>$text</a>$extra$sep";
}
function get_pagelinks() {
if (!is_object($this->cache))
$this->cache= new Cache_text('pagelinks');
if ($this->cache->exists($this->page->name)) {
$links=$this->cache->fetch($this->page->name);
if ($links !== false) return $links;
}
$links = get_pagelinks($this, $this->page->_get_raw_body());
return $links;
}
function get_backlinks() {
if (!is_object($this->bcache))
$this->bcache= new Cache_text('backlinks');
if ($this->bcache->exists($this->page->name)) {
$links=$this->bcache->fetch($this->page->name);
if ($links !== false) return $links;
}
// no backlinks found. XXX
return array();
}
function word_repl($word,$text='',$attr='',$nogroup=0,$islink=1) {
require_once(dirname(__FILE__).'/lib/xss.php');
global $DBInfo;
$nonexists='nonexists_'.$this->nonexists;
$word = $page = trim($word, '[]'); // trim out [[Hello World]] => Hello World
$extended = false;
if (($word[0] == '"' or $word[0] == 'w') and preg_match('/^(?:wiki\:)?((")?[^"]+\2)((\s+|\|)?(.*))?$/', $word, $m)) {
# ["extended wiki name"]
# ["Hello World" Go to Hello]
# [wiki:"Hello World" Go to Main]
$word = substr($m[1], 1, -1);
if (isset($m[5][0])) $text = $m[5]; // text arg ignored
$extended=true;
$page=$word;
} else if (($p = strpos($word, '|')) !== false) {
// or MediaWiki/WikiCreole like links
$text = substr($word, $p + 1);
$word = substr($word, 0, $p);
$page = $word;
} else {
// check for [[Hello attachment:foo.png]] case
$tmp = strtok($word, ' |');
$last = strtok('');
if (($p = strpos($last, ' ')) === false && substr($last, 0, 11) == 'attachment:') {
$text = $last;
$word = $tmp;
$page = $word;
}
}
if (!$extended and empty($DBInfo->mediawiki_style)) {
#$page=preg_replace("/\s+/","",$word); # concat words
$page=normalize($word); # concat words
}
if (empty($DBInfo->use_twikilink)) $islink=0;
list($page,$page_text,$gpage)=
normalize_word($page,$this->group,$this->page->name,$nogroup,$islink);
if (isset($text[0])) {
if (preg_match("/^(http|ftp|attachment).*\.(png|gif|jpeg|jpg)$/i",$text)) {
if (substr($text,0,11)=='attachment:') {
$fname=substr($text,11);
$ntext=$this->macro_repl('attachment',$fname,1);
if (!file_exists($ntext)) {
$word=$this->macro_repl('attachment',$fname);
} else {
$text=qualifiedUrl($this->url_prefix.'/'.$ntext);
$word= "<img style='border:0' alt='$text' src='$text' /></a>";
}
} else {
$text=str_replace('&','&amp;',$text);
// trash dummy query string
$text = preg_replace('@(\?|&)\.(png|gif|jpe?g)$@', '', $text);
if (!empty($this->fetch_images) and !preg_match('@^https?://'.$_SERVER['HTTP_HOST'].'@', $text))
$text = $this->fetch_action. str_replace(array('&', '?'), array('%26', '%3f'), $text);