xref: /dokuwiki/inc/common.php (revision 63cb5853ff174b45e697ea0818816060805503aa)
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
9ed7b5f09Sandi  if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
10e7cb32dcSAndreas Gohr  require_once(DOKU_CONF.'dokuwiki.php');
11ed7b5f09Sandi  require_once(DOKU_INC.'inc/io.php');
12ed7b5f09Sandi  require_once(DOKU_INC.'inc/utf8.php');
13ed7b5f09Sandi  require_once(DOKU_INC.'inc/mail.php');
14c112d578Sandi  require_once(DOKU_INC.'inc/parserutils.php');
15f3f0262cSandi
16f3f0262cSandi/**
17b6912aeaSAndreas Gohr * These constants are used with the recents function
18b6912aeaSAndreas Gohr */
19b6912aeaSAndreas Gohrdefine('RECENTS_SKIP_DELETED',2);
20b6912aeaSAndreas Gohrdefine('RECENTS_SKIP_MINORS',4);
21b6912aeaSAndreas Gohrdefine('RECENTS_SKIP_SUBSPACES',8);
22b6912aeaSAndreas Gohr
23b6912aeaSAndreas Gohr/**
24d5197206Schris * Wrapper around htmlspecialchars()
25d5197206Schris *
26d5197206Schris * @author Andreas Gohr <andi@splitbrain.org>
27d5197206Schris * @see    htmlspecialchars()
28d5197206Schris */
29d5197206Schrisfunction hsc($string){
30d5197206Schris  return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
31d5197206Schris}
32d5197206Schris
33d5197206Schris/**
34d5197206Schris * print a newline terminated string
35d5197206Schris *
36d5197206Schris * You can give an indention as optional parameter
37d5197206Schris *
38d5197206Schris * @author Andreas Gohr <andi@splitbrain.org>
39d5197206Schris */
40d5197206Schrisfunction ptln($string,$intend=0){
41d5197206Schris  for($i=0; $i<$intend; $i++) print ' ';
42d5197206Schris  print"$string\n";
43d5197206Schris}
44d5197206Schris
45d5197206Schris/**
4615fae107Sandi * Return info about the current document as associative
47f3f0262cSandi * array.
4815fae107Sandi *
4915fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
50f3f0262cSandi */
51f3f0262cSandifunction pageinfo(){
52f3f0262cSandi  global $ID;
53f3f0262cSandi  global $REV;
54f3f0262cSandi  global $USERINFO;
55f3f0262cSandi  global $conf;
56f3f0262cSandi
57f3f0262cSandi  if($_SERVER['REMOTE_USER']){
58f3f0262cSandi    $info['userinfo']   = $USERINFO;
59f3f0262cSandi    $info['perm']       = auth_quickaclcheck($ID);
601380fc45SAndreas Gohr    $info['subscribed'] = is_subscribed($ID,$_SERVER['REMOTE_USER']);
61ee4c4a1bSAndreas Gohr    $info['client']     = $_SERVER['REMOTE_USER'];
6217ee7f66SAndreas Gohr
6317ee7f66SAndreas Gohr    // if some outside auth were used only REMOTE_USER is set
6417ee7f66SAndreas Gohr    if(!$info['userinfo']['name']){
6517ee7f66SAndreas Gohr      $info['userinfo']['name'] = $_SERVER['REMOTE_USER'];
6617ee7f66SAndreas Gohr    }
67ee4c4a1bSAndreas Gohr
68f3f0262cSandi  }else{
69f3f0262cSandi    $info['perm']       = auth_aclcheck($ID,'',null);
701380fc45SAndreas Gohr    $info['subscribed'] = false;
71ee4c4a1bSAndreas Gohr    $info['client']     = clientIP(true);
72f3f0262cSandi  }
73f3f0262cSandi
74f3f0262cSandi  $info['namespace'] = getNS($ID);
75f3f0262cSandi  $info['locked']    = checklock($ID);
76f3f0262cSandi  $info['filepath']  = realpath(wikiFN($ID,$REV));
77f3f0262cSandi  $info['exists']    = @file_exists($info['filepath']);
78f3f0262cSandi  if($REV && !$info['exists']){
79f3f0262cSandi    //check if current revision was meant
80f3f0262cSandi    $cur = wikiFN($ID);
81f3f0262cSandi    if(@file_exists($cur) && (@filemtime($cur) == $REV)){
82f3f0262cSandi      $info['filepath'] = realpath($cur);
83f3f0262cSandi      $info['exists']   = true;
84f3f0262cSandi      $REV = '';
85f3f0262cSandi    }
86f3f0262cSandi  }
87c112d578Sandi  $info['rev'] = $REV;
88f3f0262cSandi  if($info['exists']){
89f3f0262cSandi    $info['writable'] = (is_writable($info['filepath']) &&
90f3f0262cSandi                         ($info['perm'] >= AUTH_EDIT));
91f3f0262cSandi  }else{
92f3f0262cSandi    $info['writable'] = ($info['perm'] >= AUTH_CREATE);
93f3f0262cSandi  }
94f3f0262cSandi  $info['editable']  = ($info['writable'] && empty($info['lock']));
95f3f0262cSandi  $info['lastmod']   = @filemtime($info['filepath']);
96f3f0262cSandi
97652610a2Sandi  //who's the editor
98652610a2Sandi  if($REV){
99fb53bfe2SBen Coburn    $revinfo = getRevisionInfo($ID,$REV,false);
100652610a2Sandi  }else{
101fb53bfe2SBen Coburn    $revinfo = getRevisionInfo($ID,$info['lastmod'],false);
102652610a2Sandi  }
103652610a2Sandi  $info['ip']     = $revinfo['ip'];
104652610a2Sandi  $info['user']   = $revinfo['user'];
105652610a2Sandi  $info['sum']    = $revinfo['sum'];
106b6912aeaSAndreas Gohr  $info['minor']  = $revinfo['minor'];
10759f257aeSchris
10888f522e9Sandi  if($revinfo['user']){
10988f522e9Sandi    $info['editor'] = $revinfo['user'];
11088f522e9Sandi  }else{
11188f522e9Sandi    $info['editor'] = $revinfo['ip'];
11288f522e9Sandi  }
113652610a2Sandi
114ee4c4a1bSAndreas Gohr  // draft
115ee4c4a1bSAndreas Gohr  $draft = getCacheName($info['client'].$ID,'.draft');
116ee4c4a1bSAndreas Gohr  if(@file_exists($draft)){
117ee4c4a1bSAndreas Gohr    if(@filemtime($draft) < @filemtime(wikiFN($ID))){
118ee4c4a1bSAndreas Gohr      // remove stale draft
119ee4c4a1bSAndreas Gohr      @unlink($draft);
120ee4c4a1bSAndreas Gohr    }else{
121ee4c4a1bSAndreas Gohr      $info['draft'] = $draft;
122ee4c4a1bSAndreas Gohr    }
123ee4c4a1bSAndreas Gohr  }
124ee4c4a1bSAndreas Gohr
125f3f0262cSandi  return $info;
126f3f0262cSandi}
127f3f0262cSandi
128f3f0262cSandi/**
1292684e50aSAndreas Gohr * Build an string of URL parameters
1302684e50aSAndreas Gohr *
1312684e50aSAndreas Gohr * @author Andreas Gohr
1322684e50aSAndreas Gohr */
133b174aeaeSchrisfunction buildURLparams($params, $sep='&amp;'){
1342684e50aSAndreas Gohr  $url = '';
1352684e50aSAndreas Gohr  $amp = false;
1362684e50aSAndreas Gohr  foreach($params as $key => $val){
137b174aeaeSchris    if($amp) $url .= $sep;
1382684e50aSAndreas Gohr
1392684e50aSAndreas Gohr    $url .= $key.'=';
140b6c6979fSAndreas Gohr    $url .= rawurlencode($val);
1412684e50aSAndreas Gohr    $amp = true;
1422684e50aSAndreas Gohr  }
1432684e50aSAndreas Gohr  return $url;
1442684e50aSAndreas Gohr}
1452684e50aSAndreas Gohr
1462684e50aSAndreas Gohr/**
1472684e50aSAndreas Gohr * Build an string of html tag attributes
1482684e50aSAndreas Gohr *
1492684e50aSAndreas Gohr * @author Andreas Gohr
1502684e50aSAndreas Gohr */
1512684e50aSAndreas Gohrfunction buildAttributes($params){
1522684e50aSAndreas Gohr  $url = '';
1532684e50aSAndreas Gohr  foreach($params as $key => $val){
1542684e50aSAndreas Gohr    $url .= $key.'="';
1552684e50aSAndreas Gohr    $url .= htmlspecialchars ($val);
1562684e50aSAndreas Gohr    $url .= '" ';
1572684e50aSAndreas Gohr  }
1582684e50aSAndreas Gohr  return $url;
1592684e50aSAndreas Gohr}
1602684e50aSAndreas Gohr
1612684e50aSAndreas Gohr
1622684e50aSAndreas Gohr/**
1630396becbSandi * print a message
1640396becbSandi *
1650396becbSandi * If HTTP headers were not sent yet the message is added
1660396becbSandi * to the global message array else it's printed directly
1670396becbSandi * using html_msgarea()
1680396becbSandi *
169f3f0262cSandi *
170f3f0262cSandi * Levels can be:
171f3f0262cSandi *
172f3f0262cSandi * -1 error
173f3f0262cSandi *  0 info
174f3f0262cSandi *  1 success
17515fae107Sandi *
17615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
1770396becbSandi * @see    html_msgarea
178f3f0262cSandi */
1790d58d74eSAndreas Gohrfunction msg($message,$lvl=0,$line='',$file=''){
180f3f0262cSandi  global $MSG;
181f3f0262cSandi  $errors[-1] = 'error';
182f3f0262cSandi  $errors[0]  = 'info';
183f3f0262cSandi  $errors[1]  = 'success';
184f3f0262cSandi
1850d58d74eSAndreas Gohr  if($line || $file) $message.=' ['.basename($file).':'.$line.']';
1860d58d74eSAndreas Gohr
187cc20ad51Sandi  if(!headers_sent()){
188f3f0262cSandi    if(!isset($MSG)) $MSG = array();
189f3f0262cSandi    $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message);
1900396becbSandi  }else{
1910396becbSandi    $MSG = array();
1920396becbSandi    $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message);
193f62ea8a1Sandi    if(function_exists('html_msgarea')){
1940396becbSandi      html_msgarea();
195f62ea8a1Sandi    }else{
196f62ea8a1Sandi      print "ERROR($lvl) $message";
197f62ea8a1Sandi    }
1980396becbSandi  }
199f3f0262cSandi}
200f3f0262cSandi
201f3f0262cSandi/**
20215fae107Sandi * This builds the breadcrumb trail and returns it as array
20315fae107Sandi *
20415fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
205f3f0262cSandi */
206f3f0262cSandifunction breadcrumbs(){
2078746e727Sandi  // we prepare the breadcrumbs early for quick session closing
2088746e727Sandi  static $crumbs = null;
2098746e727Sandi  if($crumbs != null) return $crumbs;
2108746e727Sandi
211f3f0262cSandi  global $ID;
212f3f0262cSandi  global $ACT;
213f3f0262cSandi  global $conf;
214f3f0262cSandi  $crumbs = $_SESSION[$conf['title']]['bc'];
215f3f0262cSandi
216f3f0262cSandi  //first visit?
217f3f0262cSandi  if (!is_array($crumbs)){
218f3f0262cSandi    $crumbs = array();
219f3f0262cSandi  }
220f3f0262cSandi  //we only save on show and existing wiki documents
221a77f5846Sjan  $file = wikiFN($ID);
222a77f5846Sjan  if($ACT != 'show' || !@file_exists($file)){
223f3f0262cSandi    $_SESSION[$conf['title']]['bc'] = $crumbs;
224f3f0262cSandi    return $crumbs;
225f3f0262cSandi  }
226a77f5846Sjan
227a77f5846Sjan  // page names
228a77f5846Sjan  $name = noNS($ID);
229a77f5846Sjan  if ($conf['useheading']) {
230a77f5846Sjan    // get page title
231bb0a59d4Sjan    $title = p_get_first_heading($ID);
232a77f5846Sjan    if ($title) {
233a77f5846Sjan      $name = $title;
234a77f5846Sjan    }
235a77f5846Sjan  }
236a77f5846Sjan
237f3f0262cSandi  //remove ID from array
238a77f5846Sjan  if (isset($crumbs[$ID])) {
239a77f5846Sjan    unset($crumbs[$ID]);
240f3f0262cSandi  }
241f3f0262cSandi
242f3f0262cSandi  //add to array
243a77f5846Sjan  $crumbs[$ID] = $name;
244f3f0262cSandi  //reduce size
245f3f0262cSandi  while(count($crumbs) > $conf['breadcrumbs']){
246f3f0262cSandi    array_shift($crumbs);
247f3f0262cSandi  }
248f3f0262cSandi  //save to session
249f3f0262cSandi  $_SESSION[$conf['title']]['bc'] = $crumbs;
250f3f0262cSandi  return $crumbs;
251f3f0262cSandi}
252f3f0262cSandi
253f3f0262cSandi/**
25415fae107Sandi * Filter for page IDs
25515fae107Sandi *
256f3f0262cSandi * This is run on a ID before it is outputted somewhere
257f3f0262cSandi * currently used to replace the colon with something else
258f3f0262cSandi * on Windows systems and to have proper URL encoding
25915fae107Sandi *
26049c713a3Sandi * Urlencoding is ommitted when the second parameter is false
26149c713a3Sandi *
26215fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
263f3f0262cSandi */
26449c713a3Sandifunction idfilter($id,$ue=true){
265f3f0262cSandi  global $conf;
266f3f0262cSandi  if ($conf['useslash'] && $conf['userewrite']){
267f3f0262cSandi    $id = strtr($id,':','/');
268f3f0262cSandi  }elseif (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' &&
269f3f0262cSandi      $conf['userewrite']) {
270f3f0262cSandi    $id = strtr($id,':',';');
271f3f0262cSandi  }
27249c713a3Sandi  if($ue){
273b6c6979fSAndreas Gohr    $id = rawurlencode($id);
274f3f0262cSandi    $id = str_replace('%3A',':',$id); //keep as colon
275f3f0262cSandi    $id = str_replace('%2F','/',$id); //keep as slash
27649c713a3Sandi  }
277f3f0262cSandi  return $id;
278f3f0262cSandi}
279f3f0262cSandi
280f3f0262cSandi/**
281ed7b5f09Sandi * This builds a link to a wikipage
28215fae107Sandi *
2836c7843b5Sandi * It handles URL rewriting and adds additional parameter if
2846c7843b5Sandi * given in $more
2856c7843b5Sandi *
28615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
287f3f0262cSandi */
288b174aeaeSchrisfunction wl($id='',$more='',$abs=false,$sep='&amp;'){
289f3f0262cSandi  global $conf;
2906de3759aSAndreas Gohr  if(is_array($more)){
291b174aeaeSchris    $more = buildURLparams($more,$sep);
2926de3759aSAndreas Gohr  }else{
293b174aeaeSchris    $more = str_replace(',',$sep,$more);
2946de3759aSAndreas Gohr  }
295f3f0262cSandi
296f3f0262cSandi  $id    = idfilter($id);
297ed7b5f09Sandi  if($abs){
298ed7b5f09Sandi    $xlink = DOKU_URL;
299ed7b5f09Sandi  }else{
300ed7b5f09Sandi    $xlink = DOKU_BASE;
301ed7b5f09Sandi  }
302f3f0262cSandi
3036c7843b5Sandi  if($conf['userewrite'] == 2){
3046c7843b5Sandi    $xlink .= DOKU_SCRIPT.'/'.$id;
3056c7843b5Sandi    if($more) $xlink .= '?'.$more;
3066c7843b5Sandi  }elseif($conf['userewrite']){
307f3f0262cSandi    $xlink .= $id;
308f3f0262cSandi    if($more) $xlink .= '?'.$more;
3096c7843b5Sandi  }else{
3106c7843b5Sandi    $xlink .= DOKU_SCRIPT.'?id='.$id;
311b174aeaeSchris    if($more) $xlink .= $sep.$more;
312f3f0262cSandi  }
313f3f0262cSandi
314f3f0262cSandi  return $xlink;
315f3f0262cSandi}
316f3f0262cSandi
317f3f0262cSandi/**
318f5c2808fSBen Coburn * This builds a link to an alternate page format
319f5c2808fSBen Coburn *
320f5c2808fSBen Coburn * Handles URL rewriting if enabled. Follows the style of wl().
321f5c2808fSBen Coburn *
322f5c2808fSBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
323f5c2808fSBen Coburn */
324f5c2808fSBen Coburnfunction exportlink($id='',$format='raw',$more='',$abs=false,$sep='&amp;'){
325f5c2808fSBen Coburn  global $conf;
326f5c2808fSBen Coburn  if(is_array($more)){
327f5c2808fSBen Coburn    $more = buildURLparams($more,$sep);
328f5c2808fSBen Coburn  }else{
329f5c2808fSBen Coburn    $more = str_replace(',',$sep,$more);
330f5c2808fSBen Coburn  }
331f5c2808fSBen Coburn
332f5c2808fSBen Coburn  $format = rawurlencode($format);
333f5c2808fSBen Coburn  $id = idfilter($id);
334f5c2808fSBen Coburn  if($abs){
335f5c2808fSBen Coburn    $xlink = DOKU_URL;
336f5c2808fSBen Coburn  }else{
337f5c2808fSBen Coburn    $xlink = DOKU_BASE;
338f5c2808fSBen Coburn  }
339f5c2808fSBen Coburn
340f5c2808fSBen Coburn  if($conf['userewrite'] == 2){
341f5c2808fSBen Coburn    $xlink .= DOKU_SCRIPT.'/'.$id.'?do=export_'.$format;
342f5c2808fSBen Coburn    if($more) $xlink .= $sep.$more;
343f5c2808fSBen Coburn  }elseif($conf['userewrite'] == 1){
344f5c2808fSBen Coburn    $xlink .= '_export/'.$format.'/'.$id;
345f5c2808fSBen Coburn    if($more) $xlink .= '?'.$more;
346f5c2808fSBen Coburn  }else{
347f5c2808fSBen Coburn    $xlink .= DOKU_SCRIPT.'?do=export_'.$format.$sep.'id='.$id;
348f5c2808fSBen Coburn    if($more) $xlink .= $sep.$more;
349f5c2808fSBen Coburn  }
350f5c2808fSBen Coburn
351f5c2808fSBen Coburn  return $xlink;
352f5c2808fSBen Coburn}
353f5c2808fSBen Coburn
354f5c2808fSBen Coburn/**
3556de3759aSAndreas Gohr * Build a link to a media file
3566de3759aSAndreas Gohr *
3576de3759aSAndreas Gohr * Will return a link to the detail page if $direct is false
3586de3759aSAndreas Gohr */
359b174aeaeSchrisfunction ml($id='',$more='',$direct=true,$sep='&amp;'){
3606de3759aSAndreas Gohr  global $conf;
3616de3759aSAndreas Gohr  if(is_array($more)){
362b174aeaeSchris    $more = buildURLparams($more,$sep);
3636de3759aSAndreas Gohr  }else{
364b174aeaeSchris    $more = str_replace(',',$sep,$more);
3656de3759aSAndreas Gohr  }
3666de3759aSAndreas Gohr
3676de3759aSAndreas Gohr  $xlink = DOKU_BASE;
3686de3759aSAndreas Gohr
3696de3759aSAndreas Gohr  // external URLs are always direct without rewriting
3706de3759aSAndreas Gohr  if(preg_match('#^(https?|ftp)://#i',$id)){
3716de3759aSAndreas Gohr    $xlink .= 'lib/exe/fetch.php';
3726de3759aSAndreas Gohr    if($more){
3736de3759aSAndreas Gohr      $xlink .= '?'.$more;
374b174aeaeSchris      $xlink .= $sep.'media='.rawurlencode($id);
3756de3759aSAndreas Gohr    }else{
376b6c6979fSAndreas Gohr      $xlink .= '?media='.rawurlencode($id);
3776de3759aSAndreas Gohr    }
3786de3759aSAndreas Gohr    return $xlink;
3796de3759aSAndreas Gohr  }
3806de3759aSAndreas Gohr
3816de3759aSAndreas Gohr  $id = idfilter($id);
3826de3759aSAndreas Gohr
3836de3759aSAndreas Gohr  // decide on scriptname
3846de3759aSAndreas Gohr  if($direct){
3856de3759aSAndreas Gohr    if($conf['userewrite'] == 1){
3866de3759aSAndreas Gohr      $script = '_media';
3876de3759aSAndreas Gohr    }else{
3886de3759aSAndreas Gohr      $script = 'lib/exe/fetch.php';
3896de3759aSAndreas Gohr    }
3906de3759aSAndreas Gohr  }else{
3916de3759aSAndreas Gohr    if($conf['userewrite'] == 1){
3926de3759aSAndreas Gohr      $script = '_detail';
3936de3759aSAndreas Gohr    }else{
3946de3759aSAndreas Gohr      $script = 'lib/exe/detail.php';
3956de3759aSAndreas Gohr    }
3966de3759aSAndreas Gohr  }
3976de3759aSAndreas Gohr
3986de3759aSAndreas Gohr  // build URL based on rewrite mode
3996de3759aSAndreas Gohr   if($conf['userewrite']){
4006de3759aSAndreas Gohr     $xlink .= $script.'/'.$id;
4016de3759aSAndreas Gohr     if($more) $xlink .= '?'.$more;
4026de3759aSAndreas Gohr   }else{
4036de3759aSAndreas Gohr     if($more){
404a99d3236SEsther Brunner       $xlink .= $script.'?'.$more;
405b174aeaeSchris       $xlink .= $sep.'media='.$id;
4066de3759aSAndreas Gohr     }else{
407a99d3236SEsther Brunner       $xlink .= $script.'?media='.$id;
4086de3759aSAndreas Gohr     }
4096de3759aSAndreas Gohr   }
4106de3759aSAndreas Gohr
4116de3759aSAndreas Gohr  return $xlink;
4126de3759aSAndreas Gohr}
4136de3759aSAndreas Gohr
4146de3759aSAndreas Gohr
4156de3759aSAndreas Gohr
4166de3759aSAndreas Gohr/**
417f3f0262cSandi * Just builds a link to a script
41815fae107Sandi *
419ed7b5f09Sandi * @todo   maybe obsolete
42015fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
421f3f0262cSandi */
422f3f0262cSandifunction script($script='doku.php'){
423ed7b5f09Sandi#  $link = getBaseURL();
424ed7b5f09Sandi#  $link .= $script;
425ed7b5f09Sandi#  return $link;
426ed7b5f09Sandi  return DOKU_BASE.DOKU_SCRIPT;
427f3f0262cSandi}
428f3f0262cSandi
429f3f0262cSandi/**
43015fae107Sandi * Spamcheck against wordlist
43115fae107Sandi *
432f3f0262cSandi * Checks the wikitext against a list of blocked expressions
433f3f0262cSandi * returns true if the text contains any bad words
43415fae107Sandi *
43515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
436f3f0262cSandi */
437f3f0262cSandifunction checkwordblock(){
438f3f0262cSandi  global $TEXT;
439f3f0262cSandi  global $conf;
440f3f0262cSandi
441f3f0262cSandi  if(!$conf['usewordblock']) return false;
442f3f0262cSandi
443b9ac8716Schris  $wordblocks = getWordblocks();
4443e2965d7Sandi  //how many lines to read at once (to work around some PCRE limits)
4453e2965d7Sandi  if(version_compare(phpversion(),'4.3.0','<')){
4463e2965d7Sandi    //old versions of PCRE define a maximum of parenthesises even if no
4473e2965d7Sandi    //backreferences are used - the maximum is 99
4483e2965d7Sandi    //this is very bad performancewise and may even be too high still
4493e2965d7Sandi    $chunksize = 40;
4503e2965d7Sandi  }else{
451703f6fdeSandi    //read file in chunks of 600 - this should work around the
4523e2965d7Sandi    //MAX_PATTERN_SIZE in modern PCRE
453444b87a5SAndreas Gohr    $chunksize = 400;
4543e2965d7Sandi  }
455b9ac8716Schris  while($blocks = array_splice($wordblocks,0,$chunksize)){
456f3f0262cSandi    $re = array();
457f3f0262cSandi    #build regexp from blocks
458f3f0262cSandi    foreach($blocks as $block){
459f3f0262cSandi      $block = preg_replace('/#.*$/','',$block);
460f3f0262cSandi      $block = trim($block);
461f3f0262cSandi      if(empty($block)) continue;
462f3f0262cSandi      $re[]  = $block;
463f3f0262cSandi    }
464b9ac8716Schris    if(preg_match('#('.join('|',$re).')#si',$TEXT, $match=array())) {
465b9ac8716Schris      return true;
466b9ac8716Schris    }
467703f6fdeSandi  }
468f3f0262cSandi  return false;
469f3f0262cSandi}
470f3f0262cSandi
471f3f0262cSandi/**
47215fae107Sandi * Return the IP of the client
47315fae107Sandi *
4746d8affe6SAndreas Gohr * Honours X-Forwarded-For and X-Real-IP Proxy Headers
47515fae107Sandi *
4766d8affe6SAndreas Gohr * It returns a comma separated list of IPs if the above mentioned
4776d8affe6SAndreas Gohr * headers are set. If the single parameter is set, it tries to return
4786d8affe6SAndreas Gohr * a routable public address, prefering the ones suplied in the X
4796d8affe6SAndreas Gohr * headers
4806d8affe6SAndreas Gohr *
4816d8affe6SAndreas Gohr * @param  boolean $single If set only a single IP is returned
48215fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
483f3f0262cSandi */
4846d8affe6SAndreas Gohrfunction clientIP($single=false){
4856d8affe6SAndreas Gohr  $ip = array();
4866d8affe6SAndreas Gohr  $ip[] = $_SERVER['REMOTE_ADDR'];
4876d8affe6SAndreas Gohr  if($_SERVER['HTTP_X_FORWARDED_FOR'])
4886d8affe6SAndreas Gohr    $ip = array_merge($ip,explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']));
4896d8affe6SAndreas Gohr  if($_SERVER['HTTP_X_REAL_IP'])
4906d8affe6SAndreas Gohr    $ip = array_merge($ip,explode(',',$_SERVER['HTTP_X_REAL_IP']));
4916d8affe6SAndreas Gohr
4926d8affe6SAndreas Gohr  // remove any non-IP stuff
4936d8affe6SAndreas Gohr  $cnt = count($ip);
4946d8affe6SAndreas Gohr  for($i=0; $i<$cnt; $i++){
4956d8affe6SAndreas Gohr    $ip[$i] = preg_replace('/[^0-9\.]+/','',$ip[$i]);
4966d8affe6SAndreas Gohr    if(!preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/',$ip[$i])) $ip[$i] = '';
4976d8affe6SAndreas Gohr    if(empty($ip[$i])) unset($ip[$i]);
498f3f0262cSandi  }
4996d8affe6SAndreas Gohr  $ip = array_values(array_unique($ip));
5006d8affe6SAndreas Gohr  if(!$ip[0]) $ip[0] = '0.0.0.0'; // for some strange reason we don't have a IP
5016d8affe6SAndreas Gohr
5026d8affe6SAndreas Gohr  if(!$single) return join(',',$ip);
5036d8affe6SAndreas Gohr
5046d8affe6SAndreas Gohr  // decide which IP to use, trying to avoid local addresses
5056d8affe6SAndreas Gohr  $ip = array_reverse($ip);
5066d8affe6SAndreas Gohr  foreach($ip as $i){
5076d8affe6SAndreas Gohr    if(preg_match('/^(127\.|10\.|192\.168\.|172\.((1[6-9])|(2[0-9])|(3[0-1]))\.)/',$i)){
5086d8affe6SAndreas Gohr      continue;
5096d8affe6SAndreas Gohr    }else{
5106d8affe6SAndreas Gohr      return $i;
5116d8affe6SAndreas Gohr    }
5126d8affe6SAndreas Gohr  }
5136d8affe6SAndreas Gohr  // still here? just use the first (last) address
5146d8affe6SAndreas Gohr  return $ip[0];
515f3f0262cSandi}
516f3f0262cSandi
517f3f0262cSandi/**
51815fae107Sandi * Checks if a given page is currently locked.
51915fae107Sandi *
520f3f0262cSandi * removes stale lockfiles
52115fae107Sandi *
52215fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
523f3f0262cSandi */
524f3f0262cSandifunction checklock($id){
525f3f0262cSandi  global $conf;
526f3f0262cSandi  $lock = wikiFN($id).'.lock';
527f3f0262cSandi
528f3f0262cSandi  //no lockfile
529f3f0262cSandi  if(!@file_exists($lock)) return false;
530f3f0262cSandi
531f3f0262cSandi  //lockfile expired
532f3f0262cSandi  if((time() - filemtime($lock)) > $conf['locktime']){
533f3f0262cSandi    unlink($lock);
534f3f0262cSandi    return false;
535f3f0262cSandi  }
536f3f0262cSandi
537f3f0262cSandi  //my own lock
538f3f0262cSandi  $ip = io_readFile($lock);
539f3f0262cSandi  if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){
540f3f0262cSandi    return false;
541f3f0262cSandi  }
542f3f0262cSandi
543f3f0262cSandi  return $ip;
544f3f0262cSandi}
545f3f0262cSandi
546f3f0262cSandi/**
54715fae107Sandi * Lock a page for editing
54815fae107Sandi *
54915fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
550f3f0262cSandi */
551f3f0262cSandifunction lock($id){
552f3f0262cSandi  $lock = wikiFN($id).'.lock';
553f3f0262cSandi  if($_SERVER['REMOTE_USER']){
554f3f0262cSandi    io_saveFile($lock,$_SERVER['REMOTE_USER']);
555f3f0262cSandi  }else{
556f3f0262cSandi    io_saveFile($lock,clientIP());
557f3f0262cSandi  }
558f3f0262cSandi}
559f3f0262cSandi
560f3f0262cSandi/**
56115fae107Sandi * Unlock a page if it was locked by the user
562f3f0262cSandi *
56315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
56415fae107Sandi * @return bool true if a lock was removed
565f3f0262cSandi */
566f3f0262cSandifunction unlock($id){
567f3f0262cSandi  $lock = wikiFN($id).'.lock';
568f3f0262cSandi  if(@file_exists($lock)){
569f3f0262cSandi    $ip = io_readFile($lock);
570f3f0262cSandi    if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){
571f3f0262cSandi      @unlink($lock);
572f3f0262cSandi      return true;
573f3f0262cSandi    }
574f3f0262cSandi  }
575f3f0262cSandi  return false;
576f3f0262cSandi}
577f3f0262cSandi
578f3f0262cSandi/**
579f3f0262cSandi * convert line ending to unix format
580f3f0262cSandi *
58115fae107Sandi * @see    formText() for 2crlf conversion
58215fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
583f3f0262cSandi */
584f3f0262cSandifunction cleanText($text){
585f3f0262cSandi  $text = preg_replace("/(\015\012)|(\015)/","\012",$text);
586f3f0262cSandi  return $text;
587f3f0262cSandi}
588f3f0262cSandi
589f3f0262cSandi/**
590f3f0262cSandi * Prepares text for print in Webforms by encoding special chars.
591f3f0262cSandi * It also converts line endings to Windows format which is
592f3f0262cSandi * pseudo standard for webforms.
593f3f0262cSandi *
59415fae107Sandi * @see    cleanText() for 2unix conversion
59515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
596f3f0262cSandi */
597f3f0262cSandifunction formText($text){
598f3f0262cSandi  $text = preg_replace("/\012/","\015\012",$text);
599f3f0262cSandi  return htmlspecialchars($text);
600f3f0262cSandi}
601f3f0262cSandi
602f3f0262cSandi/**
60315fae107Sandi * Returns the specified local text in raw format
60415fae107Sandi *
60515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
606f3f0262cSandi */
607f3f0262cSandifunction rawLocale($id){
608f3f0262cSandi  return io_readFile(localeFN($id));
609f3f0262cSandi}
610f3f0262cSandi
611f3f0262cSandi/**
612f3f0262cSandi * Returns the raw WikiText
61315fae107Sandi *
61415fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
615f3f0262cSandi */
616f3f0262cSandifunction rawWiki($id,$rev=''){
617f3f0262cSandi  return io_readFile(wikiFN($id,$rev));
618f3f0262cSandi}
619f3f0262cSandi
620f3f0262cSandi/**
6217146cee2SAndreas Gohr * Returns the pagetemplate contents for the ID's namespace
6227146cee2SAndreas Gohr *
6237146cee2SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
6247146cee2SAndreas Gohr */
6257146cee2SAndreas Gohrfunction pageTemplate($id){
626a15ce62dSEsther Brunner  global $conf;
627a15ce62dSEsther Brunner  global $INFO;
628a15ce62dSEsther Brunner  $tpl = io_readFile(dirname(wikiFN($id)).'/_template.txt');
629a15ce62dSEsther Brunner  $tpl = str_replace('@ID@',$id,$tpl);
630a15ce62dSEsther Brunner  $tpl = str_replace('@NS@',getNS($id),$tpl);
631a15ce62dSEsther Brunner  $tpl = str_replace('@PAGE@',strtr(noNS($id),'_',' '),$tpl);
632a15ce62dSEsther Brunner  $tpl = str_replace('@USER@',$_SERVER['REMOTE_USER'],$tpl);
633a15ce62dSEsther Brunner  $tpl = str_replace('@NAME@',$INFO['userinfo']['name'],$tpl);
634a15ce62dSEsther Brunner  $tpl = str_replace('@MAIL@',$INFO['userinfo']['mail'],$tpl);
635a15ce62dSEsther Brunner  $tpl = str_replace('@DATE@',date($conf['dformat']),$tpl);
636a15ce62dSEsther Brunner  return $tpl;
6377146cee2SAndreas Gohr}
6387146cee2SAndreas Gohr
6397146cee2SAndreas Gohr
6407146cee2SAndreas Gohr/**
64115fae107Sandi * Returns the raw Wiki Text in three slices.
64215fae107Sandi *
64315fae107Sandi * The range parameter needs to have the form "from-to"
64415cfe303Sandi * and gives the range of the section in bytes - no
64515cfe303Sandi * UTF-8 awareness is needed.
646f3f0262cSandi * The returned order is prefix, section and suffix.
64715fae107Sandi *
64815fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
649f3f0262cSandi */
650f3f0262cSandifunction rawWikiSlices($range,$id,$rev=''){
651f3f0262cSandi  list($from,$to) = split('-',$range,2);
652f3f0262cSandi  $text = io_readFile(wikiFN($id,$rev));
653f3f0262cSandi  if(!$from) $from = 0;
654c3d8e19bSandi  if(!$to)   $to   = strlen($text)+1;
655f3f0262cSandi
65615cfe303Sandi  $slices[0] = substr($text,0,$from-1);
65715cfe303Sandi  $slices[1] = substr($text,$from-1,$to-$from);
65815cfe303Sandi  $slices[2] = substr($text,$to);
659f3f0262cSandi
660f3f0262cSandi  return $slices;
661f3f0262cSandi}
662f3f0262cSandi
663f3f0262cSandi/**
66415fae107Sandi * Joins wiki text slices
66515fae107Sandi *
666f3f0262cSandi * function to join the text slices with correct lineendings again.
667f3f0262cSandi * When the pretty parameter is set to true it adds additional empty
668f3f0262cSandi * lines between sections if needed (used on saving).
66915fae107Sandi *
67015fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
671f3f0262cSandi */
672f3f0262cSandifunction con($pre,$text,$suf,$pretty=false){
673f3f0262cSandi
674f3f0262cSandi  if($pretty){
675f3f0262cSandi    if($pre && substr($pre,-1) != "\n") $pre .= "\n";
676f3f0262cSandi    if($suf && substr($text,-1) != "\n") $text .= "\n";
677f3f0262cSandi  }
678f3f0262cSandi
679f3f0262cSandi  if($pre) $pre .= "\n";
680f3f0262cSandi  if($suf) $text .= "\n";
681f3f0262cSandi  return $pre.$text.$suf;
682f3f0262cSandi}
683f3f0262cSandi
684f3f0262cSandi/**
68515fae107Sandi * print debug messages
68615fae107Sandi *
687f3f0262cSandi * little function to print the content of a var
68815fae107Sandi *
68915fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
690f3f0262cSandi */
691f3f0262cSandifunction dbg($msg,$hidden=false){
692f3f0262cSandi  (!$hidden) ? print '<pre class="dbg">' : print "<!--\n";
693f3f0262cSandi  print_r($msg);
694f3f0262cSandi  (!$hidden) ? print '</pre>' : print "\n-->";
695f3f0262cSandi}
696f3f0262cSandi
697f3f0262cSandi/**
698*63cb5853SAndreas Gohr * Print info to a log file
699*63cb5853SAndreas Gohr *
700*63cb5853SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
701*63cb5853SAndreas Gohr */
702*63cb5853SAndreas Gohrfunction dbglog($msg){
703*63cb5853SAndreas Gohr  global $conf;
704*63cb5853SAndreas Gohr  $file = $conf['cachedir'].'/debug.log';
705*63cb5853SAndreas Gohr  $fh = fopen($file,'a');
706*63cb5853SAndreas Gohr  if($fh){
707*63cb5853SAndreas Gohr    fwrite($fh,date('H:i:s ').$_SERVER['REMOTE_ADDR'].': '.$msg."\n");
708*63cb5853SAndreas Gohr    fclose($fh);
709*63cb5853SAndreas Gohr  }
710*63cb5853SAndreas Gohr}
711*63cb5853SAndreas Gohr
712*63cb5853SAndreas Gohr/**
713f3f0262cSandi * Add's an entry to the changelog
71415fae107Sandi *
71515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
716f3f0262cSandi */
717b6912aeaSAndreas Gohrfunction addLogEntry($date,$id,$summary='',$minor=false){
718f3f0262cSandi  global $conf;
719c1049928Sandi
720c1049928Sandi  if(!@is_writable($conf['changelog'])){
721c1049928Sandi    msg($conf['changelog'].' is not writable!',-1);
722c1049928Sandi    return;
723c1049928Sandi  }
724c1049928Sandi
725652610a2Sandi  if(!$date) $date = time(); //use current time if none supplied
726f3f0262cSandi  $remote = $_SERVER['REMOTE_ADDR'];
727f3f0262cSandi  $user   = $_SERVER['REMOTE_USER'];
728f3f0262cSandi
729b6912aeaSAndreas Gohr  if($conf['useacl'] && $user && $minor){
730b6912aeaSAndreas Gohr    $summary = '*'.$summary;
731b6912aeaSAndreas Gohr  }else{
732b6912aeaSAndreas Gohr    $summary = ' '.$summary;
733b6912aeaSAndreas Gohr  }
734b6912aeaSAndreas Gohr
735f3f0262cSandi  $logline = join("\t",array($date,$remote,$id,$user,$summary))."\n";
736dbb00abcSEsther Brunner  io_saveFile($conf['changelog'],$logline,true);
737f3f0262cSandi}
738f3f0262cSandi
739f3f0262cSandi/**
740b6912aeaSAndreas Gohr * Checks an summary entry if it was a minor edit
741b6912aeaSAndreas Gohr *
742b6912aeaSAndreas Gohr * The summary is cleaned of the marker char
743b6912aeaSAndreas Gohr *
744b6912aeaSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
745b6912aeaSAndreas Gohr */
746b6912aeaSAndreas Gohrfunction isMinor(&$summary){
747b6912aeaSAndreas Gohr  if(substr($summary,0,1) == '*'){
748b6912aeaSAndreas Gohr    $summary = substr($summary,1);
749b6912aeaSAndreas Gohr    return true;
750b6912aeaSAndreas Gohr  }
751b6912aeaSAndreas Gohr  $summary = trim($summary);
752b6912aeaSAndreas Gohr  return false;
753b6912aeaSAndreas Gohr}
754b6912aeaSAndreas Gohr
755b6912aeaSAndreas Gohr/**
756d437bcc4SAndreas Gohr * Internal function used by getRecents
757d437bcc4SAndreas Gohr *
758d437bcc4SAndreas Gohr * don't call directly
759d437bcc4SAndreas Gohr *
760d437bcc4SAndreas Gohr * @see getRecents()
761d437bcc4SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
762d437bcc4SAndreas Gohr */
763b6912aeaSAndreas Gohrfunction _handleRecent($line,$ns,$flags){
764d437bcc4SAndreas Gohr  static $seen  = array();         //caches seen pages and skip them
765d437bcc4SAndreas Gohr  if(empty($line)) return false;   //skip empty lines
766d437bcc4SAndreas Gohr
767d437bcc4SAndreas Gohr  // split the line into parts
768d437bcc4SAndreas Gohr  list($dt,$ip,$id,$usr,$sum) = explode("\t",$line);
769d437bcc4SAndreas Gohr
770d437bcc4SAndreas Gohr  // skip seen ones
771d437bcc4SAndreas Gohr  if($seen[$id]) return false;
772b6912aeaSAndreas Gohr  $recent = array();
773b6912aeaSAndreas Gohr
774b6912aeaSAndreas Gohr  // check minors
775b6912aeaSAndreas Gohr  if(isMinor($sum)){
776b6912aeaSAndreas Gohr    // skip minors
777b6912aeaSAndreas Gohr    if($flags & RECENTS_SKIP_MINORS) return false;
778b6912aeaSAndreas Gohr    $recent['minor'] = true;
779b6912aeaSAndreas Gohr  }else{
780b6912aeaSAndreas Gohr    $recent['minor'] = false;
781b6912aeaSAndreas Gohr  }
782d437bcc4SAndreas Gohr
783d437bcc4SAndreas Gohr  // remember in seen to skip additional sights
784d437bcc4SAndreas Gohr  $seen[$id] = 1;
785d437bcc4SAndreas Gohr
7860dc92c6fSAndreas Gohr  // check if it's a hidden page
7870dc92c6fSAndreas Gohr  if(isHiddenPage($id)) return false;
7880dc92c6fSAndreas Gohr
789d437bcc4SAndreas Gohr  // filter namespace
790d437bcc4SAndreas Gohr  if (($ns) && (strpos($id,$ns.':') !== 0)) return false;
791d437bcc4SAndreas Gohr
792d437bcc4SAndreas Gohr  // exclude subnamespaces
793b6912aeaSAndreas Gohr  if (($flags & RECENTS_SKIP_SUBSPACES) && (getNS($id) != $ns)) return false;
794d437bcc4SAndreas Gohr
795ae56bfb6SAndreas Gohr  // check ACL
796ae56bfb6SAndreas Gohr  if (auth_quickaclcheck($id) < AUTH_READ) return false;
797ae56bfb6SAndreas Gohr
798d437bcc4SAndreas Gohr  // check existance
799d437bcc4SAndreas Gohr  if(!@file_exists(wikiFN($id))){
800b6912aeaSAndreas Gohr    if($flags & RECENTS_SKIP_DELETED){
801d437bcc4SAndreas Gohr      return false;
802d437bcc4SAndreas Gohr    }else{
803d437bcc4SAndreas Gohr      $recent['del'] = true;
804d437bcc4SAndreas Gohr    }
805d437bcc4SAndreas Gohr  }else{
806d437bcc4SAndreas Gohr    $recent['del'] = false;
807d437bcc4SAndreas Gohr  }
808d437bcc4SAndreas Gohr
809d437bcc4SAndreas Gohr  $recent['id']   = $id;
810d437bcc4SAndreas Gohr  $recent['date'] = $dt;
811d437bcc4SAndreas Gohr  $recent['ip']   = $ip;
812d437bcc4SAndreas Gohr  $recent['user'] = $usr;
813d437bcc4SAndreas Gohr  $recent['sum']  = $sum;
814d437bcc4SAndreas Gohr
815d437bcc4SAndreas Gohr  return $recent;
816d437bcc4SAndreas Gohr}
817d437bcc4SAndreas Gohr
818b6912aeaSAndreas Gohr
819d437bcc4SAndreas Gohr/**
820f3f0262cSandi * returns an array of recently changed files using the
821f3f0262cSandi * changelog
822d437bcc4SAndreas Gohr *
823b6912aeaSAndreas Gohr * The following constants can be used to control which changes are
824b6912aeaSAndreas Gohr * included. Add them together as needed.
825b6912aeaSAndreas Gohr *
826b6912aeaSAndreas Gohr * RECENTS_SKIP_DELETED   - don't include deleted pages
827b6912aeaSAndreas Gohr * RECENTS_SKIP_MINORS    - don't include minor changes
828b6912aeaSAndreas Gohr * RECENTS_SKIP_SUBSPACES - don't include subspaces
829b6912aeaSAndreas Gohr *
830d437bcc4SAndreas Gohr * @param int    $first   number of first entry returned (for paginating
831d437bcc4SAndreas Gohr * @param int    $num     return $num entries
832d437bcc4SAndreas Gohr * @param string $ns      restrict to given namespace
833b6912aeaSAndreas Gohr * @param bool   $flags   see above
83415fae107Sandi *
83515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
836f3f0262cSandi */
837b6912aeaSAndreas Gohrfunction getRecents($first,$num,$ns='',$flags=0){
838f3f0262cSandi  global $conf;
839f3f0262cSandi  $recent = array();
840d437bcc4SAndreas Gohr  $count  = 0;
8415749f1ceSmatthiasgrimm
8425749f1ceSmatthiasgrimm  if(!$num)
8435749f1ceSmatthiasgrimm    return $recent;
844f3f0262cSandi
845c1049928Sandi  if(!@is_readable($conf['changelog'])){
846c1049928Sandi    msg($conf['changelog'].' is not readable',-1);
847c1049928Sandi    return $recent;
848c1049928Sandi  }
849c1049928Sandi
850d437bcc4SAndreas Gohr  $fh  = fopen($conf['changelog'],'r');
851d437bcc4SAndreas Gohr  $buf = '';
852d437bcc4SAndreas Gohr  $csz = 4096;                              //chunksize
853d437bcc4SAndreas Gohr  fseek($fh,0,SEEK_END);                    // jump to the end
854d437bcc4SAndreas Gohr  $pos = ftell($fh);                        // position pointer
855f3f0262cSandi
856d437bcc4SAndreas Gohr  // now read backwards into buffer
857d437bcc4SAndreas Gohr  while($pos > 0){
858d437bcc4SAndreas Gohr    $pos -= $csz;                           // seek to previous chunk...
859f6c1156dSWolfgang Ocker    if($pos < 0) {                          // ...or rest of file
860f6c1156dSWolfgang Ocker      $csz += $pos;
861f6c1156dSWolfgang Ocker      $pos = 0;
862f6c1156dSWolfgang Ocker    }
863f6c1156dSWolfgang Ocker
864d437bcc4SAndreas Gohr    fseek($fh,$pos);
865dbb00abcSEsther Brunner
866d437bcc4SAndreas Gohr    $buf = fread($fh,$csz).$buf;            // prepend to buffer
8678f1d587cSEsther Brunner
868d437bcc4SAndreas Gohr    $lines = explode("\n",$buf);            // split buffer into lines
8695749f1ceSmatthiasgrimm
870d437bcc4SAndreas Gohr    if($pos > 0){
871d437bcc4SAndreas Gohr      $buf = array_shift($lines);           // first one may be still incomplete
872f3f0262cSandi    }
873d437bcc4SAndreas Gohr
874d437bcc4SAndreas Gohr    $cnt = count($lines);
875d437bcc4SAndreas Gohr    if(!$cnt) continue;                     // no lines yet
876d437bcc4SAndreas Gohr
877d437bcc4SAndreas Gohr    // handle lines
878d437bcc4SAndreas Gohr    for($i = $cnt-1; $i >= 0; $i--){
879b6912aeaSAndreas Gohr      $rec = _handleRecent($lines[$i],$ns,$flags);
880d437bcc4SAndreas Gohr      if($rec !== false){
881d437bcc4SAndreas Gohr        if(--$first >= 0) continue;         // skip first entries
882d437bcc4SAndreas Gohr        $recent[] = $rec;
883d437bcc4SAndreas Gohr        $count++;
884d437bcc4SAndreas Gohr
885d437bcc4SAndreas Gohr        // break while when we have enough entries
886d437bcc4SAndreas Gohr        if($count >= $num){
887d437bcc4SAndreas Gohr          $pos = 0; // will break the while loop
888d437bcc4SAndreas Gohr          break;    // will break the for loop
889f3f0262cSandi        }
890f3f0262cSandi      }
891d437bcc4SAndreas Gohr    }
892d437bcc4SAndreas Gohr  }// end of while
893d437bcc4SAndreas Gohr
894d437bcc4SAndreas Gohr  fclose($fh);
895f3f0262cSandi  return $recent;
896f3f0262cSandi}
897f3f0262cSandi
898f3f0262cSandi/**
89951815db0SYann * Compare the logline $a to the timestamp $b
90051815db0SYann * @author Yann Hamon <yann.hamon@mandragor.org>
90151815db0SYann * @return integer 0 if the logline has timestamp $b, <0 if the timestam
90251815db0SYann *         of $a is greater than $b, >0 else.
90351815db0SYann */
90451815db0SYannfunction hasTimestamp($a, $b)
90551815db0SYann{
90651815db0SYann  if (strpos($a, $b) === 0)
90751815db0SYann    return 0;
90851815db0SYann  else
90951815db0SYann    return strcmp ($a, $b);
91051815db0SYann}
91151815db0SYann
91251815db0SYann/**
91351815db0SYann * performs a dichotomic search on an array using
91451815db0SYann * a custom compare function
91551815db0SYann *
91651815db0SYann * @author Yann Hamon <yann.hamon@mandragor.org>
91751815db0SYann */
91851815db0SYannfunction array_dichotomic_search($ar, $value, $compareFunc) {
91951815db0SYann  $value = trim($value);
92051815db0SYann  if (!$ar || !$value || !$compareFunc) return (null);
92151815db0SYann  $len = count($ar);
92251815db0SYann
92351815db0SYann  $l = 0;
92451815db0SYann  $r = $len-1;
92551815db0SYann
92651815db0SYann  do {
92751815db0SYann    $i = floor(($l+$r)/2);
92851815db0SYann    if ($compareFunc($ar[$i], $value)<0)
92951815db0SYann      $l = $i+1;
93051815db0SYann    else
93151815db0SYann     $r = $i-1;
93251815db0SYann  } while ($compareFunc($ar[$i], $value)!=0 && $l<=$r);
93351815db0SYann
93451815db0SYann  if ($compareFunc($ar[$i], $value)==0)
93551815db0SYann    return $i;
93651815db0SYann  else
93751815db0SYann    return -1;
93851815db0SYann}
93951815db0SYann
94051815db0SYann/**
941652610a2Sandi * gets additonal informations for a certain pagerevison
942652610a2Sandi * from the changelog
943652610a2Sandi *
944652610a2Sandi * @author Andreas Gohr <andi@splitbrain.org>
94551815db0SYann * @author Yann Hamon <yann.hamon@mandragor.org>
946fb53bfe2SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
947652610a2Sandi */
948fb53bfe2SBen Coburnfunction getRevisionInfo($id,$rev,$mem_cache=true){
949652610a2Sandi  global $conf;
950fb53bfe2SBen Coburn  global $doku_temporary_revinfo_cache;
951fb53bfe2SBen Coburn  $cache =& $doku_temporary_revinfo_cache;
952258641c6Sandi  if(!$rev) return(null);
953258641c6Sandi
954fb53bfe2SBen Coburn  // check if it's already in the memory cache
955fb53bfe2SBen Coburn  if (is_array($cache) && isset($cache[$id]) && isset($cache[$id][$rev])) {
956fb53bfe2SBen Coburn    return $cache[$id][$rev];
957fb53bfe2SBen Coburn  }
958fb53bfe2SBen Coburn
959c1049928Sandi  $info = array();
960c1049928Sandi  if(!@is_readable($conf['changelog'])){
961c1049928Sandi    msg($conf['changelog'].' is not readable',-1);
962c1049928Sandi    return $recent;
963c1049928Sandi  }
964652610a2Sandi  $loglines = file($conf['changelog']);
96551815db0SYann
966fb53bfe2SBen Coburn  if (!$mem_cache) {
96751815db0SYann    // Search for a line with a matching timestamp
968fb53bfe2SBen Coburn    $index = array_dichotomic_search($loglines, $rev, 'hasTimestamp');
96951815db0SYann    if ($index == -1)
97051815db0SYann      return;
97151815db0SYann
97251815db0SYann    // The following code is necessary when there is more than
97351815db0SYann    // one line with one same timestamp
97451815db0SYann    $loglines_matching = array();
9752e2fda08SYann    for ($i=$index-1;$i>=0 && hasTimestamp($loglines[$i], $rev) == 0; $i--)
97651815db0SYann      $loglines_matching[] = $loglines[$i];
977fb53bfe2SBen Coburn    $loglines_matching = array_reverse($loglines_matching);
978fb53bfe2SBen Coburn    $loglines_matching[] =  $loglines[$index];
9792e2fda08SYann    $logsize = count($loglines);
9802e2fda08SYann    for ($i=$index+1;$i<$logsize && hasTimestamp($loglines[$i], $rev) == 0; $i++)
98151815db0SYann      $loglines_matching[] = $loglines[$i];
98251815db0SYann
983fb53bfe2SBen Coburn    // pull off the line most recent line with the right id
984fb53bfe2SBen Coburn    $loglines_matching = array_reverse($loglines_matching); //newest first
985fb53bfe2SBen Coburn    foreach ($loglines_matching as $logline) {
986fb53bfe2SBen Coburn      $line = explode("\t", $logline);
987fb53bfe2SBen Coburn      if ($line[2]==$id) {
988652610a2Sandi        $info['date']  = $line[0];
989652610a2Sandi        $info['ip']    = $line[1];
990652610a2Sandi        $info['user']  = $line[3];
991652610a2Sandi        $info['sum']   = $line[4];
992b6912aeaSAndreas Gohr        $info['minor'] = isMinor($info['sum']);
993fb53bfe2SBen Coburn        break;
994fb53bfe2SBen Coburn      }
995fb53bfe2SBen Coburn    }
996fb53bfe2SBen Coburn  } else {
997fb53bfe2SBen Coburn    // load and cache all the lines with the right id
998fb53bfe2SBen Coburn    if(!is_array($cache)) { $cache = array(); }
999fb53bfe2SBen Coburn    if (!isset($cache[$id])) { $cache[$id] = array(); }
1000fb53bfe2SBen Coburn    foreach ($loglines as $logline) {
1001fb53bfe2SBen Coburn      $start = strpos($logline, "\t", strpos($logline, "\t")+1)+1;
1002fb53bfe2SBen Coburn      $end = strpos($logline, "\t", $start);
1003fb53bfe2SBen Coburn      if (substr($logline, $start, $end-$start)==$id) {
1004fb53bfe2SBen Coburn        $line = explode("\t", $logline);
1005fb53bfe2SBen Coburn        $info = array();
1006fb53bfe2SBen Coburn        $info['date']  = $line[0];
1007fb53bfe2SBen Coburn        $info['ip']    = $line[1];
1008fb53bfe2SBen Coburn        $info['user']  = $line[3];
1009fb53bfe2SBen Coburn        $info['sum']   = $line[4];
1010fb53bfe2SBen Coburn        $info['minor'] = isMinor($info['sum']);
1011fb53bfe2SBen Coburn        $cache[$id][$info['date']] = $info;
1012fb53bfe2SBen Coburn      }
1013fb53bfe2SBen Coburn    }
1014fb53bfe2SBen Coburn    $info = $cache[$id][$rev];
1015fb53bfe2SBen Coburn  }
1016fb53bfe2SBen Coburn
1017652610a2Sandi  return $info;
1018652610a2Sandi}
1019652610a2Sandi
102051815db0SYann
1021652610a2Sandi/**
1022f3f0262cSandi * Saves a wikitext by calling io_saveFile
102315fae107Sandi *
102415fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
1025f3f0262cSandi */
1026b6912aeaSAndreas Gohrfunction saveWikiText($id,$text,$summary,$minor=false){
1027f3f0262cSandi  global $conf;
1028f3f0262cSandi  global $lang;
1029f3f0262cSandi  // ignore if no changes were made
1030f3f0262cSandi  if($text == rawWiki($id,'')){
1031f3f0262cSandi    return;
1032f3f0262cSandi  }
1033f3f0262cSandi
1034f3f0262cSandi  $file = wikiFN($id);
1035f3f0262cSandi  $old  = saveOldRevision($id);
1036f3f0262cSandi
1037f3f0262cSandi  if (empty($text)){
1038e1f3d9e1SEsther Brunner    // remove empty file
1039f3f0262cSandi    @unlink($file);
1040e1f3d9e1SEsther Brunner    // remove any meta info
1041e1f3d9e1SEsther Brunner    $mfiles = metaFiles($id);
1042e1f3d9e1SEsther Brunner    foreach ($mfiles as $mfile) {
1043e1f3d9e1SEsther Brunner      if (file_exists($mfile)) @unlink($mfile);
1044b158d625SSteven Danz    }
1045f3f0262cSandi    $del = true;
10463ce054b3Sandi    // autoset summary on deletion
10473ce054b3Sandi    if(empty($summary)) $summary = $lang['deleted'];
1048f864871eSAndreas Gohr    // unlock early
1049f864871eSAndreas Gohr    unlock($id);
105053d6ccfeSandi    // remove empty namespaces
105153d6ccfeSandi    io_sweepNS($id);
1052f3f0262cSandi  }else{
1053f3f0262cSandi    // save file (datadir is created in io_saveFile)
1054f3f0262cSandi    io_saveFile($file,$text);
105539a89382SEsther Brunner    saveMetadata($id, $file, $minor);
1056f3f0262cSandi    $del = false;
1057f3f0262cSandi  }
1058f3f0262cSandi
1059b6912aeaSAndreas Gohr  addLogEntry(@filemtime($file),$id,$summary,$minor);
106026a0801fSAndreas Gohr  // send notify mails
106190033e9dSAndreas Gohr  notify($id,'admin',$old,$summary,$minor);
106290033e9dSAndreas Gohr  notify($id,'subscribers',$old,$summary,$minor);
1063f3f0262cSandi
1064f3f0262cSandi  //purge cache on add by updating the purgefile
1065f3f0262cSandi  if($conf['purgeonadd'] && (!$old || $del)){
106698407a7aSandi    io_saveFile($conf['cachedir'].'/purgefile',time());
1067f3f0262cSandi  }
1068f3f0262cSandi}
1069f3f0262cSandi
1070f3f0262cSandi/**
107139a89382SEsther Brunner * saves the metadata for a page
107239a89382SEsther Brunner *
107339a89382SEsther Brunner * @author Esther Brunner <wikidesign@gmail.com>
107439a89382SEsther Brunner */
107539a89382SEsther Brunnerfunction saveMetadata($id, $file, $minor){
107639a89382SEsther Brunner  global $INFO;
107739a89382SEsther Brunner
107839a89382SEsther Brunner  $user = $_SERVER['REMOTE_USER'];
107939a89382SEsther Brunner
108039a89382SEsther Brunner  $meta = array();
108139a89382SEsther Brunner  if (!$INFO['exists']){ // newly created
108239a89382SEsther Brunner    $meta['date']['created'] = @filectime($file);
108339a89382SEsther Brunner    if ($user) $meta['creator'] = $INFO['userinfo']['name'];
108439a89382SEsther Brunner  } elseif (!$minor) {   // non-minor modification
108539a89382SEsther Brunner    $meta['date']['modified'] = @filemtime($file);
108639a89382SEsther Brunner    if ($user) $meta['contributor'][$user] = $INFO['userinfo']['name'];
108739a89382SEsther Brunner  }
108839a89382SEsther Brunner  p_set_metadata($id, $meta, true);
108939a89382SEsther Brunner}
109039a89382SEsther Brunner
109139a89382SEsther Brunner/**
1092f3f0262cSandi * moves the current version to the attic and returns its
1093f3f0262cSandi * revision date
109415fae107Sandi *
109515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
1096f3f0262cSandi */
1097f3f0262cSandifunction saveOldRevision($id){
1098f3f0262cSandi  global $conf;
1099f3f0262cSandi  $oldf = wikiFN($id);
1100f3f0262cSandi  if(!@file_exists($oldf)) return '';
1101f3f0262cSandi  $date = filemtime($oldf);
1102f3f0262cSandi  $newf = wikiFN($id,$date);
1103f3f0262cSandi  if(substr($newf,-3)=='.gz'){
1104f3f0262cSandi    io_saveFile($newf,rawWiki($id));
1105f3f0262cSandi  }else{
1106f3f0262cSandi    io_makeFileDir($newf);
1107f3f0262cSandi    copy($oldf, $newf);
1108f3f0262cSandi  }
1109f3f0262cSandi  return $date;
1110f3f0262cSandi}
1111f3f0262cSandi
1112f3f0262cSandi/**
111326a0801fSAndreas Gohr * Sends a notify mail on page change
111426a0801fSAndreas Gohr *
111526a0801fSAndreas Gohr * @param  string  $id       The changed page
111626a0801fSAndreas Gohr * @param  string  $who      Who to notify (admin|subscribers)
111726a0801fSAndreas Gohr * @param  int     $rev      Old page revision
111826a0801fSAndreas Gohr * @param  string  $summary  What changed
111990033e9dSAndreas Gohr * @param  boolean $minor    Is this a minor edit?
112015fae107Sandi *
112115fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
1122f3f0262cSandi */
112390033e9dSAndreas Gohrfunction notify($id,$who,$rev='',$summary='',$minor=false){
1124f3f0262cSandi  global $lang;
1125f3f0262cSandi  global $conf;
1126b158d625SSteven Danz
112726a0801fSAndreas Gohr  // decide if there is something to do
112826a0801fSAndreas Gohr  if($who == 'admin'){
112926a0801fSAndreas Gohr    if(empty($conf['notify'])) return; //notify enabled?
1130f3f0262cSandi    $text = rawLocale('mailtext');
113126a0801fSAndreas Gohr    $to   = $conf['notify'];
113226a0801fSAndreas Gohr    $bcc  = '';
113326a0801fSAndreas Gohr  }elseif($who == 'subscribers'){
113426a0801fSAndreas Gohr    if(!$conf['subscribers']) return; //subscribers enabled?
113590033e9dSAndreas Gohr    if($conf['useacl'] && $_SERVER['REMOTE_USER'] && $minor) return; //skip minors
113626a0801fSAndreas Gohr    $bcc  = subscriber_addresslist($id);
113726a0801fSAndreas Gohr    if(empty($bcc)) return;
113826a0801fSAndreas Gohr    $to   = '';
113926a0801fSAndreas Gohr    $text = rawLocale('subscribermail');
1140a06e4bdbSSebastian Harl  }elseif($who == 'register'){
1141a06e4bdbSSebastian Harl    if(empty($conf['registernotify'])) return;
1142a06e4bdbSSebastian Harl    $text = rawLocale('registermail');
1143a06e4bdbSSebastian Harl    $to   = $conf['registernotify'];
1144a06e4bdbSSebastian Harl    $bcc  = '';
114526a0801fSAndreas Gohr  }else{
114626a0801fSAndreas Gohr    return; //just to be safe
114726a0801fSAndreas Gohr  }
114826a0801fSAndreas Gohr
1149f3f0262cSandi  $text = str_replace('@DATE@',date($conf['dformat']),$text);
1150f3f0262cSandi  $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text);
1151f3f0262cSandi  $text = str_replace('@IPADDRESS@',$_SERVER['REMOTE_ADDR'],$text);
1152f3f0262cSandi  $text = str_replace('@HOSTNAME@',gethostbyaddr($_SERVER['REMOTE_ADDR']),$text);
1153ed7b5f09Sandi  $text = str_replace('@NEWPAGE@',wl($id,'',true),$text);
115426a0801fSAndreas Gohr  $text = str_replace('@PAGE@',$id,$text);
115526a0801fSAndreas Gohr  $text = str_replace('@TITLE@',$conf['title'],$text);
1156ed7b5f09Sandi  $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text);
1157f3f0262cSandi  $text = str_replace('@SUMMARY@',$summary,$text);
11587a82afdcSandi  $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text);
1159f3f0262cSandi
1160a06e4bdbSSebastian Harl  if($who == 'register'){
1161a06e4bdbSSebastian Harl    $subject = $lang['mail_new_user'].' '.$summary;
1162a06e4bdbSSebastian Harl  }elseif($rev){
1163f3f0262cSandi    $subject = $lang['mail_changed'].' '.$id;
1164ed7b5f09Sandi    $text = str_replace('@OLDPAGE@',wl($id,"rev=$rev",true),$text);
1165ccdfa6c0SAndreas Gohr    require_once(DOKU_INC.'inc/DifferenceEngine.php');
1166f3f0262cSandi    $df  = new Diff(split("\n",rawWiki($id,$rev)),
1167f3f0262cSandi                    split("\n",rawWiki($id)));
1168f3f0262cSandi    $dformat = new UnifiedDiffFormatter();
1169f3f0262cSandi    $diff    = $dformat->format($df);
1170f3f0262cSandi  }else{
1171f3f0262cSandi    $subject=$lang['mail_newpage'].' '.$id;
1172f3f0262cSandi    $text = str_replace('@OLDPAGE@','none',$text);
1173f3f0262cSandi    $diff = rawWiki($id);
1174f3f0262cSandi  }
1175f3f0262cSandi  $text = str_replace('@DIFF@',$diff,$text);
1176241f3a36Sandi  $subject = '['.$conf['title'].'] '.$subject;
1177f3f0262cSandi
117826a0801fSAndreas Gohr  mail_send($to,$subject,$text,$conf['mailfrom'],'',$bcc);
1179f3f0262cSandi}
1180f3f0262cSandi
118115fae107Sandi/**
118215fae107Sandi * Return a list of available page revisons
118315fae107Sandi *
118415fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
118515fae107Sandi */
1186f3f0262cSandifunction getRevisions($id){
1187f3f0262cSandi  $revd = dirname(wikiFN($id,'foo'));
1188f3f0262cSandi  $revs = array();
1189f3f0262cSandi  $clid = cleanID($id);
1190f3f0262cSandi  if(strrpos($clid,':')) $clid = substr($clid,strrpos($clid,':')+1); //remove path
1191493a6929SKobaYY  $clid = utf8_encodeFN($clid);
11926f6c2468SBen Coburn  $clid_len = strlen($clid);
1193f3f0262cSandi  if (is_dir($revd) && $dh = opendir($revd)) {
1194f3f0262cSandi    while (($file = readdir($dh)) !== false) {
11956f6c2468SBen Coburn      if (substr($file, 0, $clid_len)===$clid) {
11963b97c5ecSchris        $p = @strpos($file, '.', $clid_len+1);
11976f6c2468SBen Coburn        if (!$p===false) {
11986f6c2468SBen Coburn          $revs[] = substr($file, $clid_len+1, $p-$clid_len-1);
11996f6c2468SBen Coburn        }
1200f3f0262cSandi      }
1201f3f0262cSandi    }
1202f3f0262cSandi    closedir($dh);
1203f3f0262cSandi  }
1204f3f0262cSandi  rsort($revs);
1205f3f0262cSandi  return $revs;
1206f3f0262cSandi}
1207f3f0262cSandi
1208f3f0262cSandi/**
1209f3f0262cSandi * extracts the query from a google referer
121015fae107Sandi *
12116b13307fSandi * @todo   should be more generic and support yahoo et al
121215fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
1213f3f0262cSandi */
1214f3f0262cSandifunction getGoogleQuery(){
1215f3f0262cSandi  $url = parse_url($_SERVER['HTTP_REFERER']);
12165c3f206fSandi  if(!$url) return '';
1217f3f0262cSandi
1218f3f0262cSandi  if(!preg_match("#google\.#i",$url['host'])) return '';
1219f3f0262cSandi  $query = array();
1220f3f0262cSandi  parse_str($url['query'],$query);
1221f3f0262cSandi
1222f3f0262cSandi  return $query['q'];
1223f3f0262cSandi}
1224f3f0262cSandi
1225f3f0262cSandi/**
122615fae107Sandi * Try to set correct locale
122715fae107Sandi *
1228095bfd5cSandi * @deprecated No longer used
122915fae107Sandi * @author     Andreas Gohr <andi@splitbrain.org>
1230f3f0262cSandi */
1231f3f0262cSandifunction setCorrectLocale(){
1232f3f0262cSandi  global $conf;
1233f3f0262cSandi  global $lang;
1234f3f0262cSandi
1235f3f0262cSandi  $enc = strtoupper($lang['encoding']);
1236f3f0262cSandi  foreach ($lang['locales'] as $loc){
1237f3f0262cSandi    //try locale
1238f3f0262cSandi    if(@setlocale(LC_ALL,$loc)) return;
1239f3f0262cSandi    //try loceale with encoding
1240f3f0262cSandi    if(@setlocale(LC_ALL,"$loc.$enc")) return;
1241f3f0262cSandi  }
1242f3f0262cSandi  //still here? try to set from environment
1243f3f0262cSandi  @setlocale(LC_ALL,"");
1244f3f0262cSandi}
1245f3f0262cSandi
1246f3f0262cSandi/**
1247f3f0262cSandi * Return the human readable size of a file
1248f3f0262cSandi *
1249f3f0262cSandi * @param       int    $size   A file size
1250f3f0262cSandi * @param       int    $dec    A number of decimal places
1251f3f0262cSandi * @author      Martin Benjamin <b.martin@cybernet.ch>
1252f3f0262cSandi * @author      Aidan Lister <aidan@php.net>
1253f3f0262cSandi * @version     1.0.0
1254f3f0262cSandi */
1255f31d5b73Sandifunction filesize_h($size, $dec = 1){
1256f3f0262cSandi  $sizes = array('B', 'KB', 'MB', 'GB');
1257f3f0262cSandi  $count = count($sizes);
1258f3f0262cSandi  $i = 0;
1259f3f0262cSandi
1260f3f0262cSandi  while ($size >= 1024 && ($i < $count - 1)) {
1261f3f0262cSandi    $size /= 1024;
1262f3f0262cSandi    $i++;
1263f3f0262cSandi  }
1264f3f0262cSandi
1265f3f0262cSandi  return round($size, $dec) . ' ' . $sizes[$i];
1266f3f0262cSandi}
1267f3f0262cSandi
126815fae107Sandi/**
126900a7b5adSEsther Brunner * return an obfuscated email address in line with $conf['mailguard'] setting
127000a7b5adSEsther Brunner *
127100a7b5adSEsther Brunner * @author Harry Fuecks <hfuecks@gmail.com>
127200a7b5adSEsther Brunner * @author Christopher Smith <chris@jalakai.co.uk>
127300a7b5adSEsther Brunner */
127400a7b5adSEsther Brunnerfunction obfuscate($email) {
127500a7b5adSEsther Brunner  global $conf;
127600a7b5adSEsther Brunner
127700a7b5adSEsther Brunner  switch ($conf['mailguard']) {
127800a7b5adSEsther Brunner    case 'visible' :
127900a7b5adSEsther Brunner      $obfuscate = array('@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] ');
128000a7b5adSEsther Brunner      return strtr($email, $obfuscate);
128100a7b5adSEsther Brunner
128200a7b5adSEsther Brunner    case 'hex' :
128300a7b5adSEsther Brunner      $encode = '';
128400a7b5adSEsther Brunner      for ($x=0; $x < strlen($email); $x++) $encode .= '&#x' . bin2hex($email{$x}).';';
128500a7b5adSEsther Brunner      return $encode;
128600a7b5adSEsther Brunner
128700a7b5adSEsther Brunner    case 'none' :
128800a7b5adSEsther Brunner    default :
128900a7b5adSEsther Brunner      return $email;
129000a7b5adSEsther Brunner  }
129100a7b5adSEsther Brunner}
129200a7b5adSEsther Brunner
129300a7b5adSEsther Brunner/**
1294dc57ef04Sandi * Return DokuWikis version
129515fae107Sandi *
129615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
129715fae107Sandi */
1298f31d5b73Sandifunction getVersion(){
1299f31d5b73Sandi  //import version string
1300f31d5b73Sandi  if(@file_exists('VERSION')){
1301f31d5b73Sandi    //official release
13020647ce3bSAndreas Gohr    return 'Release '.trim(io_readfile(DOKU_INC.'/VERSION'));
1303f31d5b73Sandi  }elseif(is_dir('_darcs')){
1304f31d5b73Sandi    //darcs checkout
1305f31d5b73Sandi    $inv = file('_darcs/inventory');
1306ae41559bSAndreas Gohr    $inv = preg_grep('#\*\*\d{14}[\]$]#',$inv);
1307f31d5b73Sandi    $cur = array_pop($inv);
1308f31d5b73Sandi    preg_match('#\*\*(\d{4})(\d{2})(\d{2})#',$cur,$matches);
1309f31d5b73Sandi    return 'Darcs '.$matches[1].'-'.$matches[2].'-'.$matches[3];
1310f31d5b73Sandi  }else{
1311f31d5b73Sandi    return 'snapshot?';
1312f31d5b73Sandi  }
1313f31d5b73Sandi}
1314f31d5b73Sandi
1315f31d5b73Sandi/**
1316f31d5b73Sandi * Run a few sanity checks
1317f31d5b73Sandi *
1318f31d5b73Sandi * @author Andreas Gohr <andi@splitbrain.org>
1319f31d5b73Sandi */
1320f3f0262cSandifunction check(){
1321f3f0262cSandi  global $conf;
1322f3f0262cSandi  global $INFO;
1323f3f0262cSandi
1324f31d5b73Sandi  msg('DokuWiki version: '.getVersion(),1);
1325f31d5b73Sandi
132649022a38Sandi  if(version_compare(phpversion(),'4.3.0','<')){
132749022a38Sandi    msg('Your PHP version is too old ('.phpversion().' vs. 4.3.+ recommended)',-1);
132849022a38Sandi  }elseif(version_compare(phpversion(),'4.3.10','<')){
132949022a38Sandi    msg('Consider upgrading PHP to 4.3.10 or higher for security reasons (your version: '.phpversion().')',0);
133049022a38Sandi  }else{
133149022a38Sandi    msg('PHP version '.phpversion(),1);
133249022a38Sandi  }
133349022a38Sandi
1334f3f0262cSandi  if(is_writable($conf['changelog'])){
1335f3f0262cSandi    msg('Changelog is writable',1);
1336f3f0262cSandi  }else{
1337f3f0262cSandi    msg('Changelog is not writable',-1);
1338f3f0262cSandi  }
1339f3f0262cSandi
1340f3f0262cSandi  if(is_writable($conf['datadir'])){
1341f3f0262cSandi    msg('Datadir is writable',1);
1342f3f0262cSandi  }else{
1343f3f0262cSandi    msg('Datadir is not writable',-1);
1344f3f0262cSandi  }
1345f3f0262cSandi
1346f3f0262cSandi  if(is_writable($conf['olddir'])){
1347f3f0262cSandi    msg('Attic is writable',1);
1348f3f0262cSandi  }else{
1349f3f0262cSandi    msg('Attic is not writable',-1);
1350f3f0262cSandi  }
1351f3f0262cSandi
1352f3f0262cSandi  if(is_writable($conf['mediadir'])){
1353f3f0262cSandi    msg('Mediadir is writable',1);
1354f3f0262cSandi  }else{
1355f3f0262cSandi    msg('Mediadir is not writable',-1);
1356f3f0262cSandi  }
1357f3f0262cSandi
135898407a7aSandi  if(is_writable($conf['cachedir'])){
135998407a7aSandi    msg('Cachedir is writable',1);
136098407a7aSandi  }else{
136198407a7aSandi    msg('Cachedir is not writable',-1);
136298407a7aSandi  }
136398407a7aSandi
13647de6c234SAndreas Gohr  if(is_writable($conf['lockdir'])){
13657de6c234SAndreas Gohr    msg('Lockdir is writable',1);
13667de6c234SAndreas Gohr  }else{
13677de6c234SAndreas Gohr    msg('Lockdir is not writable',-1);
13687de6c234SAndreas Gohr  }
13697de6c234SAndreas Gohr
1370e7cb32dcSAndreas Gohr  if(is_writable(DOKU_CONF.'users.auth.php')){
13718c4f28e8Sjan    msg('conf/users.auth.php is writable',1);
1372f3f0262cSandi  }else{
13738c4f28e8Sjan    msg('conf/users.auth.php is not writable',0);
1374f3f0262cSandi  }
137593a9e835Sandi
137693a9e835Sandi  if(function_exists('mb_strpos')){
137793a9e835Sandi    if(defined('UTF8_NOMBSTRING')){
137893a9e835Sandi      msg('mb_string extension is available but will not be used',0);
137993a9e835Sandi    }else{
138093a9e835Sandi      msg('mb_string extension is available and will be used',1);
138193a9e835Sandi    }
138293a9e835Sandi  }else{
138393a9e835Sandi    msg('mb_string extension not available - PHP only replacements will be used',0);
138493a9e835Sandi  }
1385f42d1c75SAndreas Gohr
1386f42d1c75SAndreas Gohr  if($conf['allowdebug']){
1387f42d1c75SAndreas Gohr    msg('Debugging support is enabled. If you don\'t need it you should set $conf[\'allowdebug\'] = 0',-1);
1388f42d1c75SAndreas Gohr  }else{
1389f42d1c75SAndreas Gohr    msg('Debugging support is disabled',1);
1390f42d1c75SAndreas Gohr  }
1391f3f0262cSandi
1392f3f0262cSandi  msg('Your current permission for this page is '.$INFO['perm'],0);
1393f3f0262cSandi
1394f3f0262cSandi  if(is_writable($INFO['filepath'])){
1395f3f0262cSandi    msg('The current page is writable by the webserver',0);
1396f3f0262cSandi  }else{
1397f3f0262cSandi    msg('The current page is not writable by the webserver',0);
1398f3f0262cSandi  }
1399f3f0262cSandi
1400f3f0262cSandi  if($INFO['writable']){
1401f3f0262cSandi    msg('The current page is writable by you',0);
1402f3f0262cSandi  }else{
1403f3f0262cSandi    msg('The current page is not writable you',0);
1404f3f0262cSandi  }
1405f3f0262cSandi}
1406340756e4Sandi
1407b158d625SSteven Danz/**
1408b158d625SSteven Danz * Let us know if a user is tracking a page
1409b158d625SSteven Danz *
14101380fc45SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
1411b158d625SSteven Danz */
14121380fc45SAndreas Gohrfunction is_subscribed($id,$uid){
14131380fc45SAndreas Gohr  $file=metaFN($id,'.mlist');
14141380fc45SAndreas Gohr  if (@file_exists($file)) {
1415b158d625SSteven Danz    $mlist = file($file);
14161380fc45SAndreas Gohr    $pos = array_search($uid."\n",$mlist);
14171380fc45SAndreas Gohr    return is_int($pos);
1418b158d625SSteven Danz  }
14191380fc45SAndreas Gohr
1420b158d625SSteven Danz  return false;
1421b158d625SSteven Danz}
1422340756e4Sandi
1423f9eb5648Ssteven-danz/**
1424f9eb5648Ssteven-danz * Return a string with the email addresses of all the
1425f9eb5648Ssteven-danz * users subscribed to a page
1426f9eb5648Ssteven-danz *
142726a0801fSAndreas Gohr * @author Steven Danz <steven-danz@kc.rr.com>
1428f9eb5648Ssteven-danz */
1429f9eb5648Ssteven-danzfunction subscriber_addresslist($id){
1430f9eb5648Ssteven-danz  global $conf;
1431cd52f92dSchris  global $auth;
1432f9eb5648Ssteven-danz
1433f9eb5648Ssteven-danz  $emails = '';
1434f9eb5648Ssteven-danz
143526a0801fSAndreas Gohr  if (!$conf['subscribers']) return;
143626a0801fSAndreas Gohr
1437f9eb5648Ssteven-danz  $mlist = array();
1438f9eb5648Ssteven-danz  $file=metaFN($id,'.mlist');
1439f9eb5648Ssteven-danz  if (file_exists($file)) {
1440f9eb5648Ssteven-danz    $mlist = file($file);
1441f9eb5648Ssteven-danz  }
1442f9eb5648Ssteven-danz  if(count($mlist) > 0) {
1443f9eb5648Ssteven-danz    foreach ($mlist as $who) {
1444f9eb5648Ssteven-danz      $who = rtrim($who);
1445cd52f92dSchris      $info = $auth->getUserData($who);
1446f9eb5648Ssteven-danz      $level = auth_aclcheck($id,$who,$info['grps']);
1447f9eb5648Ssteven-danz      if ($level >= AUTH_READ) {
1448f9eb5648Ssteven-danz        if (strcasecmp($info['mail'],$conf['notify']) != 0) {
1449f9eb5648Ssteven-danz          if (empty($emails)) {
1450f9eb5648Ssteven-danz            $emails = $info['mail'];
1451f9eb5648Ssteven-danz          } else {
1452f9eb5648Ssteven-danz            $emails = "$emails,".$info['mail'];
1453f9eb5648Ssteven-danz          }
1454f9eb5648Ssteven-danz        }
1455f9eb5648Ssteven-danz      }
1456f9eb5648Ssteven-danz    }
1457f9eb5648Ssteven-danz  }
1458f9eb5648Ssteven-danz
1459f9eb5648Ssteven-danz  return $emails;
1460f9eb5648Ssteven-danz}
1461f9eb5648Ssteven-danz
146289541d4bSAndreas Gohr/**
146389541d4bSAndreas Gohr * Removes quoting backslashes
146489541d4bSAndreas Gohr *
146589541d4bSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
146689541d4bSAndreas Gohr */
146789541d4bSAndreas Gohrfunction unslash($string,$char="'"){
146889541d4bSAndreas Gohr  return str_replace('\\'.$char,$char,$string);
146989541d4bSAndreas Gohr}
147089541d4bSAndreas Gohr
1471340756e4Sandi//Setup VIM: ex: et ts=2 enc=utf-8 :
1472