xref: /dokuwiki/inc/common.php (revision f3f0262c480d7e509b008d37c90aed884532bba8)
1*f3f0262cSandi<?
2*f3f0262cSandirequire_once("conf/dokuwiki.php");
3*f3f0262cSandirequire_once("inc/io.php");
4*f3f0262cSandi
5*f3f0262cSandi//set up error reporting to sane values
6*f3f0262cSandierror_reporting(E_ALL ^ E_NOTICE);
7*f3f0262cSandi
8*f3f0262cSandi//make session rewrites XHTML compliant
9*f3f0262cSandiini_set('arg_separator.output', '&amp;');
10*f3f0262cSandi
11*f3f0262cSandi//init session
12*f3f0262cSandisession_name("DokuWiki");
13*f3f0262cSandisession_start();
14*f3f0262cSandi
15*f3f0262cSandi//kill magic quotes
16*f3f0262cSandiif (get_magic_quotes_gpc()) {
17*f3f0262cSandi  if (!empty($_GET))    remove_magic_quotes($_GET);
18*f3f0262cSandi  if (!empty($_POST))   remove_magic_quotes($_POST);
19*f3f0262cSandi  if (!empty($_COOKIE)) remove_magic_quotes($_COOKIE);
20*f3f0262cSandi  if (!empty($_REQUEST)) remove_magic_quotes($_REQUEST);
21*f3f0262cSandi  if (!empty($_SESSION)) remove_magic_quotes($_SESSION);
22*f3f0262cSandi  ini_set('magic_quotes_gpc', 0);
23*f3f0262cSandi}
24*f3f0262cSandiset_magic_quotes_runtime(0);
25*f3f0262cSandiini_set('magic_quotes_sybase',0);
26*f3f0262cSandi
27*f3f0262cSandifunction remove_magic_quotes(&$array) {
28*f3f0262cSandi  foreach (array_keys($array) as $key) {
29*f3f0262cSandi    if (is_array($array[$key])) {
30*f3f0262cSandi      remove_magic_quotes($array[$key]);
31*f3f0262cSandi    }else {
32*f3f0262cSandi      $array[$key] = stripslashes($array[$key]);
33*f3f0262cSandi    }
34*f3f0262cSandi  }
35*f3f0262cSandi}
36*f3f0262cSandi
37*f3f0262cSandi//disable gzip if not available
38*f3f0262cSandiif($conf['usegzip'] && !function_exists('gzopen')){
39*f3f0262cSandi  $conf['usegzip'] = 0;
40*f3f0262cSandi}
41*f3f0262cSandi
42*f3f0262cSandi/* ---------------------------------------------------------------------------------- */
43*f3f0262cSandi
44*f3f0262cSandi/**
45*f3f0262cSandi * This returns the full absolute URL to the directory where
46*f3f0262cSandi * DokuWiki is installed in (includes a trailing slash)
47*f3f0262cSandi */
48*f3f0262cSandifunction getBaseURL($abs=false){
49*f3f0262cSandi  global $conf;
50*f3f0262cSandi  //if canonical url enabled always return absolute
51*f3f0262cSandi  if($conf['canonical']) $abs = true;
52*f3f0262cSandi
53*f3f0262cSandi  //relative URLs are easy
54*f3f0262cSandi  if(!$abs){
55*f3f0262cSandi    $dir = dirname($_SERVER['PHP_SELF']).'/';
56*f3f0262cSandi    $dir = preg_replace('#//#','/',$dir);
57*f3f0262cSandi    $dir = preg_replace('#\/$#','/',$dir); #bugfix for weird WIN behaviour
58*f3f0262cSandi    return $dir;
59*f3f0262cSandi  }
60*f3f0262cSandi
61*f3f0262cSandi  $port = ':'.$_SERVER['SERVER_PORT'];
62*f3f0262cSandi  //remove port from hostheader as sent by IE
63*f3f0262cSandi  $host = preg_replace('/:.*$/','',$_SERVER['HTTP_HOST']);
64*f3f0262cSandi
65*f3f0262cSandi  // see if HTTPS is enabled - apache leaves this empty when not available,
66*f3f0262cSandi  // IIS sets it to 'off', 'false' and 'disabled' are just guessing
67*f3f0262cSandi  if (preg_match('/^(|off|false|disabled)$/i',$_SERVER['HTTPS'])){
68*f3f0262cSandi    $proto = 'http://';
69*f3f0262cSandi    if ($_SERVER['SERVER_PORT'] == '80') {
70*f3f0262cSandi      $port='';
71*f3f0262cSandi    }
72*f3f0262cSandi  }else{
73*f3f0262cSandi    $proto = 'https://';
74*f3f0262cSandi    if ($_SERVER['SERVER_PORT'] == '443') {
75*f3f0262cSandi      $port='';
76*f3f0262cSandi    }
77*f3f0262cSandi  }
78*f3f0262cSandi  $dir = (dirname($_SERVER['PHP_SELF'])).'/';
79*f3f0262cSandi  $dir = preg_replace('#//#','/',$dir);
80*f3f0262cSandi  $dir = preg_replace('#\/$#','/',$dir); #bugfix for weird WIN behaviour
81*f3f0262cSandi
82*f3f0262cSandi  return $proto.$host.$port.$dir;
83*f3f0262cSandi}
84*f3f0262cSandi
85*f3f0262cSandi/**
86*f3f0262cSandi * Returns info about the current document as associative
87*f3f0262cSandi * array.
88*f3f0262cSandi */
89*f3f0262cSandifunction pageinfo(){
90*f3f0262cSandi  global $ID;
91*f3f0262cSandi  global $REV;
92*f3f0262cSandi  global $USERINFO;
93*f3f0262cSandi  global $conf;
94*f3f0262cSandi
95*f3f0262cSandi  if($_SERVER['REMOTE_USER']){
96*f3f0262cSandi    $info['user']     = $_SERVER['REMOTE_USER'];
97*f3f0262cSandi    $info['userinfo'] = $USERINFO;
98*f3f0262cSandi    $info['perm']     = auth_quickaclcheck($ID);
99*f3f0262cSandi  }else{
100*f3f0262cSandi    $info['user']     = '';
101*f3f0262cSandi    $info['perm']     = auth_aclcheck($ID,'',null);
102*f3f0262cSandi  }
103*f3f0262cSandi
104*f3f0262cSandi  $info['namespace'] = getNS($ID);
105*f3f0262cSandi  $info['locked']    = checklock($ID);
106*f3f0262cSandi  $info['filepath']  = realpath(wikiFN($ID,$REV));
107*f3f0262cSandi  $info['exists']    = @file_exists($info['filepath']);
108*f3f0262cSandi  if($REV && !$info['exists']){
109*f3f0262cSandi    //check if current revision was meant
110*f3f0262cSandi    $cur = wikiFN($ID);
111*f3f0262cSandi    if(@file_exists($cur) && (@filemtime($cur) == $REV)){
112*f3f0262cSandi      $info['filepath'] = realpath($cur);
113*f3f0262cSandi      $info['exists']   = true;
114*f3f0262cSandi      $REV = '';
115*f3f0262cSandi    }
116*f3f0262cSandi  }
117*f3f0262cSandi  if($info['exists']){
118*f3f0262cSandi    $info['writable'] = (is_writable($info['filepath']) &&
119*f3f0262cSandi                         ($info['perm'] >= AUTH_EDIT));
120*f3f0262cSandi  }else{
121*f3f0262cSandi    $info['writable'] = ($info['perm'] >= AUTH_CREATE);
122*f3f0262cSandi  }
123*f3f0262cSandi  $info['editable']  = ($info['writable'] && empty($info['lock']));
124*f3f0262cSandi  $info['lastmod']   = @filemtime($info['filepath']);
125*f3f0262cSandi
126*f3f0262cSandi  return $info;
127*f3f0262cSandi}
128*f3f0262cSandi
129*f3f0262cSandi/**
130*f3f0262cSandi * adds a message to the global message array
131*f3f0262cSandi *
132*f3f0262cSandi * Levels can be:
133*f3f0262cSandi *
134*f3f0262cSandi * -1 error
135*f3f0262cSandi *  0 info
136*f3f0262cSandi *  1 success
137*f3f0262cSandi */
138*f3f0262cSandifunction msg($message,$lvl=0){
139*f3f0262cSandi  global $MSG;
140*f3f0262cSandi  $errors[-1] = 'error';
141*f3f0262cSandi  $errors[0]  = 'info';
142*f3f0262cSandi  $errors[1]  = 'success';
143*f3f0262cSandi
144*f3f0262cSandi  if(!isset($MSG)) $MSG = array();
145*f3f0262cSandi  $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message);
146*f3f0262cSandi}
147*f3f0262cSandi
148*f3f0262cSandi/**
149*f3f0262cSandi * This builds the breadcrumbstrail and returns it as array
150*f3f0262cSandi */
151*f3f0262cSandifunction breadcrumbs(){
152*f3f0262cSandi  global $ID;
153*f3f0262cSandi  global $ACT;
154*f3f0262cSandi  global $conf;
155*f3f0262cSandi  $crumbs = $_SESSION[$conf['title']]['bc'];
156*f3f0262cSandi
157*f3f0262cSandi  //first visit?
158*f3f0262cSandi  if (!is_array($crumbs)){
159*f3f0262cSandi    $crumbs = array();
160*f3f0262cSandi  }
161*f3f0262cSandi  //we only save on show and existing wiki documents
162*f3f0262cSandi  if($ACT != 'show' || !@file_exists(wikiFN($ID))){
163*f3f0262cSandi    $_SESSION[$conf['title']]['bc'] = $crumbs;
164*f3f0262cSandi    return $crumbs;
165*f3f0262cSandi  }
166*f3f0262cSandi  //remove ID from array
167*f3f0262cSandi  $pos = array_search($ID,$crumbs);
168*f3f0262cSandi  if($pos !== false && $pos !== null){
169*f3f0262cSandi    array_splice($crumbs,$pos,1);
170*f3f0262cSandi  }
171*f3f0262cSandi
172*f3f0262cSandi  //add to array
173*f3f0262cSandi  $crumbs[] =$ID;
174*f3f0262cSandi  //reduce size
175*f3f0262cSandi  while(count($crumbs) > $conf['breadcrumbs']){
176*f3f0262cSandi    array_shift($crumbs);
177*f3f0262cSandi  }
178*f3f0262cSandi  //save to session
179*f3f0262cSandi  $_SESSION[$conf['title']]['bc'] = $crumbs;
180*f3f0262cSandi  return $crumbs;
181*f3f0262cSandi}
182*f3f0262cSandi
183*f3f0262cSandi/**
184*f3f0262cSandi * This is run on a ID before it is outputted somewhere
185*f3f0262cSandi * currently used to replace the colon with something else
186*f3f0262cSandi * on Windows systems and to have proper URL encoding
187*f3f0262cSandi */
188*f3f0262cSandifunction idfilter($id){
189*f3f0262cSandi  global $conf;
190*f3f0262cSandi  if ($conf['useslash'] && $conf['userewrite']){
191*f3f0262cSandi    $id = strtr($id,':','/');
192*f3f0262cSandi  }elseif (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' &&
193*f3f0262cSandi      $conf['userewrite']) {
194*f3f0262cSandi    $id = strtr($id,':',';');
195*f3f0262cSandi  }
196*f3f0262cSandi  $id = urlencode($id);
197*f3f0262cSandi  $id = str_replace('%3A',':',$id); //keep as colon
198*f3f0262cSandi  $id = str_replace('%2F','/',$id); //keep as slash
199*f3f0262cSandi  return $id;
200*f3f0262cSandi}
201*f3f0262cSandi
202*f3f0262cSandi/**
203*f3f0262cSandi * This builds a link to a wikipage (using getBaseURL)
204*f3f0262cSandi */
205*f3f0262cSandifunction wl($id='',$more='',$script='doku.php',$canonical=false){
206*f3f0262cSandi  global $conf;
207*f3f0262cSandi  $more = str_replace(',','&amp;',$more);
208*f3f0262cSandi
209*f3f0262cSandi  $id    = idfilter($id);
210*f3f0262cSandi  $xlink = getBaseURL($canonical);
211*f3f0262cSandi
212*f3f0262cSandi  if(!$conf['userewrite']){
213*f3f0262cSandi    $xlink .= $script;
214*f3f0262cSandi    $xlink .= '?id='.$id;
215*f3f0262cSandi    if($more) $xlink .= '&amp;'.$more;
216*f3f0262cSandi  }else{
217*f3f0262cSandi    $xlink .= $id;
218*f3f0262cSandi    if($more) $xlink .= '?'.$more;
219*f3f0262cSandi  }
220*f3f0262cSandi
221*f3f0262cSandi  return $xlink;
222*f3f0262cSandi}
223*f3f0262cSandi
224*f3f0262cSandi/**
225*f3f0262cSandi * Just builds a link to a script
226*f3f0262cSandi */
227*f3f0262cSandifunction script($script='doku.php'){
228*f3f0262cSandi  $link = getBaseURL();
229*f3f0262cSandi  $link .= $script;
230*f3f0262cSandi  return $link;
231*f3f0262cSandi}
232*f3f0262cSandi
233*f3f0262cSandi/**
234*f3f0262cSandi * Return namespacepart of a wiki ID
235*f3f0262cSandi */
236*f3f0262cSandifunction getNS($id){
237*f3f0262cSandi if(strpos($id,':')!==false){
238*f3f0262cSandi   return substr($id,0,strrpos($id,':'));
239*f3f0262cSandi }
240*f3f0262cSandi return false;
241*f3f0262cSandi}
242*f3f0262cSandi
243*f3f0262cSandi/**
244*f3f0262cSandi * Returns the id without the namespace
245*f3f0262cSandi */
246*f3f0262cSandifunction noNS($id){
247*f3f0262cSandi  return preg_replace('/.*:/','',$id);
248*f3f0262cSandi}
249*f3f0262cSandi
250*f3f0262cSandi/**
251*f3f0262cSandi * Checks the wikitext against a list of blocked expressions
252*f3f0262cSandi * returns true if the text contains any bad words
253*f3f0262cSandi */
254*f3f0262cSandifunction checkwordblock(){
255*f3f0262cSandi  global $TEXT;
256*f3f0262cSandi  global $conf;
257*f3f0262cSandi
258*f3f0262cSandi  if(!$conf['usewordblock']) return false;
259*f3f0262cSandi
260*f3f0262cSandi  $blocks = file('conf/wordblock.conf');
261*f3f0262cSandi  $re = array();
262*f3f0262cSandi  #build regexp from blocks
263*f3f0262cSandi  foreach($blocks as $block){
264*f3f0262cSandi    $block = preg_replace('/#.*$/','',$block);
265*f3f0262cSandi    $block = trim($block);
266*f3f0262cSandi    if(empty($block)) continue;
267*f3f0262cSandi    $re[]  = $block;
268*f3f0262cSandi  }
269*f3f0262cSandi  if(preg_match('#('.join('|',$re).')#si',$TEXT)) return true;
270*f3f0262cSandi  return false;
271*f3f0262cSandi}
272*f3f0262cSandi
273*f3f0262cSandi/**
274*f3f0262cSandi * Returns the IP of the client including X-Forwarded-For
275*f3f0262cSandi * Proxy Headers
276*f3f0262cSandi */
277*f3f0262cSandifunction clientIP(){
278*f3f0262cSandi  $my = $_SERVER['REMOTE_ADDR'];
279*f3f0262cSandi  if($_SERVER['HTTP_X_FORWARDED_FOR']){
280*f3f0262cSandi    $my .= ' ('.$_SERVER['HTTP_X_FORWARDED_FOR'].')';
281*f3f0262cSandi  }
282*f3f0262cSandi  return $my;
283*f3f0262cSandi}
284*f3f0262cSandi
285*f3f0262cSandi/**
286*f3f0262cSandi * Checks if a given page is currently locked by anyone for editing.
287*f3f0262cSandi * removes stale lockfiles
288*f3f0262cSandi */
289*f3f0262cSandifunction checklock($id){
290*f3f0262cSandi  global $conf;
291*f3f0262cSandi  $lock = wikiFN($id).'.lock';
292*f3f0262cSandi
293*f3f0262cSandi  //no lockfile
294*f3f0262cSandi  if(!@file_exists($lock)) return false;
295*f3f0262cSandi
296*f3f0262cSandi  //lockfile expired
297*f3f0262cSandi  if((time() - filemtime($lock)) > $conf['locktime']){
298*f3f0262cSandi    unlink($lock);
299*f3f0262cSandi    return false;
300*f3f0262cSandi  }
301*f3f0262cSandi
302*f3f0262cSandi  //my own lock
303*f3f0262cSandi  $ip = io_readFile($lock);
304*f3f0262cSandi  if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){
305*f3f0262cSandi    return false;
306*f3f0262cSandi  }
307*f3f0262cSandi
308*f3f0262cSandi  return $ip;
309*f3f0262cSandi}
310*f3f0262cSandi
311*f3f0262cSandi/**
312*f3f0262cSandi * Locks a page for editing
313*f3f0262cSandi */
314*f3f0262cSandifunction lock($id){
315*f3f0262cSandi  $lock = wikiFN($id).'.lock';
316*f3f0262cSandi  if($_SERVER['REMOTE_USER']){
317*f3f0262cSandi    io_saveFile($lock,$_SERVER['REMOTE_USER']);
318*f3f0262cSandi  }else{
319*f3f0262cSandi    io_saveFile($lock,clientIP());
320*f3f0262cSandi  }
321*f3f0262cSandi}
322*f3f0262cSandi
323*f3f0262cSandi/**
324*f3f0262cSandi * Unlocks a page if it was locked by the user
325*f3f0262cSandi *
326*f3f0262cSandi * return true if a lock was removed
327*f3f0262cSandi */
328*f3f0262cSandifunction unlock($id){
329*f3f0262cSandi  $lock = wikiFN($id).'.lock';
330*f3f0262cSandi  if(@file_exists($lock)){
331*f3f0262cSandi    $ip = io_readFile($lock);
332*f3f0262cSandi    if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){
333*f3f0262cSandi      @unlink($lock);
334*f3f0262cSandi      return true;
335*f3f0262cSandi    }
336*f3f0262cSandi  }
337*f3f0262cSandi  return false;
338*f3f0262cSandi}
339*f3f0262cSandi
340*f3f0262cSandi/**
341*f3f0262cSandi * Cleans a given ID to only use allowed characters. Accented characters are
342*f3f0262cSandi * converted to unaccented ones
343*f3f0262cSandi */
344*f3f0262cSandifunction cleanID($id){
345*f3f0262cSandi  global $conf;
346*f3f0262cSandi  global $lang;
347*f3f0262cSandi  $id = trim($id);
348*f3f0262cSandi  $id = strtolower($id);
349*f3f0262cSandi
350*f3f0262cSandi  //alternative namespace seperator
351*f3f0262cSandi  $id = strtr($id,';',':');
352*f3f0262cSandi  $id = strtr($id,'/',':');
353*f3f0262cSandi
354*f3f0262cSandi  if(!$conf['localnames']){
355*f3f0262cSandi    if($lang['encoding'] == 'iso-8859-15'){
356*f3f0262cSandi      // replace accented chars with unaccented ones
357*f3f0262cSandi      // this may look strange on your terminal - just don't touch
358*f3f0262cSandi      $id = strtr(
359*f3f0262cSandi      strtr($id,
360*f3f0262cSandi       '������������������������������������������������������',
361*f3f0262cSandi       'szszyaaaaaceeeeiiiinooooouuuyaaaaaceeeeiiiinooooouuuyy'),
362*f3f0262cSandi       array('�' => 'th', '�' => 'th', '�' => 'dh', '�' => 'dh', '�' => 'ss',
363*f3f0262cSandi             '�' => 'oe', '�' => 'oe', '�' => 'ae', '�' => 'ae', '�' => 'u',
364*f3f0262cSandi             '�' => 'ue', '�' => 'oe', '�' => 'ae', '�' => 'ue', '�' => '�',
365*f3f0262cSandi             '�' => 'ae'));
366*f3f0262cSandi    }
367*f3f0262cSandi    $WORD = 'a-z';
368*f3f0262cSandi  }else{
369*f3f0262cSandi    $WORD = '\w';
370*f3f0262cSandi  }
371*f3f0262cSandi
372*f3f0262cSandi  //special chars left will be converted to _
373*f3f0262cSandi  $id = preg_replace('#[^'.$WORD.'0-9:\-\.]#','_',$id);
374*f3f0262cSandi  $id = preg_replace('#__#','_',$id);
375*f3f0262cSandi  $id = preg_replace('#:+#',':',$id);
376*f3f0262cSandi  $id = trim($id,':._-');
377*f3f0262cSandi  $id = preg_replace('#:[:\._\-]+#',':',$id);
378*f3f0262cSandi
379*f3f0262cSandi  return($id);
380*f3f0262cSandi}
381*f3f0262cSandi
382*f3f0262cSandi/**
383*f3f0262cSandi * returns the full path to the datafile specified by ID and
384*f3f0262cSandi * optional revision
385*f3f0262cSandi */
386*f3f0262cSandifunction wikiFN($id,$rev=''){
387*f3f0262cSandi  global $conf;
388*f3f0262cSandi  $id = cleanID($id);
389*f3f0262cSandi  $id = str_replace(':','/',$id);
390*f3f0262cSandi  if(empty($rev)){
391*f3f0262cSandi    return $conf['datadir'].'/'.$id.'.txt';
392*f3f0262cSandi  }else{
393*f3f0262cSandi    $fn = $conf['olddir'].'/'.$id.'.'.$rev.'.txt';
394*f3f0262cSandi    if(!$conf['usegzip'] || @file_exists($fn)){
395*f3f0262cSandi      //return plaintext if exists or gzip is disabled
396*f3f0262cSandi      return $fn;
397*f3f0262cSandi    }else{
398*f3f0262cSandi      return $fn.'.gz';
399*f3f0262cSandi    }
400*f3f0262cSandi  }
401*f3f0262cSandi}
402*f3f0262cSandi
403*f3f0262cSandi/**
404*f3f0262cSandi * Returns the full filepath to a localized textfile if local
405*f3f0262cSandi * version isn't found the english one is returned
406*f3f0262cSandi */
407*f3f0262cSandifunction localeFN($id){
408*f3f0262cSandi  global $conf;
409*f3f0262cSandi  $file = './lang/'.$conf['lang'].'/'.$id.'.txt';
410*f3f0262cSandi  if(!@file_exists($file)){
411*f3f0262cSandi    //fall back to english
412*f3f0262cSandi    $file = './lang/en/'.$id.'.txt';
413*f3f0262cSandi  }
414*f3f0262cSandi  return cleanText($file);
415*f3f0262cSandi}
416*f3f0262cSandi
417*f3f0262cSandi/**
418*f3f0262cSandi * convert line ending to unix format
419*f3f0262cSandi *
420*f3f0262cSandi * @see: formText() for 2crlf conversion
421*f3f0262cSandi */
422*f3f0262cSandifunction cleanText($text){
423*f3f0262cSandi  $text = preg_replace("/(\015\012)|(\015)/","\012",$text);
424*f3f0262cSandi  return $text;
425*f3f0262cSandi}
426*f3f0262cSandi
427*f3f0262cSandi/**
428*f3f0262cSandi * Prepares text for print in Webforms by encoding special chars.
429*f3f0262cSandi * It also converts line endings to Windows format which is
430*f3f0262cSandi * pseudo standard for webforms.
431*f3f0262cSandi *
432*f3f0262cSandi * @see: cleanText() for 2unix conversion
433*f3f0262cSandi */
434*f3f0262cSandifunction formText($text){
435*f3f0262cSandi  $text = preg_replace("/\012/","\015\012",$text);
436*f3f0262cSandi  return htmlspecialchars($text);
437*f3f0262cSandi}
438*f3f0262cSandi
439*f3f0262cSandi/**
440*f3f0262cSandi * Returns the specified textfile in parsed format
441*f3f0262cSandi */
442*f3f0262cSandifunction parsedLocale($id){
443*f3f0262cSandi  //disable section editing
444*f3f0262cSandi  global $parser;
445*f3f0262cSandi  $se = $parser['secedit'];
446*f3f0262cSandi  $parser['secedit'] = false;
447*f3f0262cSandi  //fetch parsed locale
448*f3f0262cSandi  $html = io_cacheParse(localeFN($id));
449*f3f0262cSandi  //reset section editing
450*f3f0262cSandi  $parser['secedit'] = $se;
451*f3f0262cSandi  return $html;
452*f3f0262cSandi}
453*f3f0262cSandi
454*f3f0262cSandi/**
455*f3f0262cSandi * Returns the specified textfile in parsed format
456*f3f0262cSandi */
457*f3f0262cSandifunction rawLocale($id){
458*f3f0262cSandi  return io_readFile(localeFN($id));
459*f3f0262cSandi}
460*f3f0262cSandi
461*f3f0262cSandi
462*f3f0262cSandi/**
463*f3f0262cSandi * Returns the parsed Wikitext for the given id and revision. If $excuse
464*f3f0262cSandi * is true an explanation is returned if the file wasn't found
465*f3f0262cSandi */
466*f3f0262cSandifunction parsedWiki($id,$rev='',$excuse=true){
467*f3f0262cSandi  $file = wikiFN($id,$rev);
468*f3f0262cSandi  $ret  = '';
469*f3f0262cSandi
470*f3f0262cSandi  //ensure $id is in global $ID (needed for parsing)
471*f3f0262cSandi  global $ID;
472*f3f0262cSandi  $ID = $id;
473*f3f0262cSandi
474*f3f0262cSandi  if($rev){
475*f3f0262cSandi    if(@file_exists($file)){
476*f3f0262cSandi      $ret = parse(io_readFile($file));
477*f3f0262cSandi    }elseif($excuse){
478*f3f0262cSandi      $ret = parsedLocale('norev');
479*f3f0262cSandi    }
480*f3f0262cSandi  }else{
481*f3f0262cSandi    if(@file_exists($file)){
482*f3f0262cSandi      $ret = io_cacheParse($file);
483*f3f0262cSandi    }elseif($excuse){
484*f3f0262cSandi      $ret = parsedLocale('newpage');
485*f3f0262cSandi    }
486*f3f0262cSandi  }
487*f3f0262cSandi  return $ret;
488*f3f0262cSandi}
489*f3f0262cSandi
490*f3f0262cSandi/**
491*f3f0262cSandi * Returns the raw WikiText
492*f3f0262cSandi */
493*f3f0262cSandifunction rawWiki($id,$rev=''){
494*f3f0262cSandi  return io_readFile(wikiFN($id,$rev));
495*f3f0262cSandi}
496*f3f0262cSandi
497*f3f0262cSandi/**
498*f3f0262cSandi * Returns the raw Wiki Text in three slices. The range parameter
499*f3f0262cSandi * Need to have the form "from-to" and gives the range of the section.
500*f3f0262cSandi * The returned order is prefix, section and suffix.
501*f3f0262cSandi */
502*f3f0262cSandifunction rawWikiSlices($range,$id,$rev=''){
503*f3f0262cSandi  list($from,$to) = split('-',$range,2);
504*f3f0262cSandi  $text = io_readFile(wikiFN($id,$rev));
505*f3f0262cSandi  $text = split("\n",$text);
506*f3f0262cSandi  if(!$from) $from = 0;
507*f3f0262cSandi  if(!$to)   $to   = count($text);
508*f3f0262cSandi
509*f3f0262cSandi  $slices[0] = join("\n",array_slice($text,0,$from));
510*f3f0262cSandi  $slices[1] = join("\n",array_slice($text,$from,$to + 1  - $from));
511*f3f0262cSandi  $slices[2] = join("\n",array_slice($text,$to+1));
512*f3f0262cSandi
513*f3f0262cSandi  return $slices;
514*f3f0262cSandi}
515*f3f0262cSandi
516*f3f0262cSandi/**
517*f3f0262cSandi * function to join the text slices with correct lineendings again.
518*f3f0262cSandi * When the pretty parameter is set to true it adds additional empty
519*f3f0262cSandi * lines between sections if needed (used on saving).
520*f3f0262cSandi */
521*f3f0262cSandifunction con($pre,$text,$suf,$pretty=false){
522*f3f0262cSandi
523*f3f0262cSandi  if($pretty){
524*f3f0262cSandi    if($pre && substr($pre,-1) != "\n") $pre .= "\n";
525*f3f0262cSandi    if($suf && substr($text,-1) != "\n") $text .= "\n";
526*f3f0262cSandi  }
527*f3f0262cSandi
528*f3f0262cSandi  if($pre) $pre .= "\n";
529*f3f0262cSandi  if($suf) $text .= "\n";
530*f3f0262cSandi  return $pre.$text.$suf;
531*f3f0262cSandi}
532*f3f0262cSandi
533*f3f0262cSandi/**
534*f3f0262cSandi * little function to print the content of a var
535*f3f0262cSandi */
536*f3f0262cSandifunction dbg($msg,$hidden=false){
537*f3f0262cSandi  (!$hidden) ? print '<pre class="dbg">' : print "<!--\n";
538*f3f0262cSandi  print_r($msg);
539*f3f0262cSandi  (!$hidden) ? print '</pre>' : print "\n-->";
540*f3f0262cSandi}
541*f3f0262cSandi
542*f3f0262cSandi/**
543*f3f0262cSandi * Add's an entry to the changelog
544*f3f0262cSandi */
545*f3f0262cSandifunction addLogEntry($id,$summary=""){
546*f3f0262cSandi  global $conf;
547*f3f0262cSandi  $id     = cleanID($id);
548*f3f0262cSandi  $date   = time();
549*f3f0262cSandi  $remote = $_SERVER['REMOTE_ADDR'];
550*f3f0262cSandi  $user   = $_SERVER['REMOTE_USER'];
551*f3f0262cSandi
552*f3f0262cSandi  $logline = join("\t",array($date,$remote,$id,$user,$summary))."\n";
553*f3f0262cSandi
554*f3f0262cSandi  $fh = fopen($conf['changelog'],'a');
555*f3f0262cSandi  if($fh){
556*f3f0262cSandi    fwrite($fh,$logline);
557*f3f0262cSandi    fclose($fh);
558*f3f0262cSandi  }
559*f3f0262cSandi}
560*f3f0262cSandi
561*f3f0262cSandi/**
562*f3f0262cSandi * returns an array of recently changed files using the
563*f3f0262cSandi * changelog
564*f3f0262cSandi */
565*f3f0262cSandifunction getRecents($num=0,$incdel=false){
566*f3f0262cSandi  global $conf;
567*f3f0262cSandi  $recent = array();
568*f3f0262cSandi  if(!$num) $num = $conf['recent'];
569*f3f0262cSandi
570*f3f0262cSandi  $loglines = file($conf['changelog']);
571*f3f0262cSandi  rsort($loglines); //reverse sort on timestamp
572*f3f0262cSandi
573*f3f0262cSandi  foreach ($loglines as $line){
574*f3f0262cSandi    $line = rtrim($line);        //remove newline
575*f3f0262cSandi    if(empty($line)) continue;   //skip empty lines
576*f3f0262cSandi    $info = split("\t",$line);   //split into parts
577*f3f0262cSandi    //add id if not in yet and file still exists and is allowed to read
578*f3f0262cSandi    if(!$recent[$info[2]] &&
579*f3f0262cSandi       (@file_exists(wikiFN($info[2])) || $incdel) &&
580*f3f0262cSandi       (auth_quickaclcheck($info[2]) >= AUTH_READ)
581*f3f0262cSandi      ){
582*f3f0262cSandi      $recent[$info[2]]['date'] = $info[0];
583*f3f0262cSandi      $recent[$info[2]]['ip']   = $info[1];
584*f3f0262cSandi      $recent[$info[2]]['user'] = $info[3];
585*f3f0262cSandi      $recent[$info[2]]['sum']  = $info[4];
586*f3f0262cSandi      $recent[$info[2]]['del']  = !@file_exists(wikiFN($info[2]));
587*f3f0262cSandi    }
588*f3f0262cSandi    if(count($recent) >= $num){
589*f3f0262cSandi      break; //finish if enough items found
590*f3f0262cSandi    }
591*f3f0262cSandi  }
592*f3f0262cSandi  return $recent;
593*f3f0262cSandi}
594*f3f0262cSandi
595*f3f0262cSandi/**
596*f3f0262cSandi * Saves a wikitext by calling io_saveFile
597*f3f0262cSandi */
598*f3f0262cSandifunction saveWikiText($id,$text,$summary){
599*f3f0262cSandi  global $conf;
600*f3f0262cSandi  global $lang;
601*f3f0262cSandi  umask($conf['umask']);
602*f3f0262cSandi  // ignore if no changes were made
603*f3f0262cSandi  if($text == rawWiki($id,'')){
604*f3f0262cSandi    return;
605*f3f0262cSandi  }
606*f3f0262cSandi
607*f3f0262cSandi  $file = wikiFN($id);
608*f3f0262cSandi  $old  = saveOldRevision($id);
609*f3f0262cSandi
610*f3f0262cSandi  if (empty($text)){
611*f3f0262cSandi    // remove empty files
612*f3f0262cSandi    @unlink($file);
613*f3f0262cSandi    $del = true;
614*f3f0262cSandi    $summary = $lang['deleted']; //autoset summary on deletion
615*f3f0262cSandi  }else{
616*f3f0262cSandi    // save file (datadir is created in io_saveFile)
617*f3f0262cSandi    io_saveFile($file,$text);
618*f3f0262cSandi    $del = false;
619*f3f0262cSandi  }
620*f3f0262cSandi
621*f3f0262cSandi  addLogEntry($id,$summary);
622*f3f0262cSandi  notify($id,$old,$summary);
623*f3f0262cSandi
624*f3f0262cSandi  //purge cache on add by updating the purgefile
625*f3f0262cSandi  if($conf['purgeonadd'] && (!$old || $del)){
626*f3f0262cSandi    io_saveFile($conf['datadir'].'/.cache/purgefile',time());
627*f3f0262cSandi  }
628*f3f0262cSandi}
629*f3f0262cSandi
630*f3f0262cSandi/**
631*f3f0262cSandi * moves the current version to the attic and returns its
632*f3f0262cSandi * revision date
633*f3f0262cSandi */
634*f3f0262cSandifunction saveOldRevision($id){
635*f3f0262cSandi	global $conf;
636*f3f0262cSandi  umask($conf['umask']);
637*f3f0262cSandi  $oldf = wikiFN($id);
638*f3f0262cSandi  if(!@file_exists($oldf)) return '';
639*f3f0262cSandi  $date = filemtime($oldf);
640*f3f0262cSandi  $newf = wikiFN($id,$date);
641*f3f0262cSandi  if(substr($newf,-3)=='.gz'){
642*f3f0262cSandi    io_saveFile($newf,rawWiki($id));
643*f3f0262cSandi  }else{
644*f3f0262cSandi    io_makeFileDir($newf);
645*f3f0262cSandi    copy($oldf, $newf);
646*f3f0262cSandi  }
647*f3f0262cSandi  return $date;
648*f3f0262cSandi}
649*f3f0262cSandi
650*f3f0262cSandi/**
651*f3f0262cSandi * Sends a notify mail to the wikiadmin when a page was
652*f3f0262cSandi * changed
653*f3f0262cSandi */
654*f3f0262cSandifunction notify($id,$rev="",$summary=""){
655*f3f0262cSandi  global $lang;
656*f3f0262cSandi  global $conf;
657*f3f0262cSandi  $hdrs ='';
658*f3f0262cSandi  if(empty($conf['notify'])) return; //notify enabled?
659*f3f0262cSandi
660*f3f0262cSandi  $text = rawLocale('mailtext');
661*f3f0262cSandi  $text = str_replace('@DATE@',date($conf['dformat']),$text);
662*f3f0262cSandi  $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text);
663*f3f0262cSandi  $text = str_replace('@IPADDRESS@',$_SERVER['REMOTE_ADDR'],$text);
664*f3f0262cSandi  $text = str_replace('@HOSTNAME@',gethostbyaddr($_SERVER['REMOTE_ADDR']),$text);
665*f3f0262cSandi  $text = str_replace('@NEWPAGE@',wl($id,'','',true),$text);
666*f3f0262cSandi  $text = str_replace('@DOKUWIKIURL@',getBaseURL(true),$text);
667*f3f0262cSandi  $text = str_replace('@SUMMARY@',$summary,$text);
668*f3f0262cSandi
669*f3f0262cSandi  if($rev){
670*f3f0262cSandi    $subject = $lang['mail_changed'].' '.$id;
671*f3f0262cSandi    $text = str_replace('@OLDPAGE@',wl($id,"rev=$rev",'',true),$text);
672*f3f0262cSandi    require_once("inc/DifferenceEngine.php");
673*f3f0262cSandi    $df  = new Diff(split("\n",rawWiki($id,$rev)),
674*f3f0262cSandi                    split("\n",rawWiki($id)));
675*f3f0262cSandi    $dformat = new UnifiedDiffFormatter();
676*f3f0262cSandi    $diff    = $dformat->format($df);
677*f3f0262cSandi  }else{
678*f3f0262cSandi    $subject=$lang['mail_newpage'].' '.$id;
679*f3f0262cSandi    $text = str_replace('@OLDPAGE@','none',$text);
680*f3f0262cSandi    $diff = rawWiki($id);
681*f3f0262cSandi  }
682*f3f0262cSandi  $text = str_replace('@DIFF@',$diff,$text);
683*f3f0262cSandi
684*f3f0262cSandi  if (!empty($conf['mailfrom'])) {
685*f3f0262cSandi    $hdrs = 'From: '.$conf['mailfrom']."\n";
686*f3f0262cSandi  }
687*f3f0262cSandi  @mail($conf['notify'],$subject,$text,$hdrs);
688*f3f0262cSandi}
689*f3f0262cSandi
690*f3f0262cSandifunction getRevisions($id){
691*f3f0262cSandi  $revd = dirname(wikiFN($id,'foo'));
692*f3f0262cSandi  $revs = array();
693*f3f0262cSandi  $clid = cleanID($id);
694*f3f0262cSandi  if(strrpos($clid,':')) $clid = substr($clid,strrpos($clid,':')+1); //remove path
695*f3f0262cSandi
696*f3f0262cSandi  if (is_dir($revd) && $dh = opendir($revd)) {
697*f3f0262cSandi    while (($file = readdir($dh)) !== false) {
698*f3f0262cSandi      if (is_dir($revd.'/'.$file)) continue;
699*f3f0262cSandi      if (preg_match('/^'.$clid.'\.(\d+)\.txt(\.gz)?$/',$file,$match)){
700*f3f0262cSandi        $revs[]=$match[1];
701*f3f0262cSandi      }
702*f3f0262cSandi    }
703*f3f0262cSandi    closedir($dh);
704*f3f0262cSandi  }
705*f3f0262cSandi  rsort($revs);
706*f3f0262cSandi  return $revs;
707*f3f0262cSandi}
708*f3f0262cSandi
709*f3f0262cSandi/**
710*f3f0262cSandi * downloads a file from the net and saves it to the given location
711*f3f0262cSandi */
712*f3f0262cSandifunction download($url,$file){
713*f3f0262cSandi  $fp = @fopen($url,"rb");
714*f3f0262cSandi  if(!$fp) return false;
715*f3f0262cSandi
716*f3f0262cSandi  while(!feof($fp)){
717*f3f0262cSandi    $cont.= fread($fp,1024);
718*f3f0262cSandi  }
719*f3f0262cSandi  fclose($fp);
720*f3f0262cSandi
721*f3f0262cSandi  $fp2 = @fopen($file,"w");
722*f3f0262cSandi  if(!$fp2) return false;
723*f3f0262cSandi  fwrite($fp2,$cont);
724*f3f0262cSandi  fclose($fp2);
725*f3f0262cSandi  return true;
726*f3f0262cSandi}
727*f3f0262cSandi
728*f3f0262cSandi/**
729*f3f0262cSandi * extracts the query from a google referer
730*f3f0262cSandi */
731*f3f0262cSandifunction getGoogleQuery(){
732*f3f0262cSandi  $url = parse_url($_SERVER['HTTP_REFERER']);
733*f3f0262cSandi
734*f3f0262cSandi  if(!preg_match("#google\.#i",$url['host'])) return '';
735*f3f0262cSandi  $query = array();
736*f3f0262cSandi  parse_str($url['query'],$query);
737*f3f0262cSandi
738*f3f0262cSandi  return $query['q'];
739*f3f0262cSandi}
740*f3f0262cSandi
741*f3f0262cSandi/**
742*f3f0262cSandi * This function tries the locales given in the
743*f3f0262cSandi * language file
744*f3f0262cSandi */
745*f3f0262cSandifunction setCorrectLocale(){
746*f3f0262cSandi  global $conf;
747*f3f0262cSandi  global $lang;
748*f3f0262cSandi
749*f3f0262cSandi  $enc = strtoupper($lang['encoding']);
750*f3f0262cSandi  foreach ($lang['locales'] as $loc){
751*f3f0262cSandi    //try locale
752*f3f0262cSandi    if(@setlocale(LC_ALL,$loc)) return;
753*f3f0262cSandi    //try loceale with encoding
754*f3f0262cSandi    if(@setlocale(LC_ALL,"$loc.$enc")) return;
755*f3f0262cSandi  }
756*f3f0262cSandi  //still here? try to set from environment
757*f3f0262cSandi  @setlocale(LC_ALL,"");
758*f3f0262cSandi}
759*f3f0262cSandi
760*f3f0262cSandi/**
761*f3f0262cSandi* Return the human readable size of a file
762*f3f0262cSandi*
763*f3f0262cSandi* @param       int    $size   A file size
764*f3f0262cSandi* @param       int    $dec    A number of decimal places
765*f3f0262cSandi* @author      Martin Benjamin <b.martin@cybernet.ch>
766*f3f0262cSandi* @author      Aidan Lister <aidan@php.net>
767*f3f0262cSandi* @version     1.0.0
768*f3f0262cSandi*/
769*f3f0262cSandifunction filesize_h($size, $dec = 1)
770*f3f0262cSandi{
771*f3f0262cSandi  $sizes = array('B', 'KB', 'MB', 'GB');
772*f3f0262cSandi  $count = count($sizes);
773*f3f0262cSandi  $i = 0;
774*f3f0262cSandi
775*f3f0262cSandi  while ($size >= 1024 && ($i < $count - 1)) {
776*f3f0262cSandi    $size /= 1024;
777*f3f0262cSandi    $i++;
778*f3f0262cSandi  }
779*f3f0262cSandi
780*f3f0262cSandi  return round($size, $dec) . ' ' . $sizes[$i];
781*f3f0262cSandi}
782*f3f0262cSandi
783*f3f0262cSandifunction check(){
784*f3f0262cSandi  global $conf;
785*f3f0262cSandi  global $INFO;
786*f3f0262cSandi
787*f3f0262cSandi  if(is_writable($conf['changelog'])){
788*f3f0262cSandi    msg('Changelog is writable',1);
789*f3f0262cSandi  }else{
790*f3f0262cSandi    msg('Changelog is not writable',-1);
791*f3f0262cSandi  }
792*f3f0262cSandi
793*f3f0262cSandi  if(is_writable($conf['datadir'])){
794*f3f0262cSandi    msg('Datadir is writable',1);
795*f3f0262cSandi  }else{
796*f3f0262cSandi    msg('Datadir is not writable',-1);
797*f3f0262cSandi  }
798*f3f0262cSandi
799*f3f0262cSandi  if(is_writable($conf['olddir'])){
800*f3f0262cSandi    msg('Attic is writable',1);
801*f3f0262cSandi  }else{
802*f3f0262cSandi    msg('Attic is not writable',-1);
803*f3f0262cSandi  }
804*f3f0262cSandi
805*f3f0262cSandi  if(is_writable($conf['mediadir'])){
806*f3f0262cSandi    msg('Mediadir is writable',1);
807*f3f0262cSandi  }else{
808*f3f0262cSandi    msg('Mediadir is not writable',-1);
809*f3f0262cSandi  }
810*f3f0262cSandi
811*f3f0262cSandi  if(is_writable('conf/users.auth')){
812*f3f0262cSandi    msg('conf/users.auth is writable',1);
813*f3f0262cSandi  }else{
814*f3f0262cSandi    msg('conf/users.auth is not writable',0);
815*f3f0262cSandi  }
816*f3f0262cSandi
817*f3f0262cSandi  msg('Your current permission for this page is '.$INFO['perm'],0);
818*f3f0262cSandi
819*f3f0262cSandi  if(is_writable($INFO['filepath'])){
820*f3f0262cSandi    msg('The current page is writable by the webserver',0);
821*f3f0262cSandi  }else{
822*f3f0262cSandi    msg('The current page is not writable by the webserver',0);
823*f3f0262cSandi  }
824*f3f0262cSandi
825*f3f0262cSandi  if($INFO['writable']){
826*f3f0262cSandi    msg('The current page is writable by you',0);
827*f3f0262cSandi  }else{
828*f3f0262cSandi    msg('The current page is not writable you',0);
829*f3f0262cSandi  }
830*f3f0262cSandi}
831*f3f0262cSandi?>
832