1ed7b5f09Sandi<?php 215fae107Sandi/** 315fae107Sandi * Common DokuWiki functions 415fae107Sandi * 515fae107Sandi * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 715fae107Sandi */ 815fae107Sandi 9fa8adffeSAndreas Gohrif(!defined('DOKU_INC')) die('meh.'); 10f3f0262cSandi 11f3f0262cSandi/** 12b6912aeaSAndreas Gohr * These constants are used with the recents function 13b6912aeaSAndreas Gohr */ 14b6912aeaSAndreas Gohrdefine('RECENTS_SKIP_DELETED', 2); 15b6912aeaSAndreas Gohrdefine('RECENTS_SKIP_MINORS', 4); 16b6912aeaSAndreas Gohrdefine('RECENTS_SKIP_SUBSPACES', 8); 170b926329SKate Arzamastsevadefine('RECENTS_MEDIA_CHANGES', 16); 180b926329SKate Arzamastsevadefine('RECENTS_MEDIA_PAGES_MIXED', 32); 19b6912aeaSAndreas Gohr 20b6912aeaSAndreas Gohr/** 21d5197206Schris * Wrapper around htmlspecialchars() 22d5197206Schris * 23d5197206Schris * @author Andreas Gohr <andi@splitbrain.org> 24d5197206Schris * @see htmlspecialchars() 25d5197206Schris */ 26d5197206Schrisfunction hsc($string) { 27d5197206Schris return htmlspecialchars($string, ENT_QUOTES, 'UTF-8'); 28d5197206Schris} 29d5197206Schris 30d5197206Schris/** 31d5197206Schris * print a newline terminated string 32d5197206Schris * 33d5197206Schris * You can give an indention as optional parameter 34d5197206Schris * 35d5197206Schris * @author Andreas Gohr <andi@splitbrain.org> 36d5197206Schris */ 3725ec097bSChris Smithfunction ptln($string, $indent = 0) { 3825ec097bSChris Smith echo str_repeat(' ', $indent)."$string\n"; 3902b0b681SAndreas Gohr} 4002b0b681SAndreas Gohr 4102b0b681SAndreas Gohr/** 4202b0b681SAndreas Gohr * strips control characters (<32) from the given string 4302b0b681SAndreas Gohr * 4402b0b681SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 4502b0b681SAndreas Gohr */ 4602b0b681SAndreas Gohrfunction stripctl($string) { 4702b0b681SAndreas Gohr return preg_replace('/[\x00-\x1F]+/s', '', $string); 48d5197206Schris} 49d5197206Schris 50d5197206Schris/** 51634d7150SAndreas Gohr * Return a secret token to be used for CSRF attack prevention 52634d7150SAndreas Gohr * 53634d7150SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 54634d7150SAndreas Gohr * @link http://en.wikipedia.org/wiki/Cross-site_request_forgery 55634d7150SAndreas Gohr * @link http://christ1an.blogspot.com/2007/04/preventing-csrf-efficiently.html 56634d7150SAndreas Gohr * @return string 57634d7150SAndreas Gohr */ 58634d7150SAndreas Gohrfunction getSecurityToken() { 59585bf44eSChristopher Smith /** @var Input $INPUT */ 60585bf44eSChristopher Smith global $INPUT; 61585bf44eSChristopher Smith return PassHash::hmac('md5', session_id().$INPUT->server->str('REMOTE_USER'), auth_cookiesalt()); 62634d7150SAndreas Gohr} 63634d7150SAndreas Gohr 64634d7150SAndreas Gohr/** 65634d7150SAndreas Gohr * Check the secret CSRF token 66634d7150SAndreas Gohr */ 67634d7150SAndreas Gohrfunction checkSecurityToken($token = null) { 68585bf44eSChristopher Smith /** @var Input $INPUT */ 697d01a0eaSTom N Harris global $INPUT; 70585bf44eSChristopher Smith if(!$INPUT->server->str('REMOTE_USER')) return true; // no logged in user, no need for a check 71df97eaacSAndreas Gohr 727d01a0eaSTom N Harris if(is_null($token)) $token = $INPUT->str('sectok'); 73634d7150SAndreas Gohr if(getSecurityToken() != $token) { 74634d7150SAndreas Gohr msg('Security Token did not match. Possible CSRF attack.', -1); 75634d7150SAndreas Gohr return false; 76634d7150SAndreas Gohr } 77634d7150SAndreas Gohr return true; 78634d7150SAndreas Gohr} 79634d7150SAndreas Gohr 80634d7150SAndreas Gohr/** 81634d7150SAndreas Gohr * Print a hidden form field with a secret CSRF token 82634d7150SAndreas Gohr * 83634d7150SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 84634d7150SAndreas Gohr */ 85634d7150SAndreas Gohrfunction formSecurityToken($print = true) { 862404d0edSAnika Henke $ret = '<div class="no"><input type="hidden" name="sectok" value="'.getSecurityToken().'" /></div>'."\n"; 873272d797SAndreas Gohr if($print) echo $ret; 88634d7150SAndreas Gohr return $ret; 89634d7150SAndreas Gohr} 90634d7150SAndreas Gohr 91634d7150SAndreas Gohr/** 921015a57dSChristopher Smith * Determine basic information for a request of $id 9315fae107Sandi * 9415fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 957e87a794SChristopher Smith * @author Chris Smith <chris@jalakai.co.uk> 96f3f0262cSandi */ 971015a57dSChristopher Smithfunction basicinfo($id, $htmlClient=true){ 98f3f0262cSandi global $USERINFO; 99585bf44eSChristopher Smith /* @var Input $INPUT */ 100585bf44eSChristopher Smith global $INPUT; 1016afe8dcaSchris 102c66972f2SAdrian Lang // set info about manager/admin status. 103c66972f2SAdrian Lang $info['isadmin'] = false; 104c66972f2SAdrian Lang $info['ismanager'] = false; 105585bf44eSChristopher Smith if($INPUT->server->has('REMOTE_USER')) { 106f3f0262cSandi $info['userinfo'] = $USERINFO; 1071015a57dSChristopher Smith $info['perm'] = auth_quickaclcheck($id); 108585bf44eSChristopher Smith $info['client'] = $INPUT->server->str('REMOTE_USER'); 10917ee7f66SAndreas Gohr 110f8cc712eSAndreas Gohr if($info['perm'] == AUTH_ADMIN) { 111f8cc712eSAndreas Gohr $info['isadmin'] = true; 112f8cc712eSAndreas Gohr $info['ismanager'] = true; 113f8cc712eSAndreas Gohr } elseif(auth_ismanager()) { 114f8cc712eSAndreas Gohr $info['ismanager'] = true; 115f8cc712eSAndreas Gohr } 116f8cc712eSAndreas Gohr 11717ee7f66SAndreas Gohr // if some outside auth were used only REMOTE_USER is set 11817ee7f66SAndreas Gohr if(!$info['userinfo']['name']) { 119585bf44eSChristopher Smith $info['userinfo']['name'] = $INPUT->server->str('REMOTE_USER'); 12017ee7f66SAndreas Gohr } 121ee4c4a1bSAndreas Gohr 122f3f0262cSandi } else { 1231015a57dSChristopher Smith $info['perm'] = auth_aclcheck($id, '', null); 124ee4c4a1bSAndreas Gohr $info['client'] = clientIP(true); 125f3f0262cSandi } 126f3f0262cSandi 1271015a57dSChristopher Smith $info['namespace'] = getNS($id); 1281015a57dSChristopher Smith 1291015a57dSChristopher Smith // mobile detection 1301015a57dSChristopher Smith if ($htmlClient) { 1311015a57dSChristopher Smith $info['ismobile'] = clientismobile(); 1321015a57dSChristopher Smith } 1331015a57dSChristopher Smith 1341015a57dSChristopher Smith return $info; 1351015a57dSChristopher Smith } 1361015a57dSChristopher Smith 1371015a57dSChristopher Smith/** 1381015a57dSChristopher Smith * Return info about the current document as associative 1391015a57dSChristopher Smith * array. 1401015a57dSChristopher Smith * 1411015a57dSChristopher Smith * @author Andreas Gohr <andi@splitbrain.org> 1421015a57dSChristopher Smith */ 1431015a57dSChristopher Smithfunction pageinfo() { 1441015a57dSChristopher Smith global $ID; 1451015a57dSChristopher Smith global $REV; 1461015a57dSChristopher Smith global $RANGE; 1471015a57dSChristopher Smith global $lang; 148585bf44eSChristopher Smith /* @var Input $INPUT */ 149585bf44eSChristopher Smith global $INPUT; 1501015a57dSChristopher Smith 1511015a57dSChristopher Smith $info = basicinfo($ID); 1521015a57dSChristopher Smith 1531015a57dSChristopher Smith // include ID & REV not redundant, as some parts of DokuWiki may temporarily change $ID, e.g. p_wiki_xhtml 1541015a57dSChristopher Smith // FIXME ... perhaps it would be better to ensure the temporary changes weren't necessary 1551015a57dSChristopher Smith $info['id'] = $ID; 1561015a57dSChristopher Smith $info['rev'] = $REV; 1571015a57dSChristopher Smith 158585bf44eSChristopher Smith if($INPUT->server->has('REMOTE_USER')) { 1597e87a794SChristopher Smith $sub = new Subscription(); 1607e87a794SChristopher Smith $info['subscribed'] = $sub->user_subscription(); 1617e87a794SChristopher Smith } else { 1627e87a794SChristopher Smith $info['subscribed'] = false; 1637e87a794SChristopher Smith } 1647e87a794SChristopher Smith 165f3f0262cSandi $info['locked'] = checklock($ID); 16600976812SAndreas Gohr $info['filepath'] = fullpath(wikiFN($ID)); 1672ca9d91cSBen Coburn $info['exists'] = @file_exists($info['filepath']); 16801c9a118SAndreas Gohr $info['currentrev'] = @filemtime($info['filepath']); 1692ca9d91cSBen Coburn if($REV) { 1702ca9d91cSBen Coburn //check if current revision was meant 17101c9a118SAndreas Gohr if($info['exists'] && ($info['currentrev'] == $REV)) { 1722ca9d91cSBen Coburn $REV = ''; 1737b3a6803SAndreas Gohr } elseif($RANGE) { 1747b3a6803SAndreas Gohr //section editing does not work with old revisions! 1757b3a6803SAndreas Gohr $REV = ''; 1767b3a6803SAndreas Gohr $RANGE = ''; 1777b3a6803SAndreas Gohr msg($lang['nosecedit'], 0); 1782ca9d91cSBen Coburn } else { 1792ca9d91cSBen Coburn //really use old revision 18000976812SAndreas Gohr $info['filepath'] = fullpath(wikiFN($ID, $REV)); 181f3f0262cSandi $info['exists'] = @file_exists($info['filepath']); 182f3f0262cSandi } 183f3f0262cSandi } 184c112d578Sandi $info['rev'] = $REV; 185f3f0262cSandi if($info['exists']) { 186f3f0262cSandi $info['writable'] = (is_writable($info['filepath']) && 187f3f0262cSandi ($info['perm'] >= AUTH_EDIT)); 188f3f0262cSandi } else { 189f3f0262cSandi $info['writable'] = ($info['perm'] >= AUTH_CREATE); 190f3f0262cSandi } 19150e988b1SAndreas Gohr $info['editable'] = ($info['writable'] && empty($info['locked'])); 192f3f0262cSandi $info['lastmod'] = @filemtime($info['filepath']); 193f3f0262cSandi 19471726d78SBen Coburn //load page meta data 19571726d78SBen Coburn $info['meta'] = p_get_metadata($ID); 19671726d78SBen Coburn 197652610a2Sandi //who's the editor 198047bad06SGerrit Uitslag $pagelog = new PageChangeLog($ID, 1024); 199652610a2Sandi if($REV) { 200f523c971SGerrit Uitslag $revinfo = $pagelog->getRevisionInfo($REV); 201652610a2Sandi } else { 2020e80bb5eSChristopher Smith if(!empty($info['meta']['last_change']) && is_array($info['meta']['last_change'])) { 203aa27cf05SAndreas Gohr $revinfo = $info['meta']['last_change']; 204aa27cf05SAndreas Gohr } else { 205f523c971SGerrit Uitslag $revinfo = $pagelog->getRevisionInfo($info['lastmod']); 206cd00a034SBen Coburn // cache most recent changelog line in metadata if missing and still valid 207cd00a034SBen Coburn if($revinfo !== false) { 208cd00a034SBen Coburn $info['meta']['last_change'] = $revinfo; 209cd00a034SBen Coburn p_set_metadata($ID, array('last_change' => $revinfo)); 210cd00a034SBen Coburn } 211cd00a034SBen Coburn } 212cd00a034SBen Coburn } 213cd00a034SBen Coburn //and check for an external edit 214cd00a034SBen Coburn if($revinfo !== false && $revinfo['date'] != $info['lastmod']) { 215cd00a034SBen Coburn // cached changelog line no longer valid 216cd00a034SBen Coburn $revinfo = false; 217cd00a034SBen Coburn $info['meta']['last_change'] = $revinfo; 218cd00a034SBen Coburn p_set_metadata($ID, array('last_change' => $revinfo)); 219652610a2Sandi } 220bb4866bdSchris 221652610a2Sandi $info['ip'] = $revinfo['ip']; 222652610a2Sandi $info['user'] = $revinfo['user']; 223652610a2Sandi $info['sum'] = $revinfo['sum']; 22471726d78SBen Coburn // See also $INFO['meta']['last_change'] which is the most recent log line for page $ID. 225ebf1501fSBen Coburn // Use $INFO['meta']['last_change']['type']===DOKU_CHANGE_TYPE_MINOR_EDIT in place of $info['minor']. 22659f257aeSchris 22788f522e9Sandi if($revinfo['user']) { 22888f522e9Sandi $info['editor'] = $revinfo['user']; 22988f522e9Sandi } else { 23088f522e9Sandi $info['editor'] = $revinfo['ip']; 23188f522e9Sandi } 232652610a2Sandi 233ee4c4a1bSAndreas Gohr // draft 234ee4c4a1bSAndreas Gohr $draft = getCacheName($info['client'].$ID, '.draft'); 235ee4c4a1bSAndreas Gohr if(@file_exists($draft)) { 236ee4c4a1bSAndreas Gohr if(@filemtime($draft) < @filemtime(wikiFN($ID))) { 237ee4c4a1bSAndreas Gohr // remove stale draft 238ee4c4a1bSAndreas Gohr @unlink($draft); 239ee4c4a1bSAndreas Gohr } else { 240ee4c4a1bSAndreas Gohr $info['draft'] = $draft; 241ee4c4a1bSAndreas Gohr } 242ee4c4a1bSAndreas Gohr } 243ee4c4a1bSAndreas Gohr 2441015a57dSChristopher Smith return $info; 2451015a57dSChristopher Smith} 2461015a57dSChristopher Smith 2471015a57dSChristopher Smith/** 2481015a57dSChristopher Smith * Return information about the current media item as an associative array. 2491015a57dSChristopher Smith */ 2501015a57dSChristopher Smithfunction mediainfo(){ 2511015a57dSChristopher Smith global $NS; 2521015a57dSChristopher Smith global $IMG; 2531015a57dSChristopher Smith 2541015a57dSChristopher Smith $info = basicinfo("$NS:*"); 2551015a57dSChristopher Smith $info['image'] = $IMG; 2561c548ebeSAndreas Gohr 257f3f0262cSandi return $info; 258f3f0262cSandi} 259f3f0262cSandi 260f3f0262cSandi/** 2612684e50aSAndreas Gohr * Build an string of URL parameters 2622684e50aSAndreas Gohr * 2632684e50aSAndreas Gohr * @author Andreas Gohr 2642684e50aSAndreas Gohr */ 265b174aeaeSchrisfunction buildURLparams($params, $sep = '&') { 2662684e50aSAndreas Gohr $url = ''; 2672684e50aSAndreas Gohr $amp = false; 2682684e50aSAndreas Gohr foreach($params as $key => $val) { 269b174aeaeSchris if($amp) $url .= $sep; 2702684e50aSAndreas Gohr 27185e6871fSAdrian Lang $url .= rawurlencode($key).'='; 2723a50618cSgweissbach $url .= rawurlencode((string) $val); 2732684e50aSAndreas Gohr $amp = true; 2742684e50aSAndreas Gohr } 2752684e50aSAndreas Gohr return $url; 2762684e50aSAndreas Gohr} 2772684e50aSAndreas Gohr 2782684e50aSAndreas Gohr/** 2792684e50aSAndreas Gohr * Build an string of html tag attributes 2802684e50aSAndreas Gohr * 2817bff22c0SAndreas Gohr * Skips keys starting with '_', values get HTML encoded 2827bff22c0SAndreas Gohr * 2832684e50aSAndreas Gohr * @author Andreas Gohr 2842684e50aSAndreas Gohr */ 2854b030ce7SAndreas Gohrfunction buildAttributes($params, $skipempty = false) { 2862684e50aSAndreas Gohr $url = ''; 2879063ec14SAdrian Lang $white = false; 2882684e50aSAndreas Gohr foreach($params as $key => $val) { 2897bff22c0SAndreas Gohr if($key{0} == '_') continue; 290b1c94f1dSAndreas Gohr if($val === '' && $skipempty) continue; 2919063ec14SAdrian Lang if($white) $url .= ' '; 2927bff22c0SAndreas Gohr 2932684e50aSAndreas Gohr $url .= $key.'="'; 2942684e50aSAndreas Gohr $url .= htmlspecialchars($val); 2952684e50aSAndreas Gohr $url .= '"'; 2969063ec14SAdrian Lang $white = true; 2972684e50aSAndreas Gohr } 2982684e50aSAndreas Gohr return $url; 2992684e50aSAndreas Gohr} 3002684e50aSAndreas Gohr 3012684e50aSAndreas Gohr/** 30215fae107Sandi * This builds the breadcrumb trail and returns it as array 30315fae107Sandi * 30415fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 305f3f0262cSandi */ 306f3f0262cSandifunction breadcrumbs() { 3078746e727Sandi // we prepare the breadcrumbs early for quick session closing 3088746e727Sandi static $crumbs = null; 3098746e727Sandi if($crumbs != null) return $crumbs; 3108746e727Sandi 311f3f0262cSandi global $ID; 312f3f0262cSandi global $ACT; 313f3f0262cSandi global $conf; 314f3f0262cSandi 315f3f0262cSandi //first visit? 316c66972f2SAdrian Lang $crumbs = isset($_SESSION[DOKU_COOKIE]['bc']) ? $_SESSION[DOKU_COOKIE]['bc'] : array(); 317f3f0262cSandi //we only save on show and existing wiki documents 318a77f5846Sjan $file = wikiFN($ID); 319a77f5846Sjan if($ACT != 'show' || !@file_exists($file)) { 320e71ce681SAndreas Gohr $_SESSION[DOKU_COOKIE]['bc'] = $crumbs; 321f3f0262cSandi return $crumbs; 322f3f0262cSandi } 323a77f5846Sjan 324a77f5846Sjan // page names 3251a84a0f3SAnika Henke $name = noNSorNS($ID); 326fe9ec250SChris Smith if(useHeading('navigation')) { 327a77f5846Sjan // get page title 32867c15eceSMichael Hamann $title = p_get_first_heading($ID, METADATA_RENDER_USING_SIMPLE_CACHE); 329a77f5846Sjan if($title) { 330a77f5846Sjan $name = $title; 331a77f5846Sjan } 332a77f5846Sjan } 333a77f5846Sjan 334f3f0262cSandi //remove ID from array 335a77f5846Sjan if(isset($crumbs[$ID])) { 336a77f5846Sjan unset($crumbs[$ID]); 337f3f0262cSandi } 338f3f0262cSandi 339f3f0262cSandi //add to array 340a77f5846Sjan $crumbs[$ID] = $name; 341f3f0262cSandi //reduce size 342f3f0262cSandi while(count($crumbs) > $conf['breadcrumbs']) { 343f3f0262cSandi array_shift($crumbs); 344f3f0262cSandi } 345f3f0262cSandi //save to session 346e71ce681SAndreas Gohr $_SESSION[DOKU_COOKIE]['bc'] = $crumbs; 347f3f0262cSandi return $crumbs; 348f3f0262cSandi} 349f3f0262cSandi 350f3f0262cSandi/** 35115fae107Sandi * Filter for page IDs 35215fae107Sandi * 353f3f0262cSandi * This is run on a ID before it is outputted somewhere 354f3f0262cSandi * currently used to replace the colon with something else 355907f24f7SAndreas Gohr * on Windows (non-IIS) systems and to have proper URL encoding 356907f24f7SAndreas Gohr * 357907f24f7SAndreas Gohr * See discussions at https://github.com/splitbrain/dokuwiki/pull/84 and 358907f24f7SAndreas Gohr * https://github.com/splitbrain/dokuwiki/pull/173 why we use a whitelist of 359907f24f7SAndreas Gohr * unaffected servers instead of blacklisting affected servers here. 36015fae107Sandi * 36149c713a3Sandi * Urlencoding is ommitted when the second parameter is false 36249c713a3Sandi * 36315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 364f3f0262cSandi */ 36549c713a3Sandifunction idfilter($id, $ue = true) { 366f3f0262cSandi global $conf; 367585bf44eSChristopher Smith /* @var Input $INPUT */ 368585bf44eSChristopher Smith global $INPUT; 369585bf44eSChristopher Smith 370f3f0262cSandi if($conf['useslash'] && $conf['userewrite']) { 371f3f0262cSandi $id = strtr($id, ':', '/'); 372f3f0262cSandi } elseif(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && 37358bedc8aSborekb $conf['userewrite'] && 374585bf44eSChristopher Smith strpos($INPUT->server->str('SERVER_SOFTWARE'), 'Microsoft-IIS') === false 3753272d797SAndreas Gohr ) { 376f3f0262cSandi $id = strtr($id, ':', ';'); 377f3f0262cSandi } 37849c713a3Sandi if($ue) { 379b6c6979fSAndreas Gohr $id = rawurlencode($id); 380f3f0262cSandi $id = str_replace('%3A', ':', $id); //keep as colon 381f3f0262cSandi $id = str_replace('%2F', '/', $id); //keep as slash 38249c713a3Sandi } 383f3f0262cSandi return $id; 384f3f0262cSandi} 385f3f0262cSandi 386f3f0262cSandi/** 387ed7b5f09Sandi * This builds a link to a wikipage 38815fae107Sandi * 389*4bc480e5SAndreas Gohr * It handles URL rewriting and adds additional parameters 3906c7843b5Sandi * 39115fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 392*4bc480e5SAndreas Gohr * 393*4bc480e5SAndreas Gohr * @param string $id page id, defaults to start page 394*4bc480e5SAndreas Gohr * @param string|array $urlParameters URL parameters, associative array recommended 395*4bc480e5SAndreas Gohr * @param bool $absolute request an absolute URL instead of relative 396*4bc480e5SAndreas Gohr * @param string $separator parameter separator 397*4bc480e5SAndreas Gohr * @return string 398f3f0262cSandi */ 39916f15a81SDominik Eckelmannfunction wl($id = '', $urlParameters = '', $absolute = false, $separator = '&') { 400f3f0262cSandi global $conf; 40116f15a81SDominik Eckelmann if(is_array($urlParameters)) { 40216f15a81SDominik Eckelmann $urlParameters = buildURLparams($urlParameters, $separator); 4036de3759aSAndreas Gohr } else { 40416f15a81SDominik Eckelmann $urlParameters = str_replace(',', $separator, $urlParameters); 4056de3759aSAndreas Gohr } 40616f15a81SDominik Eckelmann if($id === '') { 40716f15a81SDominik Eckelmann $id = $conf['start']; 40816f15a81SDominik Eckelmann } 409f3f0262cSandi $id = idfilter($id); 41016f15a81SDominik Eckelmann if($absolute) { 411ed7b5f09Sandi $xlink = DOKU_URL; 412ed7b5f09Sandi } else { 413ed7b5f09Sandi $xlink = DOKU_BASE; 414ed7b5f09Sandi } 415f3f0262cSandi 4166c7843b5Sandi if($conf['userewrite'] == 2) { 4176c7843b5Sandi $xlink .= DOKU_SCRIPT.'/'.$id; 41816f15a81SDominik Eckelmann if($urlParameters) $xlink .= '?'.$urlParameters; 4196c7843b5Sandi } elseif($conf['userewrite']) { 420f3f0262cSandi $xlink .= $id; 42116f15a81SDominik Eckelmann if($urlParameters) $xlink .= '?'.$urlParameters; 422bce3726dSAndreas Gohr } elseif($id) { 4236c7843b5Sandi $xlink .= DOKU_SCRIPT.'?id='.$id; 42416f15a81SDominik Eckelmann if($urlParameters) $xlink .= $separator.$urlParameters; 425bce3726dSAndreas Gohr } else { 426bce3726dSAndreas Gohr $xlink .= DOKU_SCRIPT; 42716f15a81SDominik Eckelmann if($urlParameters) $xlink .= '?'.$urlParameters; 428f3f0262cSandi } 429f3f0262cSandi 430f3f0262cSandi return $xlink; 431f3f0262cSandi} 432f3f0262cSandi 433f3f0262cSandi/** 434f5c2808fSBen Coburn * This builds a link to an alternate page format 435f5c2808fSBen Coburn * 436f5c2808fSBen Coburn * Handles URL rewriting if enabled. Follows the style of wl(). 437f5c2808fSBen Coburn * 438f5c2808fSBen Coburn * @author Ben Coburn <btcoburn@silicodon.net> 439*4bc480e5SAndreas Gohr * @param string $id page id, defaults to start page 440*4bc480e5SAndreas Gohr * @param string $format the export renderer to use 441*4bc480e5SAndreas Gohr * @param string|array $urlParameters URL parameters, associative array recommended 442*4bc480e5SAndreas Gohr * @param bool $abs request an absolute URL instead of relative 443*4bc480e5SAndreas Gohr * @param string $sep parameter separator 444*4bc480e5SAndreas Gohr * @return string 445f5c2808fSBen Coburn */ 446*4bc480e5SAndreas Gohrfunction exportlink($id = '', $format = 'raw', $urlParameters = '', $abs = false, $sep = '&') { 447f5c2808fSBen Coburn global $conf; 448*4bc480e5SAndreas Gohr if(is_array($urlParameters)) { 449*4bc480e5SAndreas Gohr $urlParameters = buildURLparams($urlParameters, $sep); 450f5c2808fSBen Coburn } else { 451*4bc480e5SAndreas Gohr $urlParameters = str_replace(',', $sep, $urlParameters); 452f5c2808fSBen Coburn } 453f5c2808fSBen Coburn 454f5c2808fSBen Coburn $format = rawurlencode($format); 455f5c2808fSBen Coburn $id = idfilter($id); 456f5c2808fSBen Coburn if($abs) { 457f5c2808fSBen Coburn $xlink = DOKU_URL; 458f5c2808fSBen Coburn } else { 459f5c2808fSBen Coburn $xlink = DOKU_BASE; 460f5c2808fSBen Coburn } 461f5c2808fSBen Coburn 462f5c2808fSBen Coburn if($conf['userewrite'] == 2) { 463f5c2808fSBen Coburn $xlink .= DOKU_SCRIPT.'/'.$id.'?do=export_'.$format; 464*4bc480e5SAndreas Gohr if($urlParameters) $xlink .= $sep.$urlParameters; 465f5c2808fSBen Coburn } elseif($conf['userewrite'] == 1) { 466f5c2808fSBen Coburn $xlink .= '_export/'.$format.'/'.$id; 467*4bc480e5SAndreas Gohr if($urlParameters) $xlink .= '?'.$urlParameters; 468f5c2808fSBen Coburn } else { 469f5c2808fSBen Coburn $xlink .= DOKU_SCRIPT.'?do=export_'.$format.$sep.'id='.$id; 470*4bc480e5SAndreas Gohr if($urlParameters) $xlink .= $sep.$urlParameters; 471f5c2808fSBen Coburn } 472f5c2808fSBen Coburn 473f5c2808fSBen Coburn return $xlink; 474f5c2808fSBen Coburn} 475f5c2808fSBen Coburn 476f5c2808fSBen Coburn/** 4776de3759aSAndreas Gohr * Build a link to a media file 4786de3759aSAndreas Gohr * 4796de3759aSAndreas Gohr * Will return a link to the detail page if $direct is false 4808c08db0aSAndreas Gohr * 4818c08db0aSAndreas Gohr * The $more parameter should always be given as array, the function then 4828c08db0aSAndreas Gohr * will strip default parameters to produce even cleaner URLs 4838c08db0aSAndreas Gohr * 4843272d797SAndreas Gohr * @param string $id the media file id or URL 4853272d797SAndreas Gohr * @param mixed $more string or array with additional parameters 4863272d797SAndreas Gohr * @param bool $direct link to detail page if false 4873272d797SAndreas Gohr * @param string $sep URL parameter separator 4883272d797SAndreas Gohr * @param bool $abs Create an absolute URL 4893272d797SAndreas Gohr * @return string 4906de3759aSAndreas Gohr */ 49155b2b31bSAndreas Gohrfunction ml($id = '', $more = '', $direct = true, $sep = '&', $abs = false) { 4926de3759aSAndreas Gohr global $conf; 493b9ee6a44SKlap-in $isexternalimage = media_isexternal($id); 494826d2766SKlap-in if(!$isexternalimage) { 495826d2766SKlap-in $id = cleanID($id); 496826d2766SKlap-in } 497826d2766SKlap-in 4986de3759aSAndreas Gohr if(is_array($more)) { 4990f4e0092SChristopher Smith // add token for resized images 500443e135dSChristopher Smith if(!empty($more['w']) || !empty($more['h']) || $isexternalimage){ 5010f4e0092SChristopher Smith $more['tok'] = media_get_token($id,$more['w'],$more['h']); 5020f4e0092SChristopher Smith } 5038c08db0aSAndreas Gohr // strip defaults for shorter URLs 5048c08db0aSAndreas Gohr if(isset($more['cache']) && $more['cache'] == 'cache') unset($more['cache']); 505443e135dSChristopher Smith if(empty($more['w'])) unset($more['w']); 506443e135dSChristopher Smith if(empty($more['h'])) unset($more['h']); 5078c08db0aSAndreas Gohr if(isset($more['id']) && $direct) unset($more['id']); 508b174aeaeSchris $more = buildURLparams($more, $sep); 5096de3759aSAndreas Gohr } else { 5105e7db1e2SChristopher Smith $matches = array(); 511cc036f74SKlap-in if (preg_match_all('/\b(w|h)=(\d*)\b/',$more,$matches,PREG_SET_ORDER) || $isexternalimage){ 5125e7db1e2SChristopher Smith $resize = array('w'=>0, 'h'=>0); 5135e7db1e2SChristopher Smith foreach ($matches as $match){ 5145e7db1e2SChristopher Smith $resize[$match[1]] = $match[2]; 5155e7db1e2SChristopher Smith } 516cc036f74SKlap-in $more .= $more === '' ? '' : $sep; 517cc036f74SKlap-in $more .= 'tok='.media_get_token($id,$resize['w'],$resize['h']); 5185e7db1e2SChristopher Smith } 5198c08db0aSAndreas Gohr $more = str_replace('cache=cache', '', $more); //skip default 5208c08db0aSAndreas Gohr $more = str_replace(',,', ',', $more); 521b174aeaeSchris $more = str_replace(',', $sep, $more); 5226de3759aSAndreas Gohr } 5236de3759aSAndreas Gohr 52455b2b31bSAndreas Gohr if($abs) { 52555b2b31bSAndreas Gohr $xlink = DOKU_URL; 52655b2b31bSAndreas Gohr } else { 5276de3759aSAndreas Gohr $xlink = DOKU_BASE; 52855b2b31bSAndreas Gohr } 5296de3759aSAndreas Gohr 5306de3759aSAndreas Gohr // external URLs are always direct without rewriting 531826d2766SKlap-in if($isexternalimage) { 5326de3759aSAndreas Gohr $xlink .= 'lib/exe/fetch.php'; 533cc036f74SKlap-in $xlink .= '?'.$more; 534b174aeaeSchris $xlink .= $sep.'media='.rawurlencode($id); 5356de3759aSAndreas Gohr return $xlink; 5366de3759aSAndreas Gohr } 5376de3759aSAndreas Gohr 5386de3759aSAndreas Gohr $id = idfilter($id); 5396de3759aSAndreas Gohr 5406de3759aSAndreas Gohr // decide on scriptname 5416de3759aSAndreas Gohr if($direct) { 5426de3759aSAndreas Gohr if($conf['userewrite'] == 1) { 5436de3759aSAndreas Gohr $script = '_media'; 5446de3759aSAndreas Gohr } else { 5456de3759aSAndreas Gohr $script = 'lib/exe/fetch.php'; 5466de3759aSAndreas Gohr } 5476de3759aSAndreas Gohr } else { 5486de3759aSAndreas Gohr if($conf['userewrite'] == 1) { 5496de3759aSAndreas Gohr $script = '_detail'; 5506de3759aSAndreas Gohr } else { 5516de3759aSAndreas Gohr $script = 'lib/exe/detail.php'; 5526de3759aSAndreas Gohr } 5536de3759aSAndreas Gohr } 5546de3759aSAndreas Gohr 5556de3759aSAndreas Gohr // build URL based on rewrite mode 5566de3759aSAndreas Gohr if($conf['userewrite']) { 5576de3759aSAndreas Gohr $xlink .= $script.'/'.$id; 5586de3759aSAndreas Gohr if($more) $xlink .= '?'.$more; 5596de3759aSAndreas Gohr } else { 5606de3759aSAndreas Gohr if($more) { 561a99d3236SEsther Brunner $xlink .= $script.'?'.$more; 562b174aeaeSchris $xlink .= $sep.'media='.$id; 5636de3759aSAndreas Gohr } else { 564a99d3236SEsther Brunner $xlink .= $script.'?media='.$id; 5656de3759aSAndreas Gohr } 5666de3759aSAndreas Gohr } 5676de3759aSAndreas Gohr 5686de3759aSAndreas Gohr return $xlink; 5696de3759aSAndreas Gohr} 5706de3759aSAndreas Gohr 5716de3759aSAndreas Gohr/** 57225ca5b17SAndreas Gohr * Returns the URL to the DokuWiki base script 57315fae107Sandi * 57425ca5b17SAndreas Gohr * Consider using wl() instead, unless you absoutely need the doku.php endpoint 57525ca5b17SAndreas Gohr * 57615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 577f3f0262cSandi */ 57825ca5b17SAndreas Gohrfunction script() { 579ed7b5f09Sandi return DOKU_BASE.DOKU_SCRIPT; 580f3f0262cSandi} 581f3f0262cSandi 582f3f0262cSandi/** 58315fae107Sandi * Spamcheck against wordlist 58415fae107Sandi * 585f3f0262cSandi * Checks the wikitext against a list of blocked expressions 586f3f0262cSandi * returns true if the text contains any bad words 58715fae107Sandi * 588e403cc58SMichael Klier * Triggers COMMON_WORDBLOCK_BLOCKED 589e403cc58SMichael Klier * 590e403cc58SMichael Klier * Action Plugins can use this event to inspect the blocked data 591e403cc58SMichael Klier * and gain information about the user who was blocked. 592e403cc58SMichael Klier * 593e403cc58SMichael Klier * Event data: 594e403cc58SMichael Klier * data['matches'] - array of matches 595e403cc58SMichael Klier * data['userinfo'] - information about the blocked user 596e403cc58SMichael Klier * [ip] - ip address 597e403cc58SMichael Klier * [user] - username (if logged in) 598e403cc58SMichael Klier * [mail] - mail address (if logged in) 599e403cc58SMichael Klier * [name] - real name (if logged in) 600e403cc58SMichael Klier * 60115fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 6026dffa0e0SAndreas Gohr * @author Michael Klier <chi@chimeric.de> 6036dffa0e0SAndreas Gohr * @param string $text - optional text to check, if not given the globals are used 6046dffa0e0SAndreas Gohr * @return bool - true if a spam word was found 605f3f0262cSandi */ 6066dffa0e0SAndreas Gohrfunction checkwordblock($text = '') { 607f3f0262cSandi global $TEXT; 6086dffa0e0SAndreas Gohr global $PRE; 6096dffa0e0SAndreas Gohr global $SUF; 610e0086ca2SAndreas Gohr global $SUM; 611f3f0262cSandi global $conf; 612e403cc58SMichael Klier global $INFO; 613585bf44eSChristopher Smith /* @var Input $INPUT */ 614585bf44eSChristopher Smith global $INPUT; 615f3f0262cSandi 616f3f0262cSandi if(!$conf['usewordblock']) return false; 617f3f0262cSandi 618e0086ca2SAndreas Gohr if(!$text) $text = "$PRE $TEXT $SUF $SUM"; 6196dffa0e0SAndreas Gohr 620041d1964SAndreas Gohr // we prepare the text a tiny bit to prevent spammers circumventing URL checks 6216dffa0e0SAndreas Gohr $text = preg_replace('!(\b)(www\.[\w.:?\-;,]+?\.[\w.:?\-;,]+?[\w/\#~:.?+=&%@\!\-.:?\-;,]+?)([.:?\-;,]*[^\w/\#~:.?+=&%@\!\-.:?\-;,])!i', '\1http://\2 \2\3', $text); 622041d1964SAndreas Gohr 623b9ac8716Schris $wordblocks = getWordblocks(); 6243e2965d7Sandi // how many lines to read at once (to work around some PCRE limits) 6253e2965d7Sandi if(version_compare(phpversion(), '4.3.0', '<')) { 6263e2965d7Sandi // old versions of PCRE define a maximum of parenthesises even if no 6273e2965d7Sandi // backreferences are used - the maximum is 99 6283e2965d7Sandi // this is very bad performancewise and may even be too high still 6293e2965d7Sandi $chunksize = 40; 6303e2965d7Sandi } else { 631a51d08efSAndreas Gohr // read file in chunks of 200 - this should work around the 6323e2965d7Sandi // MAX_PATTERN_SIZE in modern PCRE 633a51d08efSAndreas Gohr $chunksize = 200; 6343e2965d7Sandi } 635b9ac8716Schris while($blocks = array_splice($wordblocks, 0, $chunksize)) { 636f3f0262cSandi $re = array(); 63749eb6e38SAndreas Gohr // build regexp from blocks 638f3f0262cSandi foreach($blocks as $block) { 639f3f0262cSandi $block = preg_replace('/#.*$/', '', $block); 640f3f0262cSandi $block = trim($block); 641f3f0262cSandi if(empty($block)) continue; 642f3f0262cSandi $re[] = $block; 643f3f0262cSandi } 644e403cc58SMichael Klier if(count($re) && preg_match('#('.join('|', $re).')#si', $text, $matches)) { 645e403cc58SMichael Klier // prepare event data 646e403cc58SMichael Klier $data['matches'] = $matches; 647585bf44eSChristopher Smith $data['userinfo']['ip'] = $INPUT->server->str('REMOTE_ADDR'); 648585bf44eSChristopher Smith if($INPUT->server->str('REMOTE_USER')) { 649585bf44eSChristopher Smith $data['userinfo']['user'] = $INPUT->server->str('REMOTE_USER'); 650e403cc58SMichael Klier $data['userinfo']['name'] = $INFO['userinfo']['name']; 651e403cc58SMichael Klier $data['userinfo']['mail'] = $INFO['userinfo']['mail']; 652e403cc58SMichael Klier } 653e403cc58SMichael Klier $callback = create_function('', 'return true;'); 654e403cc58SMichael Klier return trigger_event('COMMON_WORDBLOCK_BLOCKED', $data, $callback, true); 655b9ac8716Schris } 656703f6fdeSandi } 657f3f0262cSandi return false; 658f3f0262cSandi} 659f3f0262cSandi 660f3f0262cSandi/** 66115fae107Sandi * Return the IP of the client 66215fae107Sandi * 6636d8affe6SAndreas Gohr * Honours X-Forwarded-For and X-Real-IP Proxy Headers 66415fae107Sandi * 6656d8affe6SAndreas Gohr * It returns a comma separated list of IPs if the above mentioned 6666d8affe6SAndreas Gohr * headers are set. If the single parameter is set, it tries to return 6676d8affe6SAndreas Gohr * a routable public address, prefering the ones suplied in the X 6686d8affe6SAndreas Gohr * headers 6696d8affe6SAndreas Gohr * 67015fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 6713272d797SAndreas Gohr * @param boolean $single If set only a single IP is returned 6723272d797SAndreas Gohr * @return string 673f3f0262cSandi */ 6746d8affe6SAndreas Gohrfunction clientIP($single = false) { 675585bf44eSChristopher Smith /* @var Input $INPUT */ 676585bf44eSChristopher Smith global $INPUT; 677585bf44eSChristopher Smith 6786d8affe6SAndreas Gohr $ip = array(); 679585bf44eSChristopher Smith $ip[] = $INPUT->server->str('REMOTE_ADDR'); 680585bf44eSChristopher Smith if($INPUT->server->str('HTTP_X_FORWARDED_FOR')) { 681585bf44eSChristopher Smith $ip = array_merge($ip, explode(',', str_replace(' ', '', $INPUT->server->str('HTTP_X_FORWARDED_FOR')))); 682585bf44eSChristopher Smith } 683585bf44eSChristopher Smith if($INPUT->server->str('HTTP_X_REAL_IP')) { 684585bf44eSChristopher Smith $ip = array_merge($ip, explode(',', str_replace(' ', '', $INPUT->server->str('HTTP_X_REAL_IP')))); 685585bf44eSChristopher Smith } 6866d8affe6SAndreas Gohr 687dc14c6d1SGuy Brand // some IPv4/v6 regexps borrowed from Feyd 688dc14c6d1SGuy Brand // see: http://forums.devnetwork.net/viewtopic.php?f=38&t=53479 689dc14c6d1SGuy Brand $dec_octet = '(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|[0-9])'; 690dc14c6d1SGuy Brand $hex_digit = '[A-Fa-f0-9]'; 691dc14c6d1SGuy Brand $h16 = "{$hex_digit}{1,4}"; 692dc14c6d1SGuy Brand $IPv4Address = "$dec_octet\\.$dec_octet\\.$dec_octet\\.$dec_octet"; 693dc14c6d1SGuy Brand $ls32 = "(?:$h16:$h16|$IPv4Address)"; 694dc14c6d1SGuy Brand $IPv6Address = 695dc14c6d1SGuy Brand "(?:(?:{$IPv4Address})|(?:". 696dc14c6d1SGuy Brand "(?:$h16:){6}$ls32". 697dc14c6d1SGuy Brand "|::(?:$h16:){5}$ls32". 698dc14c6d1SGuy Brand "|(?:$h16)?::(?:$h16:){4}$ls32". 699dc14c6d1SGuy Brand "|(?:(?:$h16:){0,1}$h16)?::(?:$h16:){3}$ls32". 700dc14c6d1SGuy Brand "|(?:(?:$h16:){0,2}$h16)?::(?:$h16:){2}$ls32". 701dc14c6d1SGuy Brand "|(?:(?:$h16:){0,3}$h16)?::(?:$h16:){1}$ls32". 702dc14c6d1SGuy Brand "|(?:(?:$h16:){0,4}$h16)?::$ls32". 703dc14c6d1SGuy Brand "|(?:(?:$h16:){0,5}$h16)?::$h16". 704dc14c6d1SGuy Brand "|(?:(?:$h16:){0,6}$h16)?::". 705dc14c6d1SGuy Brand ")(?:\\/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))?)"; 706dc14c6d1SGuy Brand 7076d8affe6SAndreas Gohr // remove any non-IP stuff 7086d8affe6SAndreas Gohr $cnt = count($ip); 7094ff28443Schris $match = array(); 7106d8affe6SAndreas Gohr for($i = 0; $i < $cnt; $i++) { 711dc14c6d1SGuy Brand if(preg_match("/^$IPv4Address$/", $ip[$i], $match) || preg_match("/^$IPv6Address$/", $ip[$i], $match)) { 7124ff28443Schris $ip[$i] = $match[0]; 7134ff28443Schris } else { 7144ff28443Schris $ip[$i] = ''; 7154ff28443Schris } 7166d8affe6SAndreas Gohr if(empty($ip[$i])) unset($ip[$i]); 717f3f0262cSandi } 7186d8affe6SAndreas Gohr $ip = array_values(array_unique($ip)); 7196d8affe6SAndreas Gohr if(!$ip[0]) $ip[0] = '0.0.0.0'; // for some strange reason we don't have a IP 7206d8affe6SAndreas Gohr 7216d8affe6SAndreas Gohr if(!$single) return join(',', $ip); 7226d8affe6SAndreas Gohr 7236d8affe6SAndreas Gohr // decide which IP to use, trying to avoid local addresses 7246d8affe6SAndreas Gohr $ip = array_reverse($ip); 7256d8affe6SAndreas Gohr foreach($ip as $i) { 7262343a762SAndreas Gohr if(preg_match('/^(::1|[fF][eE]80:|127\.|10\.|192\.168\.|172\.((1[6-9])|(2[0-9])|(3[0-1]))\.)/', $i)) { 7276d8affe6SAndreas Gohr continue; 7286d8affe6SAndreas Gohr } else { 7296d8affe6SAndreas Gohr return $i; 7306d8affe6SAndreas Gohr } 7316d8affe6SAndreas Gohr } 7326d8affe6SAndreas Gohr // still here? just use the first (last) address 7336d8affe6SAndreas Gohr return $ip[0]; 734f3f0262cSandi} 735f3f0262cSandi 736f3f0262cSandi/** 7371c548ebeSAndreas Gohr * Check if the browser is on a mobile device 7381c548ebeSAndreas Gohr * 7391c548ebeSAndreas Gohr * Adapted from the example code at url below 7401c548ebeSAndreas Gohr * 7411c548ebeSAndreas Gohr * @link http://www.brainhandles.com/2007/10/15/detecting-mobile-browsers/#code 7421c548ebeSAndreas Gohr */ 7431c548ebeSAndreas Gohrfunction clientismobile() { 744585bf44eSChristopher Smith /* @var Input $INPUT */ 745585bf44eSChristopher Smith global $INPUT; 7461c548ebeSAndreas Gohr 747585bf44eSChristopher Smith if($INPUT->server->has('HTTP_X_WAP_PROFILE')) return true; 7481c548ebeSAndreas Gohr 749585bf44eSChristopher Smith if(preg_match('/wap\.|\.wap/i', $INPUT->server->str('HTTP_ACCEPT'))) return true; 7501c548ebeSAndreas Gohr 751585bf44eSChristopher Smith if(!$INPUT->server->has('HTTP_USER_AGENT')) return false; 7521c548ebeSAndreas Gohr 7531c548ebeSAndreas Gohr $uamatches = 'midp|j2me|avantg|docomo|novarra|palmos|palmsource|240x320|opwv|chtml|pda|windows ce|mmp\/|blackberry|mib\/|symbian|wireless|nokia|hand|mobi|phone|cdm|up\.b|audio|SIE\-|SEC\-|samsung|HTC|mot\-|mitsu|sagem|sony|alcatel|lg|erics|vx|NEC|philips|mmm|xx|panasonic|sharp|wap|sch|rover|pocket|benq|java|pt|pg|vox|amoi|bird|compal|kg|voda|sany|kdd|dbt|sendo|sgh|gradi|jb|\d\d\di|moto'; 7541c548ebeSAndreas Gohr 755585bf44eSChristopher Smith if(preg_match("/$uamatches/i", $INPUT->server->str('HTTP_USER_AGENT'))) return true; 7561c548ebeSAndreas Gohr 7571c548ebeSAndreas Gohr return false; 7581c548ebeSAndreas Gohr} 7591c548ebeSAndreas Gohr 7601c548ebeSAndreas Gohr/** 76163211f61SGlen Harris * Convert one or more comma separated IPs to hostnames 76263211f61SGlen Harris * 76322ef1e32SAndreas Gohr * If $conf['dnslookups'] is disabled it simply returns the input string 76422ef1e32SAndreas Gohr * 76563211f61SGlen Harris * @author Glen Harris <astfgl@iamnota.org> 7663272d797SAndreas Gohr * @param string $ips comma separated list of IP addresses 7673272d797SAndreas Gohr * @return string a comma separated list of hostnames 76863211f61SGlen Harris */ 76963211f61SGlen Harrisfunction gethostsbyaddrs($ips) { 77022ef1e32SAndreas Gohr global $conf; 77122ef1e32SAndreas Gohr if(!$conf['dnslookups']) return $ips; 77222ef1e32SAndreas Gohr 77363211f61SGlen Harris $hosts = array(); 77463211f61SGlen Harris $ips = explode(',', $ips); 775551a720fSMichael Klier 776551a720fSMichael Klier if(is_array($ips)) { 7773886270dSAndreas Gohr foreach($ips as $ip) { 778551a720fSMichael Klier $hosts[] = gethostbyaddr(trim($ip)); 77963211f61SGlen Harris } 780551a720fSMichael Klier return join(',', $hosts); 781551a720fSMichael Klier } else { 782551a720fSMichael Klier return gethostbyaddr(trim($ips)); 783551a720fSMichael Klier } 78463211f61SGlen Harris} 78563211f61SGlen Harris 78663211f61SGlen Harris/** 78715fae107Sandi * Checks if a given page is currently locked. 78815fae107Sandi * 789f3f0262cSandi * removes stale lockfiles 79015fae107Sandi * 79115fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 792f3f0262cSandi */ 793f3f0262cSandifunction checklock($id) { 794f3f0262cSandi global $conf; 795585bf44eSChristopher Smith /* @var Input $INPUT */ 796585bf44eSChristopher Smith global $INPUT; 797585bf44eSChristopher Smith 798c9b4bd1eSBen Coburn $lock = wikiLockFN($id); 799f3f0262cSandi 800f3f0262cSandi //no lockfile 801f3f0262cSandi if(!@file_exists($lock)) return false; 802f3f0262cSandi 803f3f0262cSandi //lockfile expired 804f3f0262cSandi if((time() - filemtime($lock)) > $conf['locktime']) { 805d8186216SBen Coburn @unlink($lock); 806f3f0262cSandi return false; 807f3f0262cSandi } 808f3f0262cSandi 809f3f0262cSandi //my own lock 8106d2af55dSChristopher Smith @list($ip, $session) = explode("\n", io_readFile($lock)); 8110712fefaSAndreas Gohr if($ip == $INPUT->server->str('REMOTE_USER') || $ip == clientIP() || (session_id() && $session == session_id())) { 812f3f0262cSandi return false; 813f3f0262cSandi } 814f3f0262cSandi 815f3f0262cSandi return $ip; 816f3f0262cSandi} 817f3f0262cSandi 818f3f0262cSandi/** 81915fae107Sandi * Lock a page for editing 82015fae107Sandi * 82115fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 822f3f0262cSandi */ 823f3f0262cSandifunction lock($id) { 824544ed901SDaniel Calviño Sánchez global $conf; 825585bf44eSChristopher Smith /* @var Input $INPUT */ 826585bf44eSChristopher Smith global $INPUT; 827544ed901SDaniel Calviño Sánchez 828544ed901SDaniel Calviño Sánchez if($conf['locktime'] == 0) { 829544ed901SDaniel Calviño Sánchez return; 830544ed901SDaniel Calviño Sánchez } 831544ed901SDaniel Calviño Sánchez 832c9b4bd1eSBen Coburn $lock = wikiLockFN($id); 833585bf44eSChristopher Smith if($INPUT->server->str('REMOTE_USER')) { 834585bf44eSChristopher Smith io_saveFile($lock, $INPUT->server->str('REMOTE_USER')); 835f3f0262cSandi } else { 83685fef7e2SAndreas Gohr io_saveFile($lock, clientIP()."\n".session_id()); 837f3f0262cSandi } 838f3f0262cSandi} 839f3f0262cSandi 840f3f0262cSandi/** 84115fae107Sandi * Unlock a page if it was locked by the user 842f3f0262cSandi * 84315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 8443272d797SAndreas Gohr * @param string $id page id to unlock 84515fae107Sandi * @return bool true if a lock was removed 846f3f0262cSandi */ 847f3f0262cSandifunction unlock($id) { 848585bf44eSChristopher Smith /* @var Input $INPUT */ 849585bf44eSChristopher Smith global $INPUT; 850585bf44eSChristopher Smith 851c9b4bd1eSBen Coburn $lock = wikiLockFN($id); 852f3f0262cSandi if(@file_exists($lock)) { 8536d2af55dSChristopher Smith @list($ip, $session) = explode("\n", io_readFile($lock)); 854585bf44eSChristopher Smith if($ip == $INPUT->server->str('REMOTE_USER') || $ip == clientIP() || $session == session_id()) { 855f3f0262cSandi @unlink($lock); 856f3f0262cSandi return true; 857f3f0262cSandi } 858f3f0262cSandi } 859f3f0262cSandi return false; 860f3f0262cSandi} 861f3f0262cSandi 862f3f0262cSandi/** 863f3f0262cSandi * convert line ending to unix format 864f3f0262cSandi * 8656db7468bSAndreas Gohr * also makes sure the given text is valid UTF-8 8666db7468bSAndreas Gohr * 86715fae107Sandi * @see formText() for 2crlf conversion 86815fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 869f3f0262cSandi */ 870f3f0262cSandifunction cleanText($text) { 871f3f0262cSandi $text = preg_replace("/(\015\012)|(\015)/", "\012", $text); 8726db7468bSAndreas Gohr 8736db7468bSAndreas Gohr // if the text is not valid UTF-8 we simply assume latin1 8746db7468bSAndreas Gohr // this won't break any worse than it breaks with the wrong encoding 8756db7468bSAndreas Gohr // but might actually fix the problem in many cases 8766db7468bSAndreas Gohr if(!utf8_check($text)) $text = utf8_encode($text); 8776db7468bSAndreas Gohr 878f3f0262cSandi return $text; 879f3f0262cSandi} 880f3f0262cSandi 881f3f0262cSandi/** 882f3f0262cSandi * Prepares text for print in Webforms by encoding special chars. 883f3f0262cSandi * It also converts line endings to Windows format which is 884f3f0262cSandi * pseudo standard for webforms. 885f3f0262cSandi * 88615fae107Sandi * @see cleanText() for 2unix conversion 88715fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 888f3f0262cSandi */ 889f3f0262cSandifunction formText($text) { 8905b7d45a5SAndreas Gohr $text = str_replace("\012", "\015\012", $text); 891f3f0262cSandi return htmlspecialchars($text); 892f3f0262cSandi} 893f3f0262cSandi 894f3f0262cSandi/** 89515fae107Sandi * Returns the specified local text in raw format 89615fae107Sandi * 89715fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 898f3f0262cSandi */ 8992adaf2b8SAndreas Gohrfunction rawLocale($id, $ext = 'txt') { 9002adaf2b8SAndreas Gohr return io_readFile(localeFN($id, $ext)); 901f3f0262cSandi} 902f3f0262cSandi 903f3f0262cSandi/** 904f3f0262cSandi * Returns the raw WikiText 90515fae107Sandi * 90615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 907f3f0262cSandi */ 908f3f0262cSandifunction rawWiki($id, $rev = '') { 909cc7d0c94SBen Coburn return io_readWikiPage(wikiFN($id, $rev), $id, $rev); 910f3f0262cSandi} 911f3f0262cSandi 912f3f0262cSandi/** 9137146cee2SAndreas Gohr * Returns the pagetemplate contents for the ID's namespace 9147146cee2SAndreas Gohr * 9157b84afa2SAndreas Gohr * @triggers COMMON_PAGETPL_LOAD 9167146cee2SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 9177146cee2SAndreas Gohr */ 918fe17917eSAdrian Langfunction pageTemplate($id) { 919a15ce62dSEsther Brunner global $conf; 920e29549feSAndreas Gohr 921fe17917eSAdrian Lang if(is_array($id)) $id = $id[0]; 922e29549feSAndreas Gohr 9237b84afa2SAndreas Gohr // prepare initial event data 9247b84afa2SAndreas Gohr $data = array( 9257b84afa2SAndreas Gohr 'id' => $id, // the id of the page to be created 9267b84afa2SAndreas Gohr 'tpl' => '', // the text used as template 9277b84afa2SAndreas Gohr 'tplfile' => '', // the file above text was/should be loaded from 9287b84afa2SAndreas Gohr 'doreplace' => true // should wildcard replacements be done on the text? 9297b84afa2SAndreas Gohr ); 9307b84afa2SAndreas Gohr 9317b84afa2SAndreas Gohr $evt = new Doku_Event('COMMON_PAGETPL_LOAD', $data); 9327b84afa2SAndreas Gohr if($evt->advise_before(true)) { 9337b84afa2SAndreas Gohr // the before event might have loaded the content already 9347b84afa2SAndreas Gohr if(empty($data['tpl'])) { 9357b84afa2SAndreas Gohr // if the before event did not set a template file, try to find one 9367b84afa2SAndreas Gohr if(empty($data['tplfile'])) { 937fe17917eSAdrian Lang $path = dirname(wikiFN($id)); 938e29549feSAndreas Gohr if(@file_exists($path.'/_template.txt')) { 9397b84afa2SAndreas Gohr $data['tplfile'] = $path.'/_template.txt'; 940e29549feSAndreas Gohr } else { 941e29549feSAndreas Gohr // search upper namespaces for templates 942e29549feSAndreas Gohr $len = strlen(rtrim($conf['datadir'], '/')); 943e29549feSAndreas Gohr while(strlen($path) >= $len) { 944e29549feSAndreas Gohr if(@file_exists($path.'/__template.txt')) { 9457b84afa2SAndreas Gohr $data['tplfile'] = $path.'/__template.txt'; 946e29549feSAndreas Gohr break; 947e29549feSAndreas Gohr } 948e29549feSAndreas Gohr $path = substr($path, 0, strrpos($path, '/')); 949e29549feSAndreas Gohr } 950e29549feSAndreas Gohr } 9517b84afa2SAndreas Gohr } 9527b84afa2SAndreas Gohr // load the content 9533d7ac595SMichael Hamann $data['tpl'] = io_readFile($data['tplfile']); 9547b84afa2SAndreas Gohr } 955a1bbd05bSMichael Hamann if($data['doreplace']) parsePageTemplate($data); 9567b84afa2SAndreas Gohr } 9577b84afa2SAndreas Gohr $evt->advise_after(); 9587b84afa2SAndreas Gohr unset($evt); 9597b84afa2SAndreas Gohr 960fe17917eSAdrian Lang return $data['tpl']; 9612b1223ecSAdrian Lang} 9622b1223ecSAdrian Lang 9632b1223ecSAdrian Lang/** 9642b1223ecSAdrian Lang * Performs common page template replacements 9657b84afa2SAndreas Gohr * This works on data from COMMON_PAGETPL_LOAD 9662b1223ecSAdrian Lang * 9672b1223ecSAdrian Lang * @author Andreas Gohr <andi@splitbrain.org> 9682b1223ecSAdrian Lang */ 969d535a2e9Sstretchyboyfunction parsePageTemplate(&$data) { 9703272d797SAndreas Gohr /** 9713272d797SAndreas Gohr * @var string $id the id of the page to be created 9723272d797SAndreas Gohr * @var string $tpl the text used as template 9733272d797SAndreas Gohr * @var string $tplfile the file above text was/should be loaded from 9743272d797SAndreas Gohr * @var bool $doreplace should wildcard replacements be done on the text? 9753272d797SAndreas Gohr */ 976fe17917eSAdrian Lang extract($data); 977fe17917eSAdrian Lang 978b856f7dfSAdrian Lang global $USERINFO; 979bce53b1fSAdrian Lang global $conf; 980585bf44eSChristopher Smith /* @var Input $INPUT */ 981585bf44eSChristopher Smith global $INPUT; 982e29549feSAndreas Gohr 983e29549feSAndreas Gohr // replace placeholders 98426ece5a7SAndreas Gohr $file = noNS($id); 98537c1acbdSAdrian Lang $page = strtr($file, $conf['sepchar'], ' '); 98626ece5a7SAndreas Gohr 9873272d797SAndreas Gohr $tpl = str_replace( 9883272d797SAndreas Gohr array( 98926ece5a7SAndreas Gohr '@ID@', 99026ece5a7SAndreas Gohr '@NS@', 99126ece5a7SAndreas Gohr '@FILE@', 99226ece5a7SAndreas Gohr '@!FILE@', 99326ece5a7SAndreas Gohr '@!FILE!@', 99426ece5a7SAndreas Gohr '@PAGE@', 99526ece5a7SAndreas Gohr '@!PAGE@', 99626ece5a7SAndreas Gohr '@!!PAGE@', 99726ece5a7SAndreas Gohr '@!PAGE!@', 99826ece5a7SAndreas Gohr '@USER@', 99926ece5a7SAndreas Gohr '@NAME@', 100026ece5a7SAndreas Gohr '@MAIL@', 100126ece5a7SAndreas Gohr '@DATE@', 100226ece5a7SAndreas Gohr ), 100326ece5a7SAndreas Gohr array( 100426ece5a7SAndreas Gohr $id, 100526ece5a7SAndreas Gohr getNS($id), 100626ece5a7SAndreas Gohr $file, 100726ece5a7SAndreas Gohr utf8_ucfirst($file), 100826ece5a7SAndreas Gohr utf8_strtoupper($file), 100926ece5a7SAndreas Gohr $page, 101026ece5a7SAndreas Gohr utf8_ucfirst($page), 101126ece5a7SAndreas Gohr utf8_ucwords($page), 101226ece5a7SAndreas Gohr utf8_strtoupper($page), 1013585bf44eSChristopher Smith $INPUT->server->str('REMOTE_USER'), 1014b856f7dfSAdrian Lang $USERINFO['name'], 1015b856f7dfSAdrian Lang $USERINFO['mail'], 101626ece5a7SAndreas Gohr $conf['dformat'], 10173272d797SAndreas Gohr ), $tpl 10183272d797SAndreas Gohr ); 101926ece5a7SAndreas Gohr 10207d644fc8SAndreas Gohr // we need the callback to work around strftime's char limit 10217d644fc8SAndreas Gohr $tpl = preg_replace_callback('/%./', create_function('$m', 'return strftime($m[0]);'), $tpl); 1022d535a2e9Sstretchyboy $data['tpl'] = $tpl; 1023a15ce62dSEsther Brunner return $tpl; 10247146cee2SAndreas Gohr} 10257146cee2SAndreas Gohr 10267146cee2SAndreas Gohr/** 102715fae107Sandi * Returns the raw Wiki Text in three slices. 102815fae107Sandi * 102915fae107Sandi * The range parameter needs to have the form "from-to" 103015cfe303Sandi * and gives the range of the section in bytes - no 103115cfe303Sandi * UTF-8 awareness is needed. 1032f3f0262cSandi * The returned order is prefix, section and suffix. 103315fae107Sandi * 103415fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 1035f3f0262cSandi */ 1036f3f0262cSandifunction rawWikiSlices($range, $id, $rev = '') { 1037cc7d0c94SBen Coburn $text = io_readWikiPage(wikiFN($id, $rev), $id, $rev); 1038f3f0262cSandi 103980fcb268SAdrian Lang // Parse range 104080fcb268SAdrian Lang list($from, $to) = explode('-', $range, 2); 104180fcb268SAdrian Lang // Make range zero-based, use defaults if marker is missing 104280fcb268SAdrian Lang $from = !$from ? 0 : ($from - 1); 104380fcb268SAdrian Lang $to = !$to ? strlen($text) : ($to - 1); 104480fcb268SAdrian Lang 104580fcb268SAdrian Lang $slices[0] = substr($text, 0, $from); 104680fcb268SAdrian Lang $slices[1] = substr($text, $from, $to - $from); 104715cfe303Sandi $slices[2] = substr($text, $to); 1048f3f0262cSandi return $slices; 1049f3f0262cSandi} 1050f3f0262cSandi 1051f3f0262cSandi/** 105215fae107Sandi * Joins wiki text slices 105315fae107Sandi * 105480fcb268SAdrian Lang * function to join the text slices. 1055f3f0262cSandi * When the pretty parameter is set to true it adds additional empty 1056f3f0262cSandi * lines between sections if needed (used on saving). 105715fae107Sandi * 105815fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 1059f3f0262cSandi */ 1060f3f0262cSandifunction con($pre, $text, $suf, $pretty = false) { 1061f3f0262cSandi if($pretty) { 106280fcb268SAdrian Lang if($pre !== '' && substr($pre, -1) !== "\n" && 10633272d797SAndreas Gohr substr($text, 0, 1) !== "\n" 10643272d797SAndreas Gohr ) { 106580fcb268SAdrian Lang $pre .= "\n"; 106680fcb268SAdrian Lang } 106780fcb268SAdrian Lang if($suf !== '' && substr($text, -1) !== "\n" && 10683272d797SAndreas Gohr substr($suf, 0, 1) !== "\n" 10693272d797SAndreas Gohr ) { 107080fcb268SAdrian Lang $text .= "\n"; 107180fcb268SAdrian Lang } 1072f3f0262cSandi } 1073f3f0262cSandi 1074f3f0262cSandi return $pre.$text.$suf; 1075f3f0262cSandi} 1076f3f0262cSandi 1077f3f0262cSandi/** 1078a701424fSBen Coburn * Saves a wikitext by calling io_writeWikiPage. 1079a701424fSBen Coburn * Also directs changelog and attic updates. 108015fae107Sandi * 108115fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 108271726d78SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net> 1083f3f0262cSandi */ 1084b6912aeaSAndreas Gohrfunction saveWikiText($id, $text, $summary, $minor = false) { 1085a701424fSBen Coburn /* Note to developers: 1086a701424fSBen Coburn This code is subtle and delicate. Test the behavior of 1087a701424fSBen Coburn the attic and changelog with dokuwiki and external edits 1088a701424fSBen Coburn after any changes. External edits change the wiki page 1089a701424fSBen Coburn directly without using php or dokuwiki. 1090a701424fSBen Coburn */ 1091f3f0262cSandi global $conf; 1092f3f0262cSandi global $lang; 109371726d78SBen Coburn global $REV; 1094585bf44eSChristopher Smith /* @var Input $INPUT */ 1095585bf44eSChristopher Smith global $INPUT; 1096585bf44eSChristopher Smith 1097f3f0262cSandi // ignore if no changes were made 1098f3f0262cSandi if($text == rawWiki($id, '')) { 1099f3f0262cSandi return; 1100f3f0262cSandi } 1101f3f0262cSandi 1102f3f0262cSandi $file = wikiFN($id); 1103a701424fSBen Coburn $old = @filemtime($file); // from page 1104407e65b9SAndreas Gohr $wasRemoved = (trim($text) == ''); // check for empty or whitespace only 1105d8186216SBen Coburn $wasCreated = !@file_exists($file); 110671726d78SBen Coburn $wasReverted = ($REV == true); 1107047bad06SGerrit Uitslag $pagelog = new PageChangeLog($id, 1024); 1108e45b34cdSBen Coburn $newRev = false; 1109f523c971SGerrit Uitslag $oldRev = $pagelog->getRevisions(-1, 1); // from changelog 1110a701424fSBen Coburn $oldRev = (int) (empty($oldRev) ? 0 : $oldRev[0]); 1111a701424fSBen Coburn if(!@file_exists(wikiFN($id, $old)) && @file_exists($file) && $old >= $oldRev) { 111246844156SBen Coburn // add old revision to the attic if missing 111346844156SBen Coburn saveOldRevision($id); 111446844156SBen Coburn // add a changelog entry if this edit came from outside dokuwiki 1115a701424fSBen Coburn if($old > $oldRev) { 1116ebf1501fSBen Coburn addLogEntry($old, $id, DOKU_CHANGE_TYPE_EDIT, $lang['external_edit'], '', array('ExternalEdit'=> true)); 111746844156SBen Coburn // remove soon to be stale instructions 111846844156SBen Coburn $cache = new cache_instructions($id, $file); 111946844156SBen Coburn $cache->removeCache(); 112046844156SBen Coburn } 112146844156SBen Coburn } 1122f3f0262cSandi 112371726d78SBen Coburn if($wasRemoved) { 112430725328SGabriel Birke // Send "update" event with empty data, so plugins can react to page deletion 112530725328SGabriel Birke $data = array(array($file, '', false), getNS($id), noNS($id), false); 112630725328SGabriel Birke trigger_event('IO_WIKIPAGE_WRITE', $data); 1127e45b34cdSBen Coburn // pre-save deleted revision 1128e45b34cdSBen Coburn @touch($file); 112946844156SBen Coburn clearstatcache(); 1130e45b34cdSBen Coburn $newRev = saveOldRevision($id); 1131e1f3d9e1SEsther Brunner // remove empty file 1132f3f0262cSandi @unlink($file); 1133c5f92742SMichael Hamann // don't remove old meta info as it should be saved, plugins can use IO_WIKIPAGE_WRITE for removing their metadata... 1134c5f92742SMichael Hamann // purge non-persistant meta data 11353d1f9ec3SMichael Klier p_purge_metadata($id); 1136f3f0262cSandi $del = true; 11373ce054b3Sandi // autoset summary on deletion 11383ce054b3Sandi if(empty($summary)) $summary = $lang['deleted']; 113953d6ccfeSandi // remove empty namespaces 1140cc7d0c94SBen Coburn io_sweepNS($id, 'datadir'); 1141cc7d0c94SBen Coburn io_sweepNS($id, 'mediadir'); 1142f3f0262cSandi } else { 1143cc7d0c94SBen Coburn // save file (namespace dir is created in io_writeWikiPage) 1144cc7d0c94SBen Coburn io_writeWikiPage($file, $text, $id); 114546844156SBen Coburn // pre-save the revision, to keep the attic in sync 114646844156SBen Coburn $newRev = saveOldRevision($id); 1147f3f0262cSandi $del = false; 1148f3f0262cSandi } 1149f3f0262cSandi 115071726d78SBen Coburn // select changelog line type 115171726d78SBen Coburn $extra = ''; 1152ebf1501fSBen Coburn $type = DOKU_CHANGE_TYPE_EDIT; 115371726d78SBen Coburn if($wasReverted) { 1154ebf1501fSBen Coburn $type = DOKU_CHANGE_TYPE_REVERT; 115571726d78SBen Coburn $extra = $REV; 11563272d797SAndreas Gohr } else if($wasCreated) { 11573272d797SAndreas Gohr $type = DOKU_CHANGE_TYPE_CREATE; 11583272d797SAndreas Gohr } else if($wasRemoved) { 11593272d797SAndreas Gohr $type = DOKU_CHANGE_TYPE_DELETE; 1160585bf44eSChristopher Smith } else if($minor && $conf['useacl'] && $INPUT->server->str('REMOTE_USER')) { 11613272d797SAndreas Gohr $type = DOKU_CHANGE_TYPE_MINOR_EDIT; 11623272d797SAndreas Gohr } //minor edits only for logged in users 116371726d78SBen Coburn 1164e45b34cdSBen Coburn addLogEntry($newRev, $id, $type, $summary, $extra); 116526a0801fSAndreas Gohr // send notify mails 116690033e9dSAndreas Gohr notify($id, 'admin', $old, $summary, $minor); 116790033e9dSAndreas Gohr notify($id, 'subscribers', $old, $summary, $minor); 1168f3f0262cSandi 1169ce6b63d9Schris // update the purgefile (timestamp of the last time anything within the wiki was changed) 117098407a7aSandi io_saveFile($conf['cachedir'].'/purgefile', time()); 11712eccbdaaSGina Haeussge 11722eccbdaaSGina Haeussge // if useheading is enabled, purge the cache of all linking pages 1173fe9ec250SChris Smith if(useHeading('content')) { 117407ff0babSMichael Hamann $pages = ft_backlinks($id, true); 11752eccbdaaSGina Haeussge foreach($pages as $page) { 11762eccbdaaSGina Haeussge $cache = new cache_renderer($page, wikiFN($page), 'xhtml'); 11772eccbdaaSGina Haeussge $cache->removeCache(); 11782eccbdaaSGina Haeussge } 11792eccbdaaSGina Haeussge } 1180f3f0262cSandi} 1181f3f0262cSandi 1182f3f0262cSandi/** 1183f3f0262cSandi * moves the current version to the attic and returns its 1184f3f0262cSandi * revision date 118515fae107Sandi * 118615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 1187f3f0262cSandi */ 1188f3f0262cSandifunction saveOldRevision($id) { 1189f3f0262cSandi $oldf = wikiFN($id); 1190f3f0262cSandi if(!@file_exists($oldf)) return ''; 1191f3f0262cSandi $date = filemtime($oldf); 1192f3f0262cSandi $newf = wikiFN($id, $date); 1193cc7d0c94SBen Coburn io_writeWikiPage($newf, rawWiki($id), $id, $date); 1194f3f0262cSandi return $date; 1195f3f0262cSandi} 1196f3f0262cSandi 1197f3f0262cSandi/** 1198fde10de4SAdrian Lang * Sends a notify mail on page change or registration 119926a0801fSAndreas Gohr * 120026a0801fSAndreas Gohr * @param string $id The changed page 1201fde10de4SAdrian Lang * @param string $who Who to notify (admin|subscribers|register) 12023272d797SAndreas Gohr * @param int|string $rev Old page revision 120326a0801fSAndreas Gohr * @param string $summary What changed 120490033e9dSAndreas Gohr * @param boolean $minor Is this a minor edit? 120502a498e7Schris * @param array $replace Additional string substitutions, @KEY@ to be replaced by value 120615fae107Sandi * 12073272d797SAndreas Gohr * @return bool 120815fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 1209f3f0262cSandi */ 121002a498e7Schrisfunction notify($id, $who, $rev = '', $summary = '', $minor = false, $replace = array()) { 1211f3f0262cSandi global $conf; 1212585bf44eSChristopher Smith /* @var Input $INPUT */ 1213585bf44eSChristopher Smith global $INPUT; 1214b158d625SSteven Danz 12156df843eeSAndreas Gohr // decide if there is something to do, eg. whom to mail 121626a0801fSAndreas Gohr if($who == 'admin') { 12173272d797SAndreas Gohr if(empty($conf['notify'])) return false; //notify enabled? 12182ed38036SAndreas Gohr $tpl = 'mailtext'; 121926a0801fSAndreas Gohr $to = $conf['notify']; 122026a0801fSAndreas Gohr } elseif($who == 'subscribers') { 122184c1127cSAndreas Gohr if(!actionOK('subscribe')) return false; //subscribers enabled? 1222585bf44eSChristopher Smith if($conf['useacl'] && $INPUT->server->str('REMOTE_USER') && $minor) return false; //skip minors 12238881fcc9SAdrian Lang $data = array('id' => $id, 'addresslist' => '', 'self' => false); 12243272d797SAndreas Gohr trigger_event( 12253272d797SAndreas Gohr 'COMMON_NOTIFY_ADDRESSLIST', $data, 1226835242b0SAndreas Gohr array(new Subscription(), 'notifyaddresses') 12273272d797SAndreas Gohr ); 12282ed38036SAndreas Gohr $to = $data['addresslist']; 12292ed38036SAndreas Gohr if(empty($to)) return false; 12302ed38036SAndreas Gohr $tpl = 'subscr_single'; 123126a0801fSAndreas Gohr } else { 12323272d797SAndreas Gohr return false; //just to be safe 123326a0801fSAndreas Gohr } 123426a0801fSAndreas Gohr 12356df843eeSAndreas Gohr // prepare content 12362ed38036SAndreas Gohr $subscription = new Subscription(); 12372ed38036SAndreas Gohr return $subscription->send_diff($to, $tpl, $id, $rev, $summary); 1238f3f0262cSandi} 12392ed38036SAndreas Gohr 124015fae107Sandi/** 124171f7bde7SAndreas Gohr * extracts the query from a search engine referrer 124215fae107Sandi * 124315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org> 124471f7bde7SAndreas Gohr * @author Todd Augsburger <todd@rollerorgans.com> 1245f3f0262cSandi */ 1246f3f0262cSandifunction getGoogleQuery() { 1247585bf44eSChristopher Smith /* @var Input $INPUT */ 1248585bf44eSChristopher Smith global $INPUT; 1249585bf44eSChristopher Smith 1250585bf44eSChristopher Smith if(!$INPUT->server->has('HTTP_REFERER')) { 1251c66972f2SAdrian Lang return ''; 1252c66972f2SAdrian Lang } 1253585bf44eSChristopher Smith $url = parse_url($INPUT->server->str('HTTP_REFERER')); 1254f3f0262cSandi 1255079b3ac1SAndreas Gohr // only handle common SEs 1256079b3ac1SAndreas Gohr if(!preg_match('/(google|bing|yahoo|ask|duckduckgo|babylon|aol|yandex)/',$url['host'])) return ''; 1257e4d8a516SKazutaka Miyasaka 1258079b3ac1SAndreas Gohr $query = array(); 1259e4d8a516SKazutaka Miyasaka // temporary workaround against PHP bug #49733 1260e4d8a516SKazutaka Miyasaka // see http://bugs.php.net/bug.php?id=49733 1261e4d8a516SKazutaka Miyasaka if(UTF8_MBSTRING) $enc = mb_internal_encoding(); 1262f3f0262cSandi parse_str($url['query'], $query); 1263e4d8a516SKazutaka Miyasaka if(UTF8_MBSTRING) mb_internal_encoding($enc); 1264e4d8a516SKazutaka Miyasaka 1265c66972f2SAdrian Lang $q = ''; 1266079b3ac1SAndreas Gohr if(isset($query['q'])){ 1267079b3ac1SAndreas Gohr $q = $query['q']; 1268079b3ac1SAndreas Gohr }elseif(isset($query['p'])){ 1269079b3ac1SAndreas Gohr $q = $query['p']; 1270079b3ac1SAndreas Gohr }elseif(isset($query['query'])){ 1271079b3ac1SAndreas Gohr $q = $query['query']; 1272079b3ac1SAndreas Gohr } 1273079b3ac1SAndreas Gohr $q = trim($q); 1274f3f0262cSandi 1275079b3ac1SAndreas Gohr if(!$q) return ''; 12766531ab03SAndreas Gohr $q = preg_split('/[\s\'"\\\\`()\]\[?:!\.{};,#+*<>\\/]+/', $q, -1, PREG_SPLIT_NO_EMPTY); 1277f93b3b50SAndreas Gohr return $q; 1278f3f0262cSandi} 1279f3f0262cSandi 1280f3f0262cSandi/** 1281f3f0262cSandi * Return the human readable size of a file 1282f3f0262cSandi * 1283f3f0262cSandi * @param int $size A file size 1284f3f0262cSandi * @param int $dec A number of decimal places 128574160ca1SGerrit Uitslag * @return string human readable size 1286f3f0262cSandi * @author Martin Benjamin <b.martin@cybernet.ch> 1287f3f0262cSandi * @author Aidan Lister <aidan@php.net> 1288f3f0262cSandi * @version 1.0.0 1289f3f0262cSandi */ 1290f31d5b73Sandifunction filesize_h($size, $dec = 1) { 1291f3f0262cSandi $sizes = array('B', 'KB', 'MB', 'GB'); 1292f3f0262cSandi $count = count($sizes); 1293f3f0262cSandi $i = 0; 1294f3f0262cSandi 1295f3f0262cSandi while($size >= 1024 && ($i < $count - 1)) { 1296f3f0262cSandi $size /= 1024; 1297f3f0262cSandi $i++; 1298f3f0262cSandi } 1299f3f0262cSandi 1300f3f0262cSandi return round($size, $dec).' '.$sizes[$i]; 1301f3f0262cSandi} 1302f3f0262cSandi 130315fae107Sandi/** 1304c57e365eSAndreas Gohr * Return the given timestamp as human readable, fuzzy age 1305c57e365eSAndreas Gohr * 1306c57e365eSAndreas Gohr * @author Andreas Gohr <gohr@cosmocode.de> 1307c57e365eSAndreas Gohr */ 1308c57e365eSAndreas Gohrfunction datetime_h($dt) { 1309c57e365eSAndreas Gohr global $lang; 1310c57e365eSAndreas Gohr 1311c57e365eSAndreas Gohr $ago = time() - $dt; 1312c57e365eSAndreas Gohr if($ago > 24 * 60 * 60 * 30 * 12 * 2) { 1313c57e365eSAndreas Gohr return sprintf($lang['years'], round($ago / (24 * 60 * 60 * 30 * 12))); 1314c57e365eSAndreas Gohr } 1315c57e365eSAndreas Gohr if($ago > 24 * 60 * 60 * 30 * 2) { 1316c57e365eSAndreas Gohr return sprintf($lang['months'], round($ago / (24 * 60 * 60 * 30))); 1317c57e365eSAndreas Gohr } 1318c57e365eSAndreas Gohr if($ago > 24 * 60 * 60 * 7 * 2) { 1319c57e365eSAndreas Gohr return sprintf($lang['weeks'], round($ago / (24 * 60 * 60 * 7))); 1320c57e365eSAndreas Gohr } 1321c57e365eSAndreas Gohr if($ago > 24 * 60 * 60 * 2) { 1322c57e365eSAndreas Gohr return sprintf($lang['days'], round($ago / (24 * 60 * 60))); 1323c57e365eSAndreas Gohr } 1324c57e365eSAndreas Gohr if($ago > 60 * 60 * 2) { 1325c57e365eSAndreas Gohr return sprintf($lang['hours'], round($ago / (60 * 60))); 1326c57e365eSAndreas Gohr } 1327c57e365eSAndreas Gohr if($ago > 60 * 2) { 1328c57e365eSAndreas Gohr return sprintf($lang['minutes'], round($ago / (60))); 1329c57e365eSAndreas Gohr } 1330c57e365eSAndreas Gohr return sprintf($lang['seconds'], $ago); 1331c57e365eSAndreas Gohr} 1332c57e365eSAndreas Gohr 1333c57e365eSAndreas Gohr/** 1334f2263577SAndreas Gohr * Wraps around strftime but provides support for fuzzy dates 1335f2263577SAndreas Gohr * 1336f2263577SAndreas Gohr * The format default to $conf['dformat']. It is passed to 1337f2263577SAndreas Gohr * strftime - %f can be used to get the value from datetime_h() 1338f2263577SAndreas Gohr * 1339f2263577SAndreas Gohr * @see datetime_h 1340f2263577SAndreas Gohr * @author Andreas Gohr <gohr@cosmocode.de> 1341f2263577SAndreas Gohr */ 1342f2263577SAndreas Gohrfunction dformat($dt = null, $format = '') { 1343f2263577SAndreas Gohr global $conf; 1344f2263577SAndreas Gohr 1345f2263577SAndreas Gohr if(is_null($dt)) $dt = time(); 1346f2263577SAndreas Gohr $dt = (int) $dt; 1347f2263577SAndreas Gohr if(!$format) $format = $conf['dformat']; 1348f2263577SAndreas Gohr 1349f2263577SAndreas Gohr $format = str_replace('%f', datetime_h($dt), $format); 1350f2263577SAndreas Gohr return strftime($format, $dt); 1351f2263577SAndreas Gohr} 1352f2263577SAndreas Gohr 1353f2263577SAndreas Gohr/** 1354c4f79b71SMichael Hamann * Formats a timestamp as ISO 8601 date 1355c4f79b71SMichael Hamann * 1356c4f79b71SMichael Hamann * @author <ungu at terong dot com> 1357c4f79b71SMichael Hamann * @link http://www.php.net/manual/en/function.date.php#54072 135863703ba5SAndreas Gohr * @param int $int_date: current date in UNIX timestamp 13593272d797SAndreas Gohr * @return string 1360c4f79b71SMichael Hamann */ 1361c4f79b71SMichael Hamannfunction date_iso8601($int_date) { 1362c4f79b71SMichael Hamann $date_mod = date('Y-m-d\TH:i:s', $int_date); 1363c4f79b71SMichael Hamann $pre_timezone = date('O', $int_date); 1364c4f79b71SMichael Hamann $time_zone = substr($pre_timezone, 0, 3).":".substr($pre_timezone, 3, 2); 1365c4f79b71SMichael Hamann $date_mod .= $time_zone; 1366c4f79b71SMichael Hamann return $date_mod; 1367c4f79b71SMichael Hamann} 1368c4f79b71SMichael Hamann 1369c4f79b71SMichael Hamann/** 137000a7b5adSEsther Brunner * return an obfuscated email address in line with $conf['mailguard'] setting 137100a7b5adSEsther Brunner * 137200a7b5adSEsther Brunner * @author Harry Fuecks <hfuecks@gmail.com> 137300a7b5adSEsther Brunner * @author Christopher Smith <chris@jalakai.co.uk> 137400a7b5adSEsther Brunner */ 137500a7b5adSEsther Brunnerfunction obfuscate($email) { 137600a7b5adSEsther Brunner global $conf; 137700a7b5adSEsther Brunner 137800a7b5adSEsther Brunner switch($conf['mailguard']) { 137900a7b5adSEsther Brunner case 'visible' : 138000a7b5adSEsther Brunner $obfuscate = array('@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] '); 138100a7b5adSEsther Brunner return strtr($email, $obfuscate); 138200a7b5adSEsther Brunner 138300a7b5adSEsther Brunner case 'hex' : 138400a7b5adSEsther Brunner $encode = ''; 138549eb6e38SAndreas Gohr $len = strlen($email); 138649eb6e38SAndreas Gohr for($x = 0; $x < $len; $x++) { 138749eb6e38SAndreas Gohr $encode .= '&#x'.bin2hex($email{$x}).';'; 138849eb6e38SAndreas Gohr } 138900a7b5adSEsther Brunner return $encode; 139000a7b5adSEsther Brunner 139100a7b5adSEsther Brunner case 'none' : 139200a7b5adSEsther Brunner default : 139300a7b5adSEsther Brunner return $email; 139400a7b5adSEsther Brunner } 139500a7b5adSEsther Brunner} 139600a7b5adSEsther Brunner 139700a7b5adSEsther Brunner/** 139889541d4bSAndreas Gohr * Removes quoting backslashes 139989541d4bSAndreas Gohr * 140089541d4bSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 140189541d4bSAndreas Gohr */ 140289541d4bSAndreas Gohrfunction unslash($string, $char = "'") { 140389541d4bSAndreas Gohr return str_replace('\\'.$char, $char, $string); 140489541d4bSAndreas Gohr} 140589541d4bSAndreas Gohr 140673038c47SAndreas Gohr/** 140773038c47SAndreas Gohr * Convert php.ini shorthands to byte 140873038c47SAndreas Gohr * 140973038c47SAndreas Gohr * @author <gilthans dot NO dot SPAM at gmail dot com> 141073038c47SAndreas Gohr * @link http://de3.php.net/manual/en/ini.core.php#79564 141173038c47SAndreas Gohr */ 141273038c47SAndreas Gohrfunction php_to_byte($v) { 141373038c47SAndreas Gohr $l = substr($v, -1); 141473038c47SAndreas Gohr $ret = substr($v, 0, -1); 141573038c47SAndreas Gohr switch(strtoupper($l)) { 141674160ca1SGerrit Uitslag /** @noinspection PhpMissingBreakStatementInspection */ 141773038c47SAndreas Gohr case 'P': 141873038c47SAndreas Gohr $ret *= 1024; 141974160ca1SGerrit Uitslag /** @noinspection PhpMissingBreakStatementInspection */ 142073038c47SAndreas Gohr case 'T': 142173038c47SAndreas Gohr $ret *= 1024; 142274160ca1SGerrit Uitslag /** @noinspection PhpMissingBreakStatementInspection */ 142373038c47SAndreas Gohr case 'G': 142473038c47SAndreas Gohr $ret *= 1024; 142574160ca1SGerrit Uitslag /** @noinspection PhpMissingBreakStatementInspection */ 142673038c47SAndreas Gohr case 'M': 142773038c47SAndreas Gohr $ret *= 1024; 142873038c47SAndreas Gohr case 'K': 142973038c47SAndreas Gohr $ret *= 1024; 143073038c47SAndreas Gohr break; 143149cbd23eSOtto Vainio default; 143249cbd23eSOtto Vainio $ret *= 10; 143349cbd23eSOtto Vainio break; 143473038c47SAndreas Gohr } 143573038c47SAndreas Gohr return $ret; 143673038c47SAndreas Gohr} 143773038c47SAndreas Gohr 1438546d3a99SAndreas Gohr/** 1439546d3a99SAndreas Gohr * Wrapper around preg_quote adding the default delimiter 1440546d3a99SAndreas Gohr */ 1441546d3a99SAndreas Gohrfunction preg_quote_cb($string) { 1442546d3a99SAndreas Gohr return preg_quote($string, '/'); 1443546d3a99SAndreas Gohr} 144473038c47SAndreas Gohr 1445bd2f6c2fSAndreas Gohr/** 1446bd2f6c2fSAndreas Gohr * Shorten a given string by removing data from the middle 1447bd2f6c2fSAndreas Gohr * 1448c66972f2SAdrian Lang * You can give the string in two parts, the first part $keep 1449bd2f6c2fSAndreas Gohr * will never be shortened. The second part $short will be cut 1450bd2f6c2fSAndreas Gohr * in the middle to shorten but only if at least $min chars are 1451bd2f6c2fSAndreas Gohr * left to display it. Otherwise it will be left off. 1452bd2f6c2fSAndreas Gohr * 1453bd2f6c2fSAndreas Gohr * @param string $keep the part to keep 1454bd2f6c2fSAndreas Gohr * @param string $short the part to shorten 1455bd2f6c2fSAndreas Gohr * @param int $max maximum chars you want for the whole string 1456bd2f6c2fSAndreas Gohr * @param int $min minimum number of chars to have left for middle shortening 1457bd2f6c2fSAndreas Gohr * @param string $char the shortening character to use 14583272d797SAndreas Gohr * @return string 1459bd2f6c2fSAndreas Gohr */ 1460a5d27328SAndreas Gohrfunction shorten($keep, $short, $max, $min = 9, $char = '…') { 1461bd2f6c2fSAndreas Gohr $max = $max - utf8_strlen($keep); 1462bd2f6c2fSAndreas Gohr if($max < $min) return $keep; 1463bd2f6c2fSAndreas Gohr $len = utf8_strlen($short); 1464bd2f6c2fSAndreas Gohr if($len <= $max) return $keep.$short; 1465bd2f6c2fSAndreas Gohr $half = floor($max / 2); 1466bd2f6c2fSAndreas Gohr return $keep.utf8_substr($short, 0, $half - 1).$char.utf8_substr($short, $len - $half); 1467bd2f6c2fSAndreas Gohr} 1468bd2f6c2fSAndreas Gohr 1469dc58b6f4SAndy Webber/** 1470dc58b6f4SAndy Webber * Return the users realname or e-mail address for use 1471dc58b6f4SAndy Webber * in page footer and recent changes pages 1472dc58b6f4SAndy Webber * 147315f3bc49SGerrit Uitslag * @param string|bool $username or false when currently logged-in user should be used 147415f3bc49SGerrit Uitslag * @param bool $textonly true returns only plain text, true allows returning html 1475c0953023SGerrit Uitslag * @return string html or plain text(not escaped) of formatted user name 147615f3bc49SGerrit Uitslag * 1477dc58b6f4SAndy Webber * @author Andy Webber <dokuwiki AT andywebber DOT com> 1478dc58b6f4SAndy Webber */ 147915f3bc49SGerrit Uitslagfunction editorinfo($username, $textonly = false) { 1480cd4635eeSGerrit Uitslag return userlink($username, $textonly); 1481dc58b6f4SAndy Webber} 1482dc58b6f4SAndy Webber 148360a396c8SGerrit Uitslag/** 148460a396c8SGerrit Uitslag * Returns users realname w/o link 148560a396c8SGerrit Uitslag * 148660a396c8SGerrit Uitslag * @param string|bool $username or false when currently logged-in user should be used 148715f3bc49SGerrit Uitslag * @param bool $textonly true returns only plain text, true allows returning html 1488c0953023SGerrit Uitslag * @return string html or plain text(not escaped) of formatted user name 148960a396c8SGerrit Uitslag * 149060a396c8SGerrit Uitslag * @triggers COMMON_USER_LINK 149160a396c8SGerrit Uitslag */ 1492cd4635eeSGerrit Uitslagfunction userlink($username = null, $textonly = false) { 149360a396c8SGerrit Uitslag global $conf, $INFO; 149460a396c8SGerrit Uitslag /** @var DokuWiki_Auth_Plugin $auth */ 149560a396c8SGerrit Uitslag global $auth; 149630f6ec4bSGerrit Uitslag /** @var Input $INPUT */ 149730f6ec4bSGerrit Uitslag global $INPUT; 149860a396c8SGerrit Uitslag 149960a396c8SGerrit Uitslag // prepare initial event data 150060a396c8SGerrit Uitslag $data = array( 150160a396c8SGerrit Uitslag 'username' => $username, // the unique user name 150260a396c8SGerrit Uitslag 'name' => '', 150360a396c8SGerrit Uitslag 'link' => array( //setting 'link' to false disables linking 150460a396c8SGerrit Uitslag 'target' => '', 150560a396c8SGerrit Uitslag 'pre' => '', 150660a396c8SGerrit Uitslag 'suf' => '', 150760a396c8SGerrit Uitslag 'style' => '', 150860a396c8SGerrit Uitslag 'more' => '', 150960a396c8SGerrit Uitslag 'url' => '', 151060a396c8SGerrit Uitslag 'title' => '', 151160a396c8SGerrit Uitslag 'class' => '' 151260a396c8SGerrit Uitslag ), 15134d5fc927SGerrit Uitslag 'userlink' => '', // formatted user name as will be returned 151415f3bc49SGerrit Uitslag 'textonly' => $textonly 151560a396c8SGerrit Uitslag ); 151662c8004eSGerrit Uitslag if($username === null) { 151730f6ec4bSGerrit Uitslag $data['username'] = $username = $INPUT->server->str('REMOTE_USER'); 151815f3bc49SGerrit Uitslag if($textonly){ 151915f3bc49SGerrit Uitslag $data['name'] = $INFO['userinfo']['name']. ' (' . $INPUT->server->str('REMOTE_USER') . ')'; 152015f3bc49SGerrit Uitslag }else { 152130f6ec4bSGerrit Uitslag $data['name'] = '<bdi>' . hsc($INFO['userinfo']['name']) . '</bdi> (<bdi>' . hsc($INPUT->server->str('REMOTE_USER')) . '</bdi>)'; 152260a396c8SGerrit Uitslag } 152315f3bc49SGerrit Uitslag } 152460a396c8SGerrit Uitslag 152560a396c8SGerrit Uitslag $evt = new Doku_Event('COMMON_USER_LINK', $data); 152660a396c8SGerrit Uitslag if($evt->advise_before(true)) { 152760a396c8SGerrit Uitslag if(empty($data['name'])) { 152860a396c8SGerrit Uitslag if($conf['showuseras'] == 'loginname') { 152915f3bc49SGerrit Uitslag $data['name'] = $textonly ? $data['username'] : hsc($data['username']); 153060a396c8SGerrit Uitslag } else { 153160a396c8SGerrit Uitslag if($auth) $info = $auth->getUserData($username); 1532dc58b6f4SAndy Webber if(isset($info) && $info) { 1533dc58b6f4SAndy Webber switch($conf['showuseras']) { 1534dc58b6f4SAndy Webber case 'username': 15357f081821SGerrit Uitslag case 'username_link': 153615f3bc49SGerrit Uitslag $data['name'] = $textonly ? $info['name'] : hsc($info['name']); 153760a396c8SGerrit Uitslag break; 1538dc58b6f4SAndy Webber case 'email': 1539dc58b6f4SAndy Webber case 'email_link': 154060a396c8SGerrit Uitslag $data['name'] = obfuscate($info['mail']); 154160a396c8SGerrit Uitslag break; 1542dc58b6f4SAndy Webber } 154360a396c8SGerrit Uitslag } 154460a396c8SGerrit Uitslag } 154560a396c8SGerrit Uitslag } 15467f081821SGerrit Uitslag 15477f081821SGerrit Uitslag /** @var Doku_Renderer_xhtml $xhtml_renderer */ 15487f081821SGerrit Uitslag static $xhtml_renderer = null; 15497f081821SGerrit Uitslag 155015f3bc49SGerrit Uitslag if(!$data['textonly'] && empty($data['link']['url'])) { 15517f081821SGerrit Uitslag 15527f081821SGerrit Uitslag if(in_array($conf['showuseras'], array('email_link', 'username_link'))) { 155360a396c8SGerrit Uitslag if(!isset($info)) { 155460a396c8SGerrit Uitslag if($auth) $info = $auth->getUserData($username); 155560a396c8SGerrit Uitslag } 155660a396c8SGerrit Uitslag if(isset($info) && $info) { 15577f081821SGerrit Uitslag if($conf['showuseras'] == 'email_link') { 155860a396c8SGerrit Uitslag $data['link']['url'] = 'mailto:' . obfuscate($info['mail']); 1559dc58b6f4SAndy Webber } else { 15607f081821SGerrit Uitslag if(is_null($xhtml_renderer)) { 15617f081821SGerrit Uitslag $xhtml_renderer = p_get_renderer('xhtml'); 15627f081821SGerrit Uitslag } 15637f081821SGerrit Uitslag if(empty($xhtml_renderer->interwiki)) { 15647f081821SGerrit Uitslag $xhtml_renderer->interwiki = getInterwiki(); 15657f081821SGerrit Uitslag } 15667f081821SGerrit Uitslag $shortcut = 'user'; 1567533772e1SGerrit Uitslag $exists = null; 15686496c33fSGerrit Uitslag $data['link']['url'] = $xhtml_renderer->_resolveInterWiki($shortcut, $username, $exists); 15692a2a43c4SGerrit Uitslag $data['link']['class'] .= ' interwiki iw_user'; 15706496c33fSGerrit Uitslag if($exists !== null) { 15716496c33fSGerrit Uitslag if($exists) { 15726496c33fSGerrit Uitslag $data['link']['class'] .= ' wikilink1'; 15736496c33fSGerrit Uitslag } else { 15746496c33fSGerrit Uitslag $data['link']['class'] .= ' wikilink2'; 15756496c33fSGerrit Uitslag $data['link']['rel'] = 'nofollow'; 15766496c33fSGerrit Uitslag } 15776496c33fSGerrit Uitslag } 1578dc58b6f4SAndy Webber } 1579dc58b6f4SAndy Webber } else { 158015f3bc49SGerrit Uitslag $data['textonly'] = true; 1581dc58b6f4SAndy Webber } 158260a396c8SGerrit Uitslag 158360a396c8SGerrit Uitslag } else { 158415f3bc49SGerrit Uitslag $data['textonly'] = true; 158560a396c8SGerrit Uitslag } 158660a396c8SGerrit Uitslag } 158760a396c8SGerrit Uitslag 158815f3bc49SGerrit Uitslag if($data['textonly']) { 15894d5fc927SGerrit Uitslag $data['userlink'] = $data['name']; 159060a396c8SGerrit Uitslag } else { 159160a396c8SGerrit Uitslag $data['link']['name'] = $data['name']; 159260a396c8SGerrit Uitslag if(is_null($xhtml_renderer)) { 159360a396c8SGerrit Uitslag $xhtml_renderer = p_get_renderer('xhtml'); 159460a396c8SGerrit Uitslag } 15954d5fc927SGerrit Uitslag $data['userlink'] = $xhtml_renderer->_formatLink($data['link']); 159660a396c8SGerrit Uitslag } 159760a396c8SGerrit Uitslag } 159860a396c8SGerrit Uitslag $evt->advise_after(); 159960a396c8SGerrit Uitslag unset($evt); 160060a396c8SGerrit Uitslag 16014d5fc927SGerrit Uitslag return $data['userlink']; 1602066fee30SAndreas Gohr} 1603066fee30SAndreas Gohr 1604066fee30SAndreas Gohr/** 1605066fee30SAndreas Gohr * Returns the path to a image file for the currently chosen license. 1606066fee30SAndreas Gohr * When no image exists, returns an empty string 1607066fee30SAndreas Gohr * 1608066fee30SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 1609066fee30SAndreas Gohr * @param string $type - type of image 'badge' or 'button' 16103272d797SAndreas Gohr * @return string 1611066fee30SAndreas Gohr */ 1612066fee30SAndreas Gohrfunction license_img($type) { 1613066fee30SAndreas Gohr global $license; 1614066fee30SAndreas Gohr global $conf; 1615066fee30SAndreas Gohr if(!$conf['license']) return ''; 1616066fee30SAndreas Gohr if(!is_array($license[$conf['license']])) return ''; 1617066fee30SAndreas Gohr $lic = $license[$conf['license']]; 1618066fee30SAndreas Gohr $try = array(); 1619066fee30SAndreas Gohr $try[] = 'lib/images/license/'.$type.'/'.$conf['license'].'.png'; 1620066fee30SAndreas Gohr $try[] = 'lib/images/license/'.$type.'/'.$conf['license'].'.gif'; 1621066fee30SAndreas Gohr if(substr($conf['license'], 0, 3) == 'cc-') { 1622066fee30SAndreas Gohr $try[] = 'lib/images/license/'.$type.'/cc.png'; 1623066fee30SAndreas Gohr } 1624066fee30SAndreas Gohr foreach($try as $src) { 1625066fee30SAndreas Gohr if(@file_exists(DOKU_INC.$src)) return $src; 1626066fee30SAndreas Gohr } 1627066fee30SAndreas Gohr return ''; 1628dc58b6f4SAndy Webber} 1629dc58b6f4SAndy Webber 163013c08e2fSMichael Klier/** 163113c08e2fSMichael Klier * Checks if the given amount of memory is available 163213c08e2fSMichael Klier * 163313c08e2fSMichael Klier * If the memory_get_usage() function is not available the 163413c08e2fSMichael Klier * function just assumes $bytes of already allocated memory 163513c08e2fSMichael Klier * 163613c08e2fSMichael Klier * @author Filip Oscadal <webmaster@illusionsoftworks.cz> 163713c08e2fSMichael Klier * @author Andreas Gohr <andi@splitbrain.org> 16383272d797SAndreas Gohr * 16393272d797SAndreas Gohr * @param int $mem Size of memory you want to allocate in bytes 16403272d797SAndreas Gohr * @param int $bytes 16413272d797SAndreas Gohr * @internal param int $used already allocated memory (see above) 16423272d797SAndreas Gohr * @return bool 164313c08e2fSMichael Klier */ 164413c08e2fSMichael Klierfunction is_mem_available($mem, $bytes = 1048576) { 164513c08e2fSMichael Klier $limit = trim(ini_get('memory_limit')); 164613c08e2fSMichael Klier if(empty($limit)) return true; // no limit set! 164713c08e2fSMichael Klier 164813c08e2fSMichael Klier // parse limit to bytes 164913c08e2fSMichael Klier $limit = php_to_byte($limit); 165013c08e2fSMichael Klier 165113c08e2fSMichael Klier // get used memory if possible 165213c08e2fSMichael Klier if(function_exists('memory_get_usage')) { 165313c08e2fSMichael Klier $used = memory_get_usage(); 165449eb6e38SAndreas Gohr } else { 165549eb6e38SAndreas Gohr $used = $bytes; 165613c08e2fSMichael Klier } 165713c08e2fSMichael Klier 165813c08e2fSMichael Klier if($used + $mem > $limit) { 165913c08e2fSMichael Klier return false; 166013c08e2fSMichael Klier } 166113c08e2fSMichael Klier 166213c08e2fSMichael Klier return true; 166313c08e2fSMichael Klier} 166413c08e2fSMichael Klier 1665af2408d5SAndreas Gohr/** 1666af2408d5SAndreas Gohr * Send a HTTP redirect to the browser 1667af2408d5SAndreas Gohr * 1668af2408d5SAndreas Gohr * Works arround Microsoft IIS cookie sending bug. Exits the script. 1669af2408d5SAndreas Gohr * 1670af2408d5SAndreas Gohr * @link http://support.microsoft.com/kb/q176113/ 1671af2408d5SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 1672af2408d5SAndreas Gohr */ 1673af2408d5SAndreas Gohrfunction send_redirect($url) { 1674585bf44eSChristopher Smith /* @var Input $INPUT */ 1675585bf44eSChristopher Smith global $INPUT; 1676585bf44eSChristopher Smith 16770181f021SAndreas Gohr //are there any undisplayed messages? keep them in session for display 16780181f021SAndreas Gohr global $MSG; 16790181f021SAndreas Gohr if(isset($MSG) && count($MSG) && !defined('NOSESSION')) { 16800181f021SAndreas Gohr //reopen session, store data and close session again 16810181f021SAndreas Gohr @session_start(); 16820181f021SAndreas Gohr $_SESSION[DOKU_COOKIE]['msg'] = $MSG; 16830181f021SAndreas Gohr } 16840181f021SAndreas Gohr 1685d4869846SAndreas Gohr // always close the session 1686d4869846SAndreas Gohr session_write_close(); 1687d4869846SAndreas Gohr 1688c10dcb7dSAndreas Gohr // work around IE bug 1689c10dcb7dSAndreas Gohr // http://www.ianhoar.com/2008/11/16/internet-explorer-6-and-redirected-anchor-links/ 16906d2af55dSChristopher Smith @list($url, $hash) = explode('#', $url); 1691c10dcb7dSAndreas Gohr if($hash) { 1692c10dcb7dSAndreas Gohr if(strpos($url, '?')) { 1693c10dcb7dSAndreas Gohr $url = $url.'&#'.$hash; 1694c10dcb7dSAndreas Gohr } else { 1695c10dcb7dSAndreas Gohr $url = $url.'?&#'.$hash; 1696c10dcb7dSAndreas Gohr } 1697c10dcb7dSAndreas Gohr } 1698c10dcb7dSAndreas Gohr 1699af2408d5SAndreas Gohr // check if running on IIS < 6 with CGI-PHP 1700585bf44eSChristopher Smith if($INPUT->server->has('SERVER_SOFTWARE') && $INPUT->server->has('GATEWAY_INTERFACE') && 1701585bf44eSChristopher Smith (strpos($INPUT->server->str('GATEWAY_INTERFACE'), 'CGI') !== false) && 1702585bf44eSChristopher Smith (preg_match('|^Microsoft-IIS/(\d)\.\d$|', trim($INPUT->server->str('SERVER_SOFTWARE')), $matches)) && 17033272d797SAndreas Gohr $matches[1] < 6 17043272d797SAndreas Gohr ) { 1705af2408d5SAndreas Gohr header('Refresh: 0;url='.$url); 1706af2408d5SAndreas Gohr } else { 1707af2408d5SAndreas Gohr header('Location: '.$url); 1708af2408d5SAndreas Gohr } 1709af2408d5SAndreas Gohr exit; 1710af2408d5SAndreas Gohr} 1711af2408d5SAndreas Gohr 17125b75cd1fSAdrian Lang/** 17135b75cd1fSAdrian Lang * Validate a value using a set of valid values 17145b75cd1fSAdrian Lang * 17155b75cd1fSAdrian Lang * This function checks whether a specified value is set and in the array 17165b75cd1fSAdrian Lang * $valid_values. If not, the function returns a default value or, if no 17175b75cd1fSAdrian Lang * default is specified, throws an exception. 17185b75cd1fSAdrian Lang * 17195b75cd1fSAdrian Lang * @param string $param The name of the parameter 17205b75cd1fSAdrian Lang * @param array $valid_values A set of valid values; Optionally a default may 17215b75cd1fSAdrian Lang * be marked by the key “default”. 17225b75cd1fSAdrian Lang * @param array $array The array containing the value (typically $_POST 17235b75cd1fSAdrian Lang * or $_GET) 17245b75cd1fSAdrian Lang * @param string $exc The text of the raised exception 17255b75cd1fSAdrian Lang * 17263272d797SAndreas Gohr * @throws Exception 17273272d797SAndreas Gohr * @return mixed 17285b75cd1fSAdrian Lang * @author Adrian Lang <lang@cosmocode.de> 17295b75cd1fSAdrian Lang */ 17305b75cd1fSAdrian Langfunction valid_input_set($param, $valid_values, $array, $exc = '') { 17315b75cd1fSAdrian Lang if(isset($array[$param]) && in_array($array[$param], $valid_values)) { 17325b75cd1fSAdrian Lang return $array[$param]; 17335b75cd1fSAdrian Lang } elseif(isset($valid_values['default'])) { 17345b75cd1fSAdrian Lang return $valid_values['default']; 17355b75cd1fSAdrian Lang } else { 17365b75cd1fSAdrian Lang throw new Exception($exc); 17375b75cd1fSAdrian Lang } 17385b75cd1fSAdrian Lang} 17395b75cd1fSAdrian Lang 174063703ba5SAndreas Gohr/** 174163703ba5SAndreas Gohr * Read a preference from the DokuWiki cookie 1742646a531aSChristopher Smith * (remembering both keys & values are urlencoded) 174363703ba5SAndreas Gohr */ 1744554a8c9fSAdrian Langfunction get_doku_pref($pref, $default) { 1745646a531aSChristopher Smith $enc_pref = urlencode($pref); 1746646a531aSChristopher Smith if(strpos($_COOKIE['DOKU_PREFS'], $enc_pref) !== false) { 1747554a8c9fSAdrian Lang $parts = explode('#', $_COOKIE['DOKU_PREFS']); 174863703ba5SAndreas Gohr $cnt = count($parts); 174963703ba5SAndreas Gohr for($i = 0; $i < $cnt; $i += 2) { 1750646a531aSChristopher Smith if($parts[$i] == $enc_pref) { 1751646a531aSChristopher Smith return urldecode($parts[$i + 1]); 1752554a8c9fSAdrian Lang } 1753554a8c9fSAdrian Lang } 1754554a8c9fSAdrian Lang } 1755554a8c9fSAdrian Lang return $default; 1756554a8c9fSAdrian Lang} 1757554a8c9fSAdrian Lang 17583c94d07bSAnika Henke/** 17593c94d07bSAnika Henke * Add a preference to the DokuWiki cookie 176036ec377eSChristopher Smith * (remembering $_COOKIE['DOKU_PREFS'] is urlencoded) 17613c94d07bSAnika Henke */ 17623c94d07bSAnika Henkefunction set_doku_pref($pref, $val) { 17633c94d07bSAnika Henke global $conf; 17643c94d07bSAnika Henke $orig = get_doku_pref($pref, false); 17653c94d07bSAnika Henke $cookieVal = ''; 17663c94d07bSAnika Henke 17673c94d07bSAnika Henke if($orig && ($orig != $val)) { 17683c94d07bSAnika Henke $parts = explode('#', $_COOKIE['DOKU_PREFS']); 17693c94d07bSAnika Henke $cnt = count($parts); 177036ec377eSChristopher Smith // urlencode $pref for the comparison 177136ec377eSChristopher Smith $enc_pref = rawurlencode($pref); 17723c94d07bSAnika Henke for($i = 0; $i < $cnt; $i += 2) { 177336ec377eSChristopher Smith if($parts[$i] == $enc_pref) { 177436ec377eSChristopher Smith $parts[$i + 1] = rawurlencode($val); 177550f261f7SMichael Hamann break; 17763c94d07bSAnika Henke } 17773c94d07bSAnika Henke } 17783c94d07bSAnika Henke $cookieVal = implode('#', $parts); 17793c94d07bSAnika Henke } else if (!$orig) { 178036ec377eSChristopher Smith $cookieVal = ($_COOKIE['DOKU_PREFS'] ? $_COOKIE['DOKU_PREFS'].'#' : '').rawurlencode($pref).'#'.rawurlencode($val); 17813c94d07bSAnika Henke } 17823c94d07bSAnika Henke 17833c94d07bSAnika Henke if (!empty($cookieVal)) { 178475e4dd8aSGerrit Uitslag $cookieDir = empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir']; 178575e4dd8aSGerrit Uitslag setcookie('DOKU_PREFS', $cookieVal, time()+365*24*3600, $cookieDir, '', ($conf['securecookie'] && is_ssl())); 17863c94d07bSAnika Henke } 17873c94d07bSAnika Henke} 17883c94d07bSAnika Henke 1789f8fb2d18SAndreas Gohr/** 1790f8fb2d18SAndreas Gohr * Strips source mapping declarations from given text #601 1791f8fb2d18SAndreas Gohr * 1792f8fb2d18SAndreas Gohr * @param &string $text reference to the CSS or JavaScript code to clean 1793f8fb2d18SAndreas Gohr */ 1794f8fb2d18SAndreas Gohrfunction stripsourcemaps(&$text){ 1795f8fb2d18SAndreas Gohr $text = preg_replace('/^(\/\/|\/\*)[@#]\s+sourceMappingURL=.*?(\*\/)?$/im', '\\1\\2', $text); 1796f8fb2d18SAndreas Gohr} 1797f8fb2d18SAndreas Gohr 1798e3776c06SMichael Hamann//Setup VIM: ex: et ts=2 : 1799