xref: /dokuwiki/inc/common.php (revision 7bff22c03d8d769cfed475f6e253c72b43f9b131)
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');
127d559c7fSBen Coburn  require_once(DOKU_INC.'inc/changelog.php');
13ed7b5f09Sandi  require_once(DOKU_INC.'inc/utf8.php');
14ed7b5f09Sandi  require_once(DOKU_INC.'inc/mail.php');
15c112d578Sandi  require_once(DOKU_INC.'inc/parserutils.php');
16f3f0262cSandi
17f3f0262cSandi/**
18b6912aeaSAndreas Gohr * These constants are used with the recents function
19b6912aeaSAndreas Gohr */
20b6912aeaSAndreas Gohrdefine('RECENTS_SKIP_DELETED',2);
21b6912aeaSAndreas Gohrdefine('RECENTS_SKIP_MINORS',4);
22b6912aeaSAndreas Gohrdefine('RECENTS_SKIP_SUBSPACES',8);
23b6912aeaSAndreas Gohr
24b6912aeaSAndreas Gohr/**
25d5197206Schris * Wrapper around htmlspecialchars()
26d5197206Schris *
27d5197206Schris * @author Andreas Gohr <andi@splitbrain.org>
28d5197206Schris * @see    htmlspecialchars()
29d5197206Schris */
30d5197206Schrisfunction hsc($string){
31d5197206Schris  return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
32d5197206Schris}
33d5197206Schris
34d5197206Schris/**
35d5197206Schris * print a newline terminated string
36d5197206Schris *
37d5197206Schris * You can give an indention as optional parameter
38d5197206Schris *
39d5197206Schris * @author Andreas Gohr <andi@splitbrain.org>
40d5197206Schris */
41d5197206Schrisfunction ptln($string,$intend=0){
42d5197206Schris  for($i=0; $i<$intend; $i++) print ' ';
43d5197206Schris  print"$string\n";
44d5197206Schris}
45d5197206Schris
46d5197206Schris/**
4715fae107Sandi * Return info about the current document as associative
48f3f0262cSandi * array.
4915fae107Sandi *
5015fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
51f3f0262cSandi */
52f3f0262cSandifunction pageinfo(){
53f3f0262cSandi  global $ID;
54f3f0262cSandi  global $REV;
55f3f0262cSandi  global $USERINFO;
56f3f0262cSandi  global $conf;
57f3f0262cSandi
58f3f0262cSandi  if($_SERVER['REMOTE_USER']){
59f3f0262cSandi    $info['userinfo']   = $USERINFO;
60f3f0262cSandi    $info['perm']       = auth_quickaclcheck($ID);
611380fc45SAndreas Gohr    $info['subscribed'] = is_subscribed($ID,$_SERVER['REMOTE_USER']);
62ee4c4a1bSAndreas Gohr    $info['client']     = $_SERVER['REMOTE_USER'];
6317ee7f66SAndreas Gohr
6417ee7f66SAndreas Gohr    // if some outside auth were used only REMOTE_USER is set
6517ee7f66SAndreas Gohr    if(!$info['userinfo']['name']){
6617ee7f66SAndreas Gohr      $info['userinfo']['name'] = $_SERVER['REMOTE_USER'];
6717ee7f66SAndreas Gohr    }
68ee4c4a1bSAndreas Gohr
69f3f0262cSandi  }else{
70f3f0262cSandi    $info['perm']       = auth_aclcheck($ID,'',null);
711380fc45SAndreas Gohr    $info['subscribed'] = false;
72ee4c4a1bSAndreas Gohr    $info['client']     = clientIP(true);
73f3f0262cSandi  }
74f3f0262cSandi
75f3f0262cSandi  $info['namespace'] = getNS($ID);
76f3f0262cSandi  $info['locked']    = checklock($ID);
77f3f0262cSandi  $info['filepath']  = realpath(wikiFN($ID,$REV));
78f3f0262cSandi  $info['exists']    = @file_exists($info['filepath']);
79f3f0262cSandi  if($REV && !$info['exists']){
80f3f0262cSandi    //check if current revision was meant
81f3f0262cSandi    $cur = wikiFN($ID);
82f3f0262cSandi    if(@file_exists($cur) && (@filemtime($cur) == $REV)){
83f3f0262cSandi      $info['filepath'] = realpath($cur);
84f3f0262cSandi      $info['exists']   = true;
85f3f0262cSandi      $REV = '';
86f3f0262cSandi    }
87f3f0262cSandi  }
88c112d578Sandi  $info['rev'] = $REV;
89f3f0262cSandi  if($info['exists']){
90f3f0262cSandi    $info['writable'] = (is_writable($info['filepath']) &&
91f3f0262cSandi                         ($info['perm'] >= AUTH_EDIT));
92f3f0262cSandi  }else{
93f3f0262cSandi    $info['writable'] = ($info['perm'] >= AUTH_CREATE);
94f3f0262cSandi  }
95f3f0262cSandi  $info['editable']  = ($info['writable'] && empty($info['lock']));
96f3f0262cSandi  $info['lastmod']   = @filemtime($info['filepath']);
97f3f0262cSandi
9871726d78SBen Coburn  //load page meta data
9971726d78SBen Coburn  $info['meta'] = p_get_metadata($ID);
10071726d78SBen Coburn
101652610a2Sandi  //who's the editor
102652610a2Sandi  if($REV){
10371726d78SBen Coburn    $revinfo = getRevisionInfo($ID, $REV, 1024);
104652610a2Sandi  }else{
10571726d78SBen Coburn    $revinfo = $info['meta']['last_change'];
106652610a2Sandi  }
107652610a2Sandi  $info['ip']     = $revinfo['ip'];
108652610a2Sandi  $info['user']   = $revinfo['user'];
109652610a2Sandi  $info['sum']    = $revinfo['sum'];
11071726d78SBen Coburn  // See also $INFO['meta']['last_change'] which is the most recent log line for page $ID.
11171726d78SBen Coburn  // Use $INFO['meta']['last_change']['type']==='e' in place of $info['minor'].
11259f257aeSchris
11388f522e9Sandi  if($revinfo['user']){
11488f522e9Sandi    $info['editor'] = $revinfo['user'];
11588f522e9Sandi  }else{
11688f522e9Sandi    $info['editor'] = $revinfo['ip'];
11788f522e9Sandi  }
118652610a2Sandi
119ee4c4a1bSAndreas Gohr  // draft
120ee4c4a1bSAndreas Gohr  $draft = getCacheName($info['client'].$ID,'.draft');
121ee4c4a1bSAndreas Gohr  if(@file_exists($draft)){
122ee4c4a1bSAndreas Gohr    if(@filemtime($draft) < @filemtime(wikiFN($ID))){
123ee4c4a1bSAndreas Gohr      // remove stale draft
124ee4c4a1bSAndreas Gohr      @unlink($draft);
125ee4c4a1bSAndreas Gohr    }else{
126ee4c4a1bSAndreas Gohr      $info['draft'] = $draft;
127ee4c4a1bSAndreas Gohr    }
128ee4c4a1bSAndreas Gohr  }
129ee4c4a1bSAndreas Gohr
130f3f0262cSandi  return $info;
131f3f0262cSandi}
132f3f0262cSandi
133f3f0262cSandi/**
1342684e50aSAndreas Gohr * Build an string of URL parameters
1352684e50aSAndreas Gohr *
1362684e50aSAndreas Gohr * @author Andreas Gohr
1372684e50aSAndreas Gohr */
138b174aeaeSchrisfunction buildURLparams($params, $sep='&amp;'){
1392684e50aSAndreas Gohr  $url = '';
1402684e50aSAndreas Gohr  $amp = false;
1412684e50aSAndreas Gohr  foreach($params as $key => $val){
142b174aeaeSchris    if($amp) $url .= $sep;
1432684e50aSAndreas Gohr
1442684e50aSAndreas Gohr    $url .= $key.'=';
145b6c6979fSAndreas Gohr    $url .= rawurlencode($val);
1462684e50aSAndreas Gohr    $amp = true;
1472684e50aSAndreas Gohr  }
1482684e50aSAndreas Gohr  return $url;
1492684e50aSAndreas Gohr}
1502684e50aSAndreas Gohr
1512684e50aSAndreas Gohr/**
1522684e50aSAndreas Gohr * Build an string of html tag attributes
1532684e50aSAndreas Gohr *
154*7bff22c0SAndreas Gohr * Skips keys starting with '_', values get HTML encoded
155*7bff22c0SAndreas Gohr *
1562684e50aSAndreas Gohr * @author Andreas Gohr
1572684e50aSAndreas Gohr */
1582684e50aSAndreas Gohrfunction buildAttributes($params){
1592684e50aSAndreas Gohr  $url = '';
1602684e50aSAndreas Gohr  foreach($params as $key => $val){
161*7bff22c0SAndreas Gohr    if($key{0} == '_') continue;
162*7bff22c0SAndreas Gohr
1632684e50aSAndreas Gohr    $url .= $key.'="';
1642684e50aSAndreas Gohr    $url .= htmlspecialchars ($val);
1652684e50aSAndreas Gohr    $url .= '" ';
1662684e50aSAndreas Gohr  }
1672684e50aSAndreas Gohr  return $url;
1682684e50aSAndreas Gohr}
1692684e50aSAndreas Gohr
1702684e50aSAndreas Gohr
1712684e50aSAndreas Gohr/**
1720396becbSandi * print a message
1730396becbSandi *
1740396becbSandi * If HTTP headers were not sent yet the message is added
1750396becbSandi * to the global message array else it's printed directly
1760396becbSandi * using html_msgarea()
1770396becbSandi *
178f3f0262cSandi *
179f3f0262cSandi * Levels can be:
180f3f0262cSandi *
181f3f0262cSandi * -1 error
182f3f0262cSandi *  0 info
183f3f0262cSandi *  1 success
18415fae107Sandi *
18515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
1860396becbSandi * @see    html_msgarea
187f3f0262cSandi */
1880d58d74eSAndreas Gohrfunction msg($message,$lvl=0,$line='',$file=''){
189f3f0262cSandi  global $MSG;
190f3f0262cSandi  $errors[-1] = 'error';
191f3f0262cSandi  $errors[0]  = 'info';
192f3f0262cSandi  $errors[1]  = 'success';
193f3f0262cSandi
1940d58d74eSAndreas Gohr  if($line || $file) $message.=' ['.basename($file).':'.$line.']';
1950d58d74eSAndreas Gohr
196cc20ad51Sandi  if(!headers_sent()){
197f3f0262cSandi    if(!isset($MSG)) $MSG = array();
198f3f0262cSandi    $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message);
1990396becbSandi  }else{
2000396becbSandi    $MSG = array();
2010396becbSandi    $MSG[]=array('lvl' => $errors[$lvl], 'msg' => $message);
202f62ea8a1Sandi    if(function_exists('html_msgarea')){
2030396becbSandi      html_msgarea();
204f62ea8a1Sandi    }else{
205f62ea8a1Sandi      print "ERROR($lvl) $message";
206f62ea8a1Sandi    }
2070396becbSandi  }
208f3f0262cSandi}
209f3f0262cSandi
210f3f0262cSandi/**
21115fae107Sandi * This builds the breadcrumb trail and returns it as array
21215fae107Sandi *
21315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
214f3f0262cSandi */
215f3f0262cSandifunction breadcrumbs(){
2168746e727Sandi  // we prepare the breadcrumbs early for quick session closing
2178746e727Sandi  static $crumbs = null;
2188746e727Sandi  if($crumbs != null) return $crumbs;
2198746e727Sandi
220f3f0262cSandi  global $ID;
221f3f0262cSandi  global $ACT;
222f3f0262cSandi  global $conf;
223f3f0262cSandi  $crumbs = $_SESSION[$conf['title']]['bc'];
224f3f0262cSandi
225f3f0262cSandi  //first visit?
226f3f0262cSandi  if (!is_array($crumbs)){
227f3f0262cSandi    $crumbs = array();
228f3f0262cSandi  }
229f3f0262cSandi  //we only save on show and existing wiki documents
230a77f5846Sjan  $file = wikiFN($ID);
231a77f5846Sjan  if($ACT != 'show' || !@file_exists($file)){
232f3f0262cSandi    $_SESSION[$conf['title']]['bc'] = $crumbs;
233f3f0262cSandi    return $crumbs;
234f3f0262cSandi  }
235a77f5846Sjan
236a77f5846Sjan  // page names
237a77f5846Sjan  $name = noNS($ID);
238a77f5846Sjan  if ($conf['useheading']) {
239a77f5846Sjan    // get page title
240bb0a59d4Sjan    $title = p_get_first_heading($ID);
241a77f5846Sjan    if ($title) {
242a77f5846Sjan      $name = $title;
243a77f5846Sjan    }
244a77f5846Sjan  }
245a77f5846Sjan
246f3f0262cSandi  //remove ID from array
247a77f5846Sjan  if (isset($crumbs[$ID])) {
248a77f5846Sjan    unset($crumbs[$ID]);
249f3f0262cSandi  }
250f3f0262cSandi
251f3f0262cSandi  //add to array
252a77f5846Sjan  $crumbs[$ID] = $name;
253f3f0262cSandi  //reduce size
254f3f0262cSandi  while(count($crumbs) > $conf['breadcrumbs']){
255f3f0262cSandi    array_shift($crumbs);
256f3f0262cSandi  }
257f3f0262cSandi  //save to session
258f3f0262cSandi  $_SESSION[$conf['title']]['bc'] = $crumbs;
259f3f0262cSandi  return $crumbs;
260f3f0262cSandi}
261f3f0262cSandi
262f3f0262cSandi/**
26315fae107Sandi * Filter for page IDs
26415fae107Sandi *
265f3f0262cSandi * This is run on a ID before it is outputted somewhere
266f3f0262cSandi * currently used to replace the colon with something else
267f3f0262cSandi * on Windows systems and to have proper URL encoding
26815fae107Sandi *
26949c713a3Sandi * Urlencoding is ommitted when the second parameter is false
27049c713a3Sandi *
27115fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
272f3f0262cSandi */
27349c713a3Sandifunction idfilter($id,$ue=true){
274f3f0262cSandi  global $conf;
275f3f0262cSandi  if ($conf['useslash'] && $conf['userewrite']){
276f3f0262cSandi    $id = strtr($id,':','/');
277f3f0262cSandi  }elseif (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' &&
278f3f0262cSandi      $conf['userewrite']) {
279f3f0262cSandi    $id = strtr($id,':',';');
280f3f0262cSandi  }
28149c713a3Sandi  if($ue){
282b6c6979fSAndreas Gohr    $id = rawurlencode($id);
283f3f0262cSandi    $id = str_replace('%3A',':',$id); //keep as colon
284f3f0262cSandi    $id = str_replace('%2F','/',$id); //keep as slash
28549c713a3Sandi  }
286f3f0262cSandi  return $id;
287f3f0262cSandi}
288f3f0262cSandi
289f3f0262cSandi/**
290ed7b5f09Sandi * This builds a link to a wikipage
29115fae107Sandi *
2926c7843b5Sandi * It handles URL rewriting and adds additional parameter if
2936c7843b5Sandi * given in $more
2946c7843b5Sandi *
29515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
296f3f0262cSandi */
297b174aeaeSchrisfunction wl($id='',$more='',$abs=false,$sep='&amp;'){
298f3f0262cSandi  global $conf;
2996de3759aSAndreas Gohr  if(is_array($more)){
300b174aeaeSchris    $more = buildURLparams($more,$sep);
3016de3759aSAndreas Gohr  }else{
302b174aeaeSchris    $more = str_replace(',',$sep,$more);
3036de3759aSAndreas Gohr  }
304f3f0262cSandi
305f3f0262cSandi  $id    = idfilter($id);
306ed7b5f09Sandi  if($abs){
307ed7b5f09Sandi    $xlink = DOKU_URL;
308ed7b5f09Sandi  }else{
309ed7b5f09Sandi    $xlink = DOKU_BASE;
310ed7b5f09Sandi  }
311f3f0262cSandi
3126c7843b5Sandi  if($conf['userewrite'] == 2){
3136c7843b5Sandi    $xlink .= DOKU_SCRIPT.'/'.$id;
3146c7843b5Sandi    if($more) $xlink .= '?'.$more;
3156c7843b5Sandi  }elseif($conf['userewrite']){
316f3f0262cSandi    $xlink .= $id;
317f3f0262cSandi    if($more) $xlink .= '?'.$more;
3186c7843b5Sandi  }else{
3196c7843b5Sandi    $xlink .= DOKU_SCRIPT.'?id='.$id;
320b174aeaeSchris    if($more) $xlink .= $sep.$more;
321f3f0262cSandi  }
322f3f0262cSandi
323f3f0262cSandi  return $xlink;
324f3f0262cSandi}
325f3f0262cSandi
326f3f0262cSandi/**
327f5c2808fSBen Coburn * This builds a link to an alternate page format
328f5c2808fSBen Coburn *
329f5c2808fSBen Coburn * Handles URL rewriting if enabled. Follows the style of wl().
330f5c2808fSBen Coburn *
331f5c2808fSBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
332f5c2808fSBen Coburn */
333f5c2808fSBen Coburnfunction exportlink($id='',$format='raw',$more='',$abs=false,$sep='&amp;'){
334f5c2808fSBen Coburn  global $conf;
335f5c2808fSBen Coburn  if(is_array($more)){
336f5c2808fSBen Coburn    $more = buildURLparams($more,$sep);
337f5c2808fSBen Coburn  }else{
338f5c2808fSBen Coburn    $more = str_replace(',',$sep,$more);
339f5c2808fSBen Coburn  }
340f5c2808fSBen Coburn
341f5c2808fSBen Coburn  $format = rawurlencode($format);
342f5c2808fSBen Coburn  $id = idfilter($id);
343f5c2808fSBen Coburn  if($abs){
344f5c2808fSBen Coburn    $xlink = DOKU_URL;
345f5c2808fSBen Coburn  }else{
346f5c2808fSBen Coburn    $xlink = DOKU_BASE;
347f5c2808fSBen Coburn  }
348f5c2808fSBen Coburn
349f5c2808fSBen Coburn  if($conf['userewrite'] == 2){
350f5c2808fSBen Coburn    $xlink .= DOKU_SCRIPT.'/'.$id.'?do=export_'.$format;
351f5c2808fSBen Coburn    if($more) $xlink .= $sep.$more;
352f5c2808fSBen Coburn  }elseif($conf['userewrite'] == 1){
353f5c2808fSBen Coburn    $xlink .= '_export/'.$format.'/'.$id;
354f5c2808fSBen Coburn    if($more) $xlink .= '?'.$more;
355f5c2808fSBen Coburn  }else{
356f5c2808fSBen Coburn    $xlink .= DOKU_SCRIPT.'?do=export_'.$format.$sep.'id='.$id;
357f5c2808fSBen Coburn    if($more) $xlink .= $sep.$more;
358f5c2808fSBen Coburn  }
359f5c2808fSBen Coburn
360f5c2808fSBen Coburn  return $xlink;
361f5c2808fSBen Coburn}
362f5c2808fSBen Coburn
363f5c2808fSBen Coburn/**
3646de3759aSAndreas Gohr * Build a link to a media file
3656de3759aSAndreas Gohr *
3666de3759aSAndreas Gohr * Will return a link to the detail page if $direct is false
3676de3759aSAndreas Gohr */
368b174aeaeSchrisfunction ml($id='',$more='',$direct=true,$sep='&amp;'){
3696de3759aSAndreas Gohr  global $conf;
3706de3759aSAndreas Gohr  if(is_array($more)){
371b174aeaeSchris    $more = buildURLparams($more,$sep);
3726de3759aSAndreas Gohr  }else{
373b174aeaeSchris    $more = str_replace(',',$sep,$more);
3746de3759aSAndreas Gohr  }
3756de3759aSAndreas Gohr
3766de3759aSAndreas Gohr  $xlink = DOKU_BASE;
3776de3759aSAndreas Gohr
3786de3759aSAndreas Gohr  // external URLs are always direct without rewriting
3796de3759aSAndreas Gohr  if(preg_match('#^(https?|ftp)://#i',$id)){
3806de3759aSAndreas Gohr    $xlink .= 'lib/exe/fetch.php';
3816de3759aSAndreas Gohr    if($more){
3826de3759aSAndreas Gohr      $xlink .= '?'.$more;
383b174aeaeSchris      $xlink .= $sep.'media='.rawurlencode($id);
3846de3759aSAndreas Gohr    }else{
385b6c6979fSAndreas Gohr      $xlink .= '?media='.rawurlencode($id);
3866de3759aSAndreas Gohr    }
3876de3759aSAndreas Gohr    return $xlink;
3886de3759aSAndreas Gohr  }
3896de3759aSAndreas Gohr
3906de3759aSAndreas Gohr  $id = idfilter($id);
3916de3759aSAndreas Gohr
3926de3759aSAndreas Gohr  // decide on scriptname
3936de3759aSAndreas Gohr  if($direct){
3946de3759aSAndreas Gohr    if($conf['userewrite'] == 1){
3956de3759aSAndreas Gohr      $script = '_media';
3966de3759aSAndreas Gohr    }else{
3976de3759aSAndreas Gohr      $script = 'lib/exe/fetch.php';
3986de3759aSAndreas Gohr    }
3996de3759aSAndreas Gohr  }else{
4006de3759aSAndreas Gohr    if($conf['userewrite'] == 1){
4016de3759aSAndreas Gohr      $script = '_detail';
4026de3759aSAndreas Gohr    }else{
4036de3759aSAndreas Gohr      $script = 'lib/exe/detail.php';
4046de3759aSAndreas Gohr    }
4056de3759aSAndreas Gohr  }
4066de3759aSAndreas Gohr
4076de3759aSAndreas Gohr  // build URL based on rewrite mode
4086de3759aSAndreas Gohr   if($conf['userewrite']){
4096de3759aSAndreas Gohr     $xlink .= $script.'/'.$id;
4106de3759aSAndreas Gohr     if($more) $xlink .= '?'.$more;
4116de3759aSAndreas Gohr   }else{
4126de3759aSAndreas Gohr     if($more){
413a99d3236SEsther Brunner       $xlink .= $script.'?'.$more;
414b174aeaeSchris       $xlink .= $sep.'media='.$id;
4156de3759aSAndreas Gohr     }else{
416a99d3236SEsther Brunner       $xlink .= $script.'?media='.$id;
4176de3759aSAndreas Gohr     }
4186de3759aSAndreas Gohr   }
4196de3759aSAndreas Gohr
4206de3759aSAndreas Gohr  return $xlink;
4216de3759aSAndreas Gohr}
4226de3759aSAndreas Gohr
4236de3759aSAndreas Gohr
4246de3759aSAndreas Gohr
4256de3759aSAndreas Gohr/**
426f3f0262cSandi * Just builds a link to a script
42715fae107Sandi *
428ed7b5f09Sandi * @todo   maybe obsolete
42915fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
430f3f0262cSandi */
431f3f0262cSandifunction script($script='doku.php'){
432ed7b5f09Sandi#  $link = getBaseURL();
433ed7b5f09Sandi#  $link .= $script;
434ed7b5f09Sandi#  return $link;
435ed7b5f09Sandi  return DOKU_BASE.DOKU_SCRIPT;
436f3f0262cSandi}
437f3f0262cSandi
438f3f0262cSandi/**
43915fae107Sandi * Spamcheck against wordlist
44015fae107Sandi *
441f3f0262cSandi * Checks the wikitext against a list of blocked expressions
442f3f0262cSandi * returns true if the text contains any bad words
44315fae107Sandi *
44415fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
445f3f0262cSandi */
446f3f0262cSandifunction checkwordblock(){
447f3f0262cSandi  global $TEXT;
448f3f0262cSandi  global $conf;
449f3f0262cSandi
450f3f0262cSandi  if(!$conf['usewordblock']) return false;
451f3f0262cSandi
452b9ac8716Schris  $wordblocks = getWordblocks();
4533e2965d7Sandi  //how many lines to read at once (to work around some PCRE limits)
4543e2965d7Sandi  if(version_compare(phpversion(),'4.3.0','<')){
4553e2965d7Sandi    //old versions of PCRE define a maximum of parenthesises even if no
4563e2965d7Sandi    //backreferences are used - the maximum is 99
4573e2965d7Sandi    //this is very bad performancewise and may even be too high still
4583e2965d7Sandi    $chunksize = 40;
4593e2965d7Sandi  }else{
460703f6fdeSandi    //read file in chunks of 600 - this should work around the
4613e2965d7Sandi    //MAX_PATTERN_SIZE in modern PCRE
462444b87a5SAndreas Gohr    $chunksize = 400;
4633e2965d7Sandi  }
464b9ac8716Schris  while($blocks = array_splice($wordblocks,0,$chunksize)){
465f3f0262cSandi    $re = array();
466f3f0262cSandi    #build regexp from blocks
467f3f0262cSandi    foreach($blocks as $block){
468f3f0262cSandi      $block = preg_replace('/#.*$/','',$block);
469f3f0262cSandi      $block = trim($block);
470f3f0262cSandi      if(empty($block)) continue;
471f3f0262cSandi      $re[]  = $block;
472f3f0262cSandi    }
473b9ac8716Schris    if(preg_match('#('.join('|',$re).')#si',$TEXT, $match=array())) {
474b9ac8716Schris      return true;
475b9ac8716Schris    }
476703f6fdeSandi  }
477f3f0262cSandi  return false;
478f3f0262cSandi}
479f3f0262cSandi
480f3f0262cSandi/**
48115fae107Sandi * Return the IP of the client
48215fae107Sandi *
4836d8affe6SAndreas Gohr * Honours X-Forwarded-For and X-Real-IP Proxy Headers
48415fae107Sandi *
4856d8affe6SAndreas Gohr * It returns a comma separated list of IPs if the above mentioned
4866d8affe6SAndreas Gohr * headers are set. If the single parameter is set, it tries to return
4876d8affe6SAndreas Gohr * a routable public address, prefering the ones suplied in the X
4886d8affe6SAndreas Gohr * headers
4896d8affe6SAndreas Gohr *
4906d8affe6SAndreas Gohr * @param  boolean $single If set only a single IP is returned
49115fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
492f3f0262cSandi */
4936d8affe6SAndreas Gohrfunction clientIP($single=false){
4946d8affe6SAndreas Gohr  $ip = array();
4956d8affe6SAndreas Gohr  $ip[] = $_SERVER['REMOTE_ADDR'];
4966d8affe6SAndreas Gohr  if($_SERVER['HTTP_X_FORWARDED_FOR'])
4976d8affe6SAndreas Gohr    $ip = array_merge($ip,explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']));
4986d8affe6SAndreas Gohr  if($_SERVER['HTTP_X_REAL_IP'])
4996d8affe6SAndreas Gohr    $ip = array_merge($ip,explode(',',$_SERVER['HTTP_X_REAL_IP']));
5006d8affe6SAndreas Gohr
5016d8affe6SAndreas Gohr  // remove any non-IP stuff
5026d8affe6SAndreas Gohr  $cnt = count($ip);
5034ff28443Schris  $match = array();
5046d8affe6SAndreas Gohr  for($i=0; $i<$cnt; $i++){
5054ff28443Schris    if(preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/',$ip[$i],$match)) {
5064ff28443Schris      $ip[$i] = $match[0];
5074ff28443Schris    } else {
5084ff28443Schris      $ip[$i] = '';
5094ff28443Schris    }
5106d8affe6SAndreas Gohr    if(empty($ip[$i])) unset($ip[$i]);
511f3f0262cSandi  }
5126d8affe6SAndreas Gohr  $ip = array_values(array_unique($ip));
5136d8affe6SAndreas Gohr  if(!$ip[0]) $ip[0] = '0.0.0.0'; // for some strange reason we don't have a IP
5146d8affe6SAndreas Gohr
5156d8affe6SAndreas Gohr  if(!$single) return join(',',$ip);
5166d8affe6SAndreas Gohr
5176d8affe6SAndreas Gohr  // decide which IP to use, trying to avoid local addresses
5186d8affe6SAndreas Gohr  $ip = array_reverse($ip);
5196d8affe6SAndreas Gohr  foreach($ip as $i){
5206d8affe6SAndreas Gohr    if(preg_match('/^(127\.|10\.|192\.168\.|172\.((1[6-9])|(2[0-9])|(3[0-1]))\.)/',$i)){
5216d8affe6SAndreas Gohr      continue;
5226d8affe6SAndreas Gohr    }else{
5236d8affe6SAndreas Gohr      return $i;
5246d8affe6SAndreas Gohr    }
5256d8affe6SAndreas Gohr  }
5266d8affe6SAndreas Gohr  // still here? just use the first (last) address
5276d8affe6SAndreas Gohr  return $ip[0];
528f3f0262cSandi}
529f3f0262cSandi
530f3f0262cSandi/**
53115fae107Sandi * Checks if a given page is currently locked.
53215fae107Sandi *
533f3f0262cSandi * removes stale lockfiles
53415fae107Sandi *
53515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
536f3f0262cSandi */
537f3f0262cSandifunction checklock($id){
538f3f0262cSandi  global $conf;
539c9b4bd1eSBen Coburn  $lock = wikiLockFN($id);
540f3f0262cSandi
541f3f0262cSandi  //no lockfile
542f3f0262cSandi  if(!@file_exists($lock)) return false;
543f3f0262cSandi
544f3f0262cSandi  //lockfile expired
545f3f0262cSandi  if((time() - filemtime($lock)) > $conf['locktime']){
546d8186216SBen Coburn    @unlink($lock);
547f3f0262cSandi    return false;
548f3f0262cSandi  }
549f3f0262cSandi
550f3f0262cSandi  //my own lock
551f3f0262cSandi  $ip = io_readFile($lock);
552f3f0262cSandi  if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){
553f3f0262cSandi    return false;
554f3f0262cSandi  }
555f3f0262cSandi
556f3f0262cSandi  return $ip;
557f3f0262cSandi}
558f3f0262cSandi
559f3f0262cSandi/**
56015fae107Sandi * Lock a page for editing
56115fae107Sandi *
56215fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
563f3f0262cSandi */
564f3f0262cSandifunction lock($id){
565c9b4bd1eSBen Coburn  $lock = wikiLockFN($id);
566f3f0262cSandi  if($_SERVER['REMOTE_USER']){
567f3f0262cSandi    io_saveFile($lock,$_SERVER['REMOTE_USER']);
568f3f0262cSandi  }else{
569f3f0262cSandi    io_saveFile($lock,clientIP());
570f3f0262cSandi  }
571f3f0262cSandi}
572f3f0262cSandi
573f3f0262cSandi/**
57415fae107Sandi * Unlock a page if it was locked by the user
575f3f0262cSandi *
57615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
57715fae107Sandi * @return bool true if a lock was removed
578f3f0262cSandi */
579f3f0262cSandifunction unlock($id){
580c9b4bd1eSBen Coburn  $lock = wikiLockFN($id);
581f3f0262cSandi  if(@file_exists($lock)){
582f3f0262cSandi    $ip = io_readFile($lock);
583f3f0262cSandi    if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){
584f3f0262cSandi      @unlink($lock);
585f3f0262cSandi      return true;
586f3f0262cSandi    }
587f3f0262cSandi  }
588f3f0262cSandi  return false;
589f3f0262cSandi}
590f3f0262cSandi
591f3f0262cSandi/**
592f3f0262cSandi * convert line ending to unix format
593f3f0262cSandi *
59415fae107Sandi * @see    formText() for 2crlf conversion
59515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
596f3f0262cSandi */
597f3f0262cSandifunction cleanText($text){
598f3f0262cSandi  $text = preg_replace("/(\015\012)|(\015)/","\012",$text);
599f3f0262cSandi  return $text;
600f3f0262cSandi}
601f3f0262cSandi
602f3f0262cSandi/**
603f3f0262cSandi * Prepares text for print in Webforms by encoding special chars.
604f3f0262cSandi * It also converts line endings to Windows format which is
605f3f0262cSandi * pseudo standard for webforms.
606f3f0262cSandi *
60715fae107Sandi * @see    cleanText() for 2unix conversion
60815fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
609f3f0262cSandi */
610f3f0262cSandifunction formText($text){
611f3f0262cSandi  $text = preg_replace("/\012/","\015\012",$text);
612f3f0262cSandi  return htmlspecialchars($text);
613f3f0262cSandi}
614f3f0262cSandi
615f3f0262cSandi/**
61615fae107Sandi * Returns the specified local text in raw format
61715fae107Sandi *
61815fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
619f3f0262cSandi */
620f3f0262cSandifunction rawLocale($id){
621f3f0262cSandi  return io_readFile(localeFN($id));
622f3f0262cSandi}
623f3f0262cSandi
624f3f0262cSandi/**
625f3f0262cSandi * Returns the raw WikiText
62615fae107Sandi *
62715fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
628f3f0262cSandi */
629f3f0262cSandifunction rawWiki($id,$rev=''){
630cc7d0c94SBen Coburn  return io_readWikiPage(wikiFN($id, $rev), $id, $rev);
631f3f0262cSandi}
632f3f0262cSandi
633f3f0262cSandi/**
6347146cee2SAndreas Gohr * Returns the pagetemplate contents for the ID's namespace
6357146cee2SAndreas Gohr *
6367146cee2SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
6377146cee2SAndreas Gohr */
638b7d5a5f0SAndreas Gohrfunction pageTemplate($data){
639b7d5a5f0SAndreas Gohr  $id = $data[0];
640a15ce62dSEsther Brunner  global $conf;
641a15ce62dSEsther Brunner  global $INFO;
642a15ce62dSEsther Brunner  $tpl = io_readFile(dirname(wikiFN($id)).'/_template.txt');
643a15ce62dSEsther Brunner  $tpl = str_replace('@ID@',$id,$tpl);
644a15ce62dSEsther Brunner  $tpl = str_replace('@NS@',getNS($id),$tpl);
645a15ce62dSEsther Brunner  $tpl = str_replace('@PAGE@',strtr(noNS($id),'_',' '),$tpl);
646a15ce62dSEsther Brunner  $tpl = str_replace('@USER@',$_SERVER['REMOTE_USER'],$tpl);
647a15ce62dSEsther Brunner  $tpl = str_replace('@NAME@',$INFO['userinfo']['name'],$tpl);
648a15ce62dSEsther Brunner  $tpl = str_replace('@MAIL@',$INFO['userinfo']['mail'],$tpl);
649a15ce62dSEsther Brunner  $tpl = str_replace('@DATE@',date($conf['dformat']),$tpl);
650a15ce62dSEsther Brunner  return $tpl;
6517146cee2SAndreas Gohr}
6527146cee2SAndreas Gohr
6537146cee2SAndreas Gohr
6547146cee2SAndreas Gohr/**
65515fae107Sandi * Returns the raw Wiki Text in three slices.
65615fae107Sandi *
65715fae107Sandi * The range parameter needs to have the form "from-to"
65815cfe303Sandi * and gives the range of the section in bytes - no
65915cfe303Sandi * UTF-8 awareness is needed.
660f3f0262cSandi * The returned order is prefix, section and suffix.
66115fae107Sandi *
66215fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
663f3f0262cSandi */
664f3f0262cSandifunction rawWikiSlices($range,$id,$rev=''){
665f3f0262cSandi  list($from,$to) = split('-',$range,2);
666cc7d0c94SBen Coburn  $text = io_readWikiPage(wikiFN($id, $rev), $id, $rev);
667f3f0262cSandi  if(!$from) $from = 0;
668c3d8e19bSandi  if(!$to)   $to   = strlen($text)+1;
669f3f0262cSandi
67015cfe303Sandi  $slices[0] = substr($text,0,$from-1);
67115cfe303Sandi  $slices[1] = substr($text,$from-1,$to-$from);
67215cfe303Sandi  $slices[2] = substr($text,$to);
673f3f0262cSandi
674f3f0262cSandi  return $slices;
675f3f0262cSandi}
676f3f0262cSandi
677f3f0262cSandi/**
67815fae107Sandi * Joins wiki text slices
67915fae107Sandi *
680f3f0262cSandi * function to join the text slices with correct lineendings again.
681f3f0262cSandi * When the pretty parameter is set to true it adds additional empty
682f3f0262cSandi * lines between sections if needed (used on saving).
68315fae107Sandi *
68415fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
685f3f0262cSandi */
686f3f0262cSandifunction con($pre,$text,$suf,$pretty=false){
687f3f0262cSandi
688f3f0262cSandi  if($pretty){
689f3f0262cSandi    if($pre && substr($pre,-1) != "\n") $pre .= "\n";
690f3f0262cSandi    if($suf && substr($text,-1) != "\n") $text .= "\n";
691f3f0262cSandi  }
692f3f0262cSandi
693f3f0262cSandi  if($pre) $pre .= "\n";
694f3f0262cSandi  if($suf) $text .= "\n";
695f3f0262cSandi  return $pre.$text.$suf;
696f3f0262cSandi}
697f3f0262cSandi
698f3f0262cSandi/**
69915fae107Sandi * print debug messages
70015fae107Sandi *
701f3f0262cSandi * little function to print the content of a var
70215fae107Sandi *
70315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
704f3f0262cSandi */
705f3f0262cSandifunction dbg($msg,$hidden=false){
706f3f0262cSandi  (!$hidden) ? print '<pre class="dbg">' : print "<!--\n";
707f3f0262cSandi  print_r($msg);
708f3f0262cSandi  (!$hidden) ? print '</pre>' : print "\n-->";
709f3f0262cSandi}
710f3f0262cSandi
711f3f0262cSandi/**
71263cb5853SAndreas Gohr * Print info to a log file
71363cb5853SAndreas Gohr *
71463cb5853SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
71563cb5853SAndreas Gohr */
71663cb5853SAndreas Gohrfunction dbglog($msg){
71763cb5853SAndreas Gohr  global $conf;
71863cb5853SAndreas Gohr  $file = $conf['cachedir'].'/debug.log';
71963cb5853SAndreas Gohr  $fh = fopen($file,'a');
72063cb5853SAndreas Gohr  if($fh){
72163cb5853SAndreas Gohr    fwrite($fh,date('H:i:s ').$_SERVER['REMOTE_ADDR'].': '.$msg."\n");
72263cb5853SAndreas Gohr    fclose($fh);
72363cb5853SAndreas Gohr  }
72463cb5853SAndreas Gohr}
72563cb5853SAndreas Gohr
72663cb5853SAndreas Gohr/**
727cc7d0c94SBen Coburn * Saves a wikitext by calling io_writeWikiPage
72815fae107Sandi *
72915fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
73071726d78SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
731f3f0262cSandi */
732b6912aeaSAndreas Gohrfunction saveWikiText($id,$text,$summary,$minor=false){
733f3f0262cSandi  global $conf;
734f3f0262cSandi  global $lang;
73571726d78SBen Coburn  global $REV;
736f3f0262cSandi  // ignore if no changes were made
737f3f0262cSandi  if($text == rawWiki($id,'')){
738f3f0262cSandi    return;
739f3f0262cSandi  }
740f3f0262cSandi
741f3f0262cSandi  $file = wikiFN($id);
742f3f0262cSandi  $old  = saveOldRevision($id);
74371726d78SBen Coburn  $wasRemoved = empty($text);
744d8186216SBen Coburn  $wasCreated = !@file_exists($file);
74571726d78SBen Coburn  $wasReverted = ($REV==true);
746e45b34cdSBen Coburn  $newRev = false;
747f3f0262cSandi
74871726d78SBen Coburn  if ($wasRemoved){
749e45b34cdSBen Coburn    // pre-save deleted revision
750e45b34cdSBen Coburn    @touch($file);
751e45b34cdSBen Coburn    $newRev = saveOldRevision($id);
752e1f3d9e1SEsther Brunner    // remove empty file
753f3f0262cSandi    @unlink($file);
75471726d78SBen Coburn    // remove old meta info...
755e1f3d9e1SEsther Brunner    $mfiles = metaFiles($id);
75671726d78SBen Coburn    $changelog = metaFN($id, '.changes');
757e1f3d9e1SEsther Brunner    foreach ($mfiles as $mfile) {
75871726d78SBen Coburn      // but keep per-page changelog to preserve page history
759d8186216SBen Coburn      if (@file_exists($mfile) && $mfile!==$changelog) { @unlink($mfile); }
760b158d625SSteven Danz    }
761f3f0262cSandi    $del = true;
7623ce054b3Sandi    // autoset summary on deletion
7633ce054b3Sandi    if(empty($summary)) $summary = $lang['deleted'];
76453d6ccfeSandi    // remove empty namespaces
765cc7d0c94SBen Coburn    io_sweepNS($id, 'datadir');
766cc7d0c94SBen Coburn    io_sweepNS($id, 'mediadir');
767f3f0262cSandi  }else{
768cc7d0c94SBen Coburn    // save file (namespace dir is created in io_writeWikiPage)
769cc7d0c94SBen Coburn    io_writeWikiPage($file, $text, $id);
770e45b34cdSBen Coburn    $newRev = @filemtime($file);
771f3f0262cSandi    $del = false;
772f3f0262cSandi  }
773f3f0262cSandi
77471726d78SBen Coburn  // select changelog line type
77571726d78SBen Coburn  $extra = '';
77671726d78SBen Coburn  $type = 'E';
77771726d78SBen Coburn  if ($wasReverted) {
77871726d78SBen Coburn    $type = 'R';
77971726d78SBen Coburn    $extra = $REV;
78071726d78SBen Coburn  }
78171726d78SBen Coburn  else if ($wasCreated) { $type = 'C'; }
78271726d78SBen Coburn  else if ($wasRemoved) { $type = 'D'; }
78371726d78SBen Coburn  else if ($minor && $conf['useacl'] && $_SERVER['REMOTE_USER']) { $type = 'e'; } //minor edits only for logged in users
78471726d78SBen Coburn
785e45b34cdSBen Coburn  addLogEntry($newRev, $id, $type, $summary, $extra);
78626a0801fSAndreas Gohr  // send notify mails
78790033e9dSAndreas Gohr  notify($id,'admin',$old,$summary,$minor);
78890033e9dSAndreas Gohr  notify($id,'subscribers',$old,$summary,$minor);
789f3f0262cSandi
790f3f0262cSandi  //purge cache on add by updating the purgefile
791f3f0262cSandi  if($conf['purgeonadd'] && (!$old || $del)){
79298407a7aSandi    io_saveFile($conf['cachedir'].'/purgefile',time());
793f3f0262cSandi  }
794f3f0262cSandi}
795f3f0262cSandi
796f3f0262cSandi/**
797f3f0262cSandi * moves the current version to the attic and returns its
798f3f0262cSandi * revision date
79915fae107Sandi *
80015fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
801f3f0262cSandi */
802f3f0262cSandifunction saveOldRevision($id){
803f3f0262cSandi  global $conf;
804f3f0262cSandi  $oldf = wikiFN($id);
805f3f0262cSandi  if(!@file_exists($oldf)) return '';
806f3f0262cSandi  $date = filemtime($oldf);
807f3f0262cSandi  $newf = wikiFN($id,$date);
808cc7d0c94SBen Coburn  io_writeWikiPage($newf, rawWiki($id), $id, $date);
809f3f0262cSandi  return $date;
810f3f0262cSandi}
811f3f0262cSandi
812f3f0262cSandi/**
81326a0801fSAndreas Gohr * Sends a notify mail on page change
81426a0801fSAndreas Gohr *
81526a0801fSAndreas Gohr * @param  string  $id       The changed page
81626a0801fSAndreas Gohr * @param  string  $who      Who to notify (admin|subscribers)
81726a0801fSAndreas Gohr * @param  int     $rev      Old page revision
81826a0801fSAndreas Gohr * @param  string  $summary  What changed
81990033e9dSAndreas Gohr * @param  boolean $minor    Is this a minor edit?
82002a498e7Schris * @param  array   $replace  Additional string substitutions, @KEY@ to be replaced by value
82115fae107Sandi *
82215fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
823f3f0262cSandi */
82402a498e7Schrisfunction notify($id,$who,$rev='',$summary='',$minor=false,$replace=array()){
825f3f0262cSandi  global $lang;
826f3f0262cSandi  global $conf;
827b158d625SSteven Danz
82826a0801fSAndreas Gohr  // decide if there is something to do
82926a0801fSAndreas Gohr  if($who == 'admin'){
83026a0801fSAndreas Gohr    if(empty($conf['notify'])) return; //notify enabled?
831f3f0262cSandi    $text = rawLocale('mailtext');
83226a0801fSAndreas Gohr    $to   = $conf['notify'];
83326a0801fSAndreas Gohr    $bcc  = '';
83426a0801fSAndreas Gohr  }elseif($who == 'subscribers'){
83526a0801fSAndreas Gohr    if(!$conf['subscribers']) return; //subscribers enabled?
83690033e9dSAndreas Gohr    if($conf['useacl'] && $_SERVER['REMOTE_USER'] && $minor) return; //skip minors
83726a0801fSAndreas Gohr    $bcc  = subscriber_addresslist($id);
83826a0801fSAndreas Gohr    if(empty($bcc)) return;
83926a0801fSAndreas Gohr    $to   = '';
84026a0801fSAndreas Gohr    $text = rawLocale('subscribermail');
841a06e4bdbSSebastian Harl  }elseif($who == 'register'){
842a06e4bdbSSebastian Harl    if(empty($conf['registernotify'])) return;
843a06e4bdbSSebastian Harl    $text = rawLocale('registermail');
844a06e4bdbSSebastian Harl    $to   = $conf['registernotify'];
845a06e4bdbSSebastian Harl    $bcc  = '';
84626a0801fSAndreas Gohr  }else{
84726a0801fSAndreas Gohr    return; //just to be safe
84826a0801fSAndreas Gohr  }
84926a0801fSAndreas Gohr
850f3f0262cSandi  $text = str_replace('@DATE@',date($conf['dformat']),$text);
851f3f0262cSandi  $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text);
852f3f0262cSandi  $text = str_replace('@IPADDRESS@',$_SERVER['REMOTE_ADDR'],$text);
853f3f0262cSandi  $text = str_replace('@HOSTNAME@',gethostbyaddr($_SERVER['REMOTE_ADDR']),$text);
854ed7b5f09Sandi  $text = str_replace('@NEWPAGE@',wl($id,'',true),$text);
85526a0801fSAndreas Gohr  $text = str_replace('@PAGE@',$id,$text);
85626a0801fSAndreas Gohr  $text = str_replace('@TITLE@',$conf['title'],$text);
857ed7b5f09Sandi  $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text);
858f3f0262cSandi  $text = str_replace('@SUMMARY@',$summary,$text);
8597a82afdcSandi  $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text);
860f3f0262cSandi
86102a498e7Schris  foreach ($replace as $key => $substitution) {
86202a498e7Schris    $text = str_replace('@'.strtoupper($key).'@',$substitution, $text);
86302a498e7Schris  }
86402a498e7Schris
865a06e4bdbSSebastian Harl  if($who == 'register'){
866a06e4bdbSSebastian Harl    $subject = $lang['mail_new_user'].' '.$summary;
867a06e4bdbSSebastian Harl  }elseif($rev){
868f3f0262cSandi    $subject = $lang['mail_changed'].' '.$id;
869ed7b5f09Sandi    $text = str_replace('@OLDPAGE@',wl($id,"rev=$rev",true),$text);
870ccdfa6c0SAndreas Gohr    require_once(DOKU_INC.'inc/DifferenceEngine.php');
871f3f0262cSandi    $df  = new Diff(split("\n",rawWiki($id,$rev)),
872f3f0262cSandi                    split("\n",rawWiki($id)));
873f3f0262cSandi    $dformat = new UnifiedDiffFormatter();
874f3f0262cSandi    $diff    = $dformat->format($df);
875f3f0262cSandi  }else{
876f3f0262cSandi    $subject=$lang['mail_newpage'].' '.$id;
877f3f0262cSandi    $text = str_replace('@OLDPAGE@','none',$text);
878f3f0262cSandi    $diff = rawWiki($id);
879f3f0262cSandi  }
880f3f0262cSandi  $text = str_replace('@DIFF@',$diff,$text);
881241f3a36Sandi  $subject = '['.$conf['title'].'] '.$subject;
882f3f0262cSandi
88326a0801fSAndreas Gohr  mail_send($to,$subject,$text,$conf['mailfrom'],'',$bcc);
884f3f0262cSandi}
885f3f0262cSandi
88615fae107Sandi/**
887f3f0262cSandi * extracts the query from a google referer
88815fae107Sandi *
8896b13307fSandi * @todo   should be more generic and support yahoo et al
89015fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
891f3f0262cSandi */
892f3f0262cSandifunction getGoogleQuery(){
893f3f0262cSandi  $url = parse_url($_SERVER['HTTP_REFERER']);
8945c3f206fSandi  if(!$url) return '';
895f3f0262cSandi
896f3f0262cSandi  if(!preg_match("#google\.#i",$url['host'])) return '';
897f3f0262cSandi  $query = array();
898f3f0262cSandi  parse_str($url['query'],$query);
899f3f0262cSandi
900f3f0262cSandi  return $query['q'];
901f3f0262cSandi}
902f3f0262cSandi
903f3f0262cSandi/**
90415fae107Sandi * Try to set correct locale
90515fae107Sandi *
906095bfd5cSandi * @deprecated No longer used
90715fae107Sandi * @author     Andreas Gohr <andi@splitbrain.org>
908f3f0262cSandi */
909f3f0262cSandifunction setCorrectLocale(){
910f3f0262cSandi  global $conf;
911f3f0262cSandi  global $lang;
912f3f0262cSandi
913f3f0262cSandi  $enc = strtoupper($lang['encoding']);
914f3f0262cSandi  foreach ($lang['locales'] as $loc){
915f3f0262cSandi    //try locale
916f3f0262cSandi    if(@setlocale(LC_ALL,$loc)) return;
917f3f0262cSandi    //try loceale with encoding
918f3f0262cSandi    if(@setlocale(LC_ALL,"$loc.$enc")) return;
919f3f0262cSandi  }
920f3f0262cSandi  //still here? try to set from environment
921f3f0262cSandi  @setlocale(LC_ALL,"");
922f3f0262cSandi}
923f3f0262cSandi
924f3f0262cSandi/**
925f3f0262cSandi * Return the human readable size of a file
926f3f0262cSandi *
927f3f0262cSandi * @param       int    $size   A file size
928f3f0262cSandi * @param       int    $dec    A number of decimal places
929f3f0262cSandi * @author      Martin Benjamin <b.martin@cybernet.ch>
930f3f0262cSandi * @author      Aidan Lister <aidan@php.net>
931f3f0262cSandi * @version     1.0.0
932f3f0262cSandi */
933f31d5b73Sandifunction filesize_h($size, $dec = 1){
934f3f0262cSandi  $sizes = array('B', 'KB', 'MB', 'GB');
935f3f0262cSandi  $count = count($sizes);
936f3f0262cSandi  $i = 0;
937f3f0262cSandi
938f3f0262cSandi  while ($size >= 1024 && ($i < $count - 1)) {
939f3f0262cSandi    $size /= 1024;
940f3f0262cSandi    $i++;
941f3f0262cSandi  }
942f3f0262cSandi
943f3f0262cSandi  return round($size, $dec) . ' ' . $sizes[$i];
944f3f0262cSandi}
945f3f0262cSandi
94615fae107Sandi/**
94700a7b5adSEsther Brunner * return an obfuscated email address in line with $conf['mailguard'] setting
94800a7b5adSEsther Brunner *
94900a7b5adSEsther Brunner * @author Harry Fuecks <hfuecks@gmail.com>
95000a7b5adSEsther Brunner * @author Christopher Smith <chris@jalakai.co.uk>
95100a7b5adSEsther Brunner */
95200a7b5adSEsther Brunnerfunction obfuscate($email) {
95300a7b5adSEsther Brunner  global $conf;
95400a7b5adSEsther Brunner
95500a7b5adSEsther Brunner  switch ($conf['mailguard']) {
95600a7b5adSEsther Brunner    case 'visible' :
95700a7b5adSEsther Brunner      $obfuscate = array('@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] ');
95800a7b5adSEsther Brunner      return strtr($email, $obfuscate);
95900a7b5adSEsther Brunner
96000a7b5adSEsther Brunner    case 'hex' :
96100a7b5adSEsther Brunner      $encode = '';
96200a7b5adSEsther Brunner      for ($x=0; $x < strlen($email); $x++) $encode .= '&#x' . bin2hex($email{$x}).';';
96300a7b5adSEsther Brunner      return $encode;
96400a7b5adSEsther Brunner
96500a7b5adSEsther Brunner    case 'none' :
96600a7b5adSEsther Brunner    default :
96700a7b5adSEsther Brunner      return $email;
96800a7b5adSEsther Brunner  }
96900a7b5adSEsther Brunner}
97000a7b5adSEsther Brunner
97100a7b5adSEsther Brunner/**
972dc57ef04Sandi * Return DokuWikis version
97315fae107Sandi *
97415fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
97515fae107Sandi */
976f31d5b73Sandifunction getVersion(){
977f31d5b73Sandi  //import version string
978f31d5b73Sandi  if(@file_exists('VERSION')){
979f31d5b73Sandi    //official release
9800647ce3bSAndreas Gohr    return 'Release '.trim(io_readfile(DOKU_INC.'/VERSION'));
981f31d5b73Sandi  }elseif(is_dir('_darcs')){
982f31d5b73Sandi    //darcs checkout
983f31d5b73Sandi    $inv = file('_darcs/inventory');
984ae41559bSAndreas Gohr    $inv = preg_grep('#\*\*\d{14}[\]$]#',$inv);
985f31d5b73Sandi    $cur = array_pop($inv);
986f31d5b73Sandi    preg_match('#\*\*(\d{4})(\d{2})(\d{2})#',$cur,$matches);
987f31d5b73Sandi    return 'Darcs '.$matches[1].'-'.$matches[2].'-'.$matches[3];
988f31d5b73Sandi  }else{
989f31d5b73Sandi    return 'snapshot?';
990f31d5b73Sandi  }
991f31d5b73Sandi}
992f31d5b73Sandi
993f31d5b73Sandi/**
994f31d5b73Sandi * Run a few sanity checks
995f31d5b73Sandi *
996f31d5b73Sandi * @author Andreas Gohr <andi@splitbrain.org>
997f31d5b73Sandi */
998f3f0262cSandifunction check(){
999f3f0262cSandi  global $conf;
1000f3f0262cSandi  global $INFO;
1001f3f0262cSandi
1002f31d5b73Sandi  msg('DokuWiki version: '.getVersion(),1);
1003f31d5b73Sandi
100449022a38Sandi  if(version_compare(phpversion(),'4.3.0','<')){
100549022a38Sandi    msg('Your PHP version is too old ('.phpversion().' vs. 4.3.+ recommended)',-1);
100649022a38Sandi  }elseif(version_compare(phpversion(),'4.3.10','<')){
100749022a38Sandi    msg('Consider upgrading PHP to 4.3.10 or higher for security reasons (your version: '.phpversion().')',0);
100849022a38Sandi  }else{
100949022a38Sandi    msg('PHP version '.phpversion(),1);
101049022a38Sandi  }
101149022a38Sandi
1012f3f0262cSandi  if(is_writable($conf['changelog'])){
1013f3f0262cSandi    msg('Changelog is writable',1);
1014f3f0262cSandi  }else{
1015d8186216SBen Coburn    if (@file_exists($conf['changelog'])) {
1016f3f0262cSandi      msg('Changelog is not writable',-1);
1017f3f0262cSandi    }
101871726d78SBen Coburn  }
101971726d78SBen Coburn
1020d8186216SBen Coburn  if (isset($conf['changelog_old']) && @file_exists($conf['changelog_old'])) {
102171726d78SBen Coburn    msg('Old changelog exists.', 0);
102271726d78SBen Coburn  }
102371726d78SBen Coburn
1024d8186216SBen Coburn  if (@file_exists($conf['changelog'].'_failed')) {
102571726d78SBen Coburn    msg('Importing old changelog failed.', -1);
1026d8186216SBen Coburn  } else if (@file_exists($conf['changelog'].'_importing')) {
102771726d78SBen Coburn    msg('Importing old changelog now.', 0);
1028d8186216SBen Coburn  } else if (@file_exists($conf['changelog'].'_import_ok')) {
102971726d78SBen Coburn    msg('Old changelog imported.', 1);
1030e45b34cdSBen Coburn    if (!plugin_isdisabled('importoldchangelog')) {
1031e45b34cdSBen Coburn      msg('Importoldchangelog plugin not disabled after import.', -1);
1032e45b34cdSBen Coburn    }
103371726d78SBen Coburn  }
1034f3f0262cSandi
1035f3f0262cSandi  if(is_writable($conf['datadir'])){
1036f3f0262cSandi    msg('Datadir is writable',1);
1037f3f0262cSandi  }else{
1038f3f0262cSandi    msg('Datadir is not writable',-1);
1039f3f0262cSandi  }
1040f3f0262cSandi
1041f3f0262cSandi  if(is_writable($conf['olddir'])){
1042f3f0262cSandi    msg('Attic is writable',1);
1043f3f0262cSandi  }else{
1044f3f0262cSandi    msg('Attic is not writable',-1);
1045f3f0262cSandi  }
1046f3f0262cSandi
1047f3f0262cSandi  if(is_writable($conf['mediadir'])){
1048f3f0262cSandi    msg('Mediadir is writable',1);
1049f3f0262cSandi  }else{
1050f3f0262cSandi    msg('Mediadir is not writable',-1);
1051f3f0262cSandi  }
1052f3f0262cSandi
105398407a7aSandi  if(is_writable($conf['cachedir'])){
105498407a7aSandi    msg('Cachedir is writable',1);
105598407a7aSandi  }else{
105698407a7aSandi    msg('Cachedir is not writable',-1);
105798407a7aSandi  }
105898407a7aSandi
10597de6c234SAndreas Gohr  if(is_writable($conf['lockdir'])){
10607de6c234SAndreas Gohr    msg('Lockdir is writable',1);
10617de6c234SAndreas Gohr  }else{
10627de6c234SAndreas Gohr    msg('Lockdir is not writable',-1);
10637de6c234SAndreas Gohr  }
10647de6c234SAndreas Gohr
1065e7cb32dcSAndreas Gohr  if(is_writable(DOKU_CONF.'users.auth.php')){
10668c4f28e8Sjan    msg('conf/users.auth.php is writable',1);
1067f3f0262cSandi  }else{
10688c4f28e8Sjan    msg('conf/users.auth.php is not writable',0);
1069f3f0262cSandi  }
107093a9e835Sandi
107193a9e835Sandi  if(function_exists('mb_strpos')){
107293a9e835Sandi    if(defined('UTF8_NOMBSTRING')){
107393a9e835Sandi      msg('mb_string extension is available but will not be used',0);
107493a9e835Sandi    }else{
107593a9e835Sandi      msg('mb_string extension is available and will be used',1);
107693a9e835Sandi    }
107793a9e835Sandi  }else{
107893a9e835Sandi    msg('mb_string extension not available - PHP only replacements will be used',0);
107993a9e835Sandi  }
1080f42d1c75SAndreas Gohr
1081f42d1c75SAndreas Gohr  if($conf['allowdebug']){
1082f42d1c75SAndreas Gohr    msg('Debugging support is enabled. If you don\'t need it you should set $conf[\'allowdebug\'] = 0',-1);
1083f42d1c75SAndreas Gohr  }else{
1084f42d1c75SAndreas Gohr    msg('Debugging support is disabled',1);
1085f42d1c75SAndreas Gohr  }
1086f3f0262cSandi
1087f3f0262cSandi  msg('Your current permission for this page is '.$INFO['perm'],0);
1088f3f0262cSandi
1089f3f0262cSandi  if(is_writable($INFO['filepath'])){
1090f3f0262cSandi    msg('The current page is writable by the webserver',0);
1091f3f0262cSandi  }else{
1092f3f0262cSandi    msg('The current page is not writable by the webserver',0);
1093f3f0262cSandi  }
1094f3f0262cSandi
1095f3f0262cSandi  if($INFO['writable']){
1096f3f0262cSandi    msg('The current page is writable by you',0);
1097f3f0262cSandi  }else{
1098f3f0262cSandi    msg('The current page is not writable you',0);
1099f3f0262cSandi  }
1100f3f0262cSandi}
1101340756e4Sandi
1102b158d625SSteven Danz/**
1103b158d625SSteven Danz * Let us know if a user is tracking a page
1104b158d625SSteven Danz *
11051380fc45SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
1106b158d625SSteven Danz */
11071380fc45SAndreas Gohrfunction is_subscribed($id,$uid){
11081380fc45SAndreas Gohr  $file=metaFN($id,'.mlist');
11091380fc45SAndreas Gohr  if (@file_exists($file)) {
1110b158d625SSteven Danz    $mlist = file($file);
11111380fc45SAndreas Gohr    $pos = array_search($uid."\n",$mlist);
11121380fc45SAndreas Gohr    return is_int($pos);
1113b158d625SSteven Danz  }
11141380fc45SAndreas Gohr
1115b158d625SSteven Danz  return false;
1116b158d625SSteven Danz}
1117340756e4Sandi
1118f9eb5648Ssteven-danz/**
1119f9eb5648Ssteven-danz * Return a string with the email addresses of all the
1120f9eb5648Ssteven-danz * users subscribed to a page
1121f9eb5648Ssteven-danz *
112226a0801fSAndreas Gohr * @author Steven Danz <steven-danz@kc.rr.com>
1123f9eb5648Ssteven-danz */
1124f9eb5648Ssteven-danzfunction subscriber_addresslist($id){
1125f9eb5648Ssteven-danz  global $conf;
1126cd52f92dSchris  global $auth;
1127f9eb5648Ssteven-danz
1128f9eb5648Ssteven-danz  $emails = '';
1129f9eb5648Ssteven-danz
113026a0801fSAndreas Gohr  if (!$conf['subscribers']) return;
113126a0801fSAndreas Gohr
1132f9eb5648Ssteven-danz  $mlist = array();
1133f9eb5648Ssteven-danz  $file=metaFN($id,'.mlist');
1134d8186216SBen Coburn  if (@file_exists($file)) {
1135f9eb5648Ssteven-danz    $mlist = file($file);
1136f9eb5648Ssteven-danz  }
1137f9eb5648Ssteven-danz  if(count($mlist) > 0) {
1138f9eb5648Ssteven-danz    foreach ($mlist as $who) {
1139f9eb5648Ssteven-danz      $who = rtrim($who);
1140cd52f92dSchris      $info = $auth->getUserData($who);
1141f9eb5648Ssteven-danz      $level = auth_aclcheck($id,$who,$info['grps']);
1142f9eb5648Ssteven-danz      if ($level >= AUTH_READ) {
1143f9eb5648Ssteven-danz        if (strcasecmp($info['mail'],$conf['notify']) != 0) {
1144f9eb5648Ssteven-danz          if (empty($emails)) {
1145f9eb5648Ssteven-danz            $emails = $info['mail'];
1146f9eb5648Ssteven-danz          } else {
1147f9eb5648Ssteven-danz            $emails = "$emails,".$info['mail'];
1148f9eb5648Ssteven-danz          }
1149f9eb5648Ssteven-danz        }
1150f9eb5648Ssteven-danz      }
1151f9eb5648Ssteven-danz    }
1152f9eb5648Ssteven-danz  }
1153f9eb5648Ssteven-danz
1154f9eb5648Ssteven-danz  return $emails;
1155f9eb5648Ssteven-danz}
1156f9eb5648Ssteven-danz
115789541d4bSAndreas Gohr/**
115889541d4bSAndreas Gohr * Removes quoting backslashes
115989541d4bSAndreas Gohr *
116089541d4bSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
116189541d4bSAndreas Gohr */
116289541d4bSAndreas Gohrfunction unslash($string,$char="'"){
116389541d4bSAndreas Gohr  return str_replace('\\'.$char,$char,$string);
116489541d4bSAndreas Gohr}
116589541d4bSAndreas Gohr
1166340756e4Sandi//Setup VIM: ex: et ts=2 enc=utf-8 :
1167