xref: /dokuwiki/inc/common.php (revision 2ca9d91c1c4b1048c7be938a1436def5521a1909)
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
9ed7b5f09Sandiif(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
10e7cb32dcSAndreas Gohrrequire_once(DOKU_CONF.'dokuwiki.php');
11ed7b5f09Sandirequire_once(DOKU_INC.'inc/io.php');
127d559c7fSBen Coburnrequire_once(DOKU_INC.'inc/changelog.php');
13ed7b5f09Sandirequire_once(DOKU_INC.'inc/utf8.php');
14ed7b5f09Sandirequire_once(DOKU_INC.'inc/mail.php');
15c112d578Sandirequire_once(DOKU_INC.'inc/parserutils.php');
16c29dc6e4SAndreas Gohrrequire_once(DOKU_INC.'inc/infoutils.php');
17f3f0262cSandi
18f3f0262cSandi/**
19b6912aeaSAndreas Gohr * These constants are used with the recents function
20b6912aeaSAndreas Gohr */
21b6912aeaSAndreas Gohrdefine('RECENTS_SKIP_DELETED',2);
22b6912aeaSAndreas Gohrdefine('RECENTS_SKIP_MINORS',4);
23b6912aeaSAndreas Gohrdefine('RECENTS_SKIP_SUBSPACES',8);
24b6912aeaSAndreas Gohr
25b6912aeaSAndreas Gohr/**
26d5197206Schris * Wrapper around htmlspecialchars()
27d5197206Schris *
28d5197206Schris * @author Andreas Gohr <andi@splitbrain.org>
29d5197206Schris * @see    htmlspecialchars()
30d5197206Schris */
31d5197206Schrisfunction hsc($string){
32d5197206Schris  return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
33d5197206Schris}
34d5197206Schris
35d5197206Schris/**
36d5197206Schris * print a newline terminated string
37d5197206Schris *
38d5197206Schris * You can give an indention as optional parameter
39d5197206Schris *
40d5197206Schris * @author Andreas Gohr <andi@splitbrain.org>
41d5197206Schris */
42d5197206Schrisfunction ptln($string,$intend=0){
43d5197206Schris  for($i=0; $i<$intend; $i++) print ' ';
4402b0b681SAndreas Gohr  echo "$string\n";
4502b0b681SAndreas Gohr}
4602b0b681SAndreas Gohr
4702b0b681SAndreas Gohr/**
4802b0b681SAndreas Gohr * strips control characters (<32) from the given string
4902b0b681SAndreas Gohr *
5002b0b681SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
5102b0b681SAndreas Gohr */
5202b0b681SAndreas Gohrfunction stripctl($string){
5302b0b681SAndreas Gohr  return preg_replace('/[\x00-\x1F]+/s','',$string);
54d5197206Schris}
55d5197206Schris
56d5197206Schris/**
5715fae107Sandi * Return info about the current document as associative
58f3f0262cSandi * array.
5915fae107Sandi *
6015fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
61f3f0262cSandi */
62f3f0262cSandifunction pageinfo(){
63f3f0262cSandi  global $ID;
64f3f0262cSandi  global $REV;
65f3f0262cSandi  global $USERINFO;
66f3f0262cSandi  global $conf;
67f3f0262cSandi
686afe8dcaSchris  // include ID & REV not redundant, as some parts of DokuWiki may temporarily change $ID, e.g. p_wiki_xhtml
696afe8dcaSchris  // FIXME ... perhaps it would be better to ensure the temporary changes weren't necessary
706afe8dcaSchris  $info['id'] = $ID;
716afe8dcaSchris  $info['rev'] = $REV;
726afe8dcaSchris
73f3f0262cSandi  if($_SERVER['REMOTE_USER']){
74f3f0262cSandi    $info['userinfo']   = $USERINFO;
75f3f0262cSandi    $info['perm']       = auth_quickaclcheck($ID);
761380fc45SAndreas Gohr    $info['subscribed'] = is_subscribed($ID,$_SERVER['REMOTE_USER']);
77ee4c4a1bSAndreas Gohr    $info['client']     = $_SERVER['REMOTE_USER'];
7817ee7f66SAndreas Gohr
7917ee7f66SAndreas Gohr    // if some outside auth were used only REMOTE_USER is set
8017ee7f66SAndreas Gohr    if(!$info['userinfo']['name']){
8117ee7f66SAndreas Gohr      $info['userinfo']['name'] = $_SERVER['REMOTE_USER'];
8217ee7f66SAndreas Gohr    }
83ee4c4a1bSAndreas Gohr
84f3f0262cSandi  }else{
85f3f0262cSandi    $info['perm']       = auth_aclcheck($ID,'',null);
861380fc45SAndreas Gohr    $info['subscribed'] = false;
87ee4c4a1bSAndreas Gohr    $info['client']     = clientIP(true);
88f3f0262cSandi  }
89f3f0262cSandi
90f3f0262cSandi  $info['namespace'] = getNS($ID);
91f3f0262cSandi  $info['locked']    = checklock($ID);
92*2ca9d91cSBen Coburn  $info['filepath']  = realpath(wikiFN($ID));
93*2ca9d91cSBen Coburn  $info['exists']    = @file_exists($info['filepath']);
94*2ca9d91cSBen Coburn  if($REV){
95*2ca9d91cSBen Coburn    //check if current revision was meant
96*2ca9d91cSBen Coburn    if($info['exists'] && (@filemtime($info['filepath'])==$REV)){
97*2ca9d91cSBen Coburn      $REV = '';
98*2ca9d91cSBen Coburn    }else{
99*2ca9d91cSBen Coburn      //really use old revision
100f3f0262cSandi      $info['filepath'] = realpath(wikiFN($ID,$REV));
101f3f0262cSandi      $info['exists']   = @file_exists($info['filepath']);
102f3f0262cSandi    }
103f3f0262cSandi  }
104c112d578Sandi  $info['rev'] = $REV;
105f3f0262cSandi  if($info['exists']){
106f3f0262cSandi    $info['writable'] = (is_writable($info['filepath']) &&
107f3f0262cSandi                         ($info['perm'] >= AUTH_EDIT));
108f3f0262cSandi  }else{
109f3f0262cSandi    $info['writable'] = ($info['perm'] >= AUTH_CREATE);
110f3f0262cSandi  }
111f3f0262cSandi  $info['editable']  = ($info['writable'] && empty($info['lock']));
112f3f0262cSandi  $info['lastmod']   = @filemtime($info['filepath']);
113f3f0262cSandi
11471726d78SBen Coburn  //load page meta data
11571726d78SBen Coburn  $info['meta'] = p_get_metadata($ID);
11671726d78SBen Coburn
117652610a2Sandi  //who's the editor
118652610a2Sandi  if($REV){
11971726d78SBen Coburn    $revinfo = getRevisionInfo($ID, $REV, 1024);
120652610a2Sandi  }else{
121bb4866bdSchris    $revinfo = isset($info['meta']['last_change']) ? $info['meta']['last_change'] : getRevisionInfo($ID,$info['lastmod'],1024);
122652610a2Sandi  }
123bb4866bdSchris
124652610a2Sandi  $info['ip']     = $revinfo['ip'];
125652610a2Sandi  $info['user']   = $revinfo['user'];
126652610a2Sandi  $info['sum']    = $revinfo['sum'];
12771726d78SBen Coburn  // See also $INFO['meta']['last_change'] which is the most recent log line for page $ID.
12871726d78SBen Coburn  // Use $INFO['meta']['last_change']['type']==='e' in place of $info['minor'].
12959f257aeSchris
13088f522e9Sandi  if($revinfo['user']){
13188f522e9Sandi    $info['editor'] = $revinfo['user'];
13288f522e9Sandi  }else{
13388f522e9Sandi    $info['editor'] = $revinfo['ip'];
13488f522e9Sandi  }
135652610a2Sandi
136ee4c4a1bSAndreas Gohr  // draft
137ee4c4a1bSAndreas Gohr  $draft = getCacheName($info['client'].$ID,'.draft');
138ee4c4a1bSAndreas Gohr  if(@file_exists($draft)){
139ee4c4a1bSAndreas Gohr    if(@filemtime($draft) < @filemtime(wikiFN($ID))){
140ee4c4a1bSAndreas Gohr      // remove stale draft
141ee4c4a1bSAndreas Gohr      @unlink($draft);
142ee4c4a1bSAndreas Gohr    }else{
143ee4c4a1bSAndreas Gohr      $info['draft'] = $draft;
144ee4c4a1bSAndreas Gohr    }
145ee4c4a1bSAndreas Gohr  }
146ee4c4a1bSAndreas Gohr
147f3f0262cSandi  return $info;
148f3f0262cSandi}
149f3f0262cSandi
150f3f0262cSandi/**
1512684e50aSAndreas Gohr * Build an string of URL parameters
1522684e50aSAndreas Gohr *
1532684e50aSAndreas Gohr * @author Andreas Gohr
1542684e50aSAndreas Gohr */
155b174aeaeSchrisfunction buildURLparams($params, $sep='&amp;'){
1562684e50aSAndreas Gohr  $url = '';
1572684e50aSAndreas Gohr  $amp = false;
1582684e50aSAndreas Gohr  foreach($params as $key => $val){
159b174aeaeSchris    if($amp) $url .= $sep;
1602684e50aSAndreas Gohr
1612684e50aSAndreas Gohr    $url .= $key.'=';
162b6c6979fSAndreas Gohr    $url .= rawurlencode($val);
1632684e50aSAndreas Gohr    $amp = true;
1642684e50aSAndreas Gohr  }
1652684e50aSAndreas Gohr  return $url;
1662684e50aSAndreas Gohr}
1672684e50aSAndreas Gohr
1682684e50aSAndreas Gohr/**
1692684e50aSAndreas Gohr * Build an string of html tag attributes
1702684e50aSAndreas Gohr *
1717bff22c0SAndreas Gohr * Skips keys starting with '_', values get HTML encoded
1727bff22c0SAndreas Gohr *
1732684e50aSAndreas Gohr * @author Andreas Gohr
1742684e50aSAndreas Gohr */
1752684e50aSAndreas Gohrfunction buildAttributes($params){
1762684e50aSAndreas Gohr  $url = '';
1772684e50aSAndreas Gohr  foreach($params as $key => $val){
1787bff22c0SAndreas Gohr    if($key{0} == '_') continue;
1797bff22c0SAndreas Gohr
1802684e50aSAndreas Gohr    $url .= $key.'="';
1812684e50aSAndreas Gohr    $url .= htmlspecialchars ($val);
1822684e50aSAndreas Gohr    $url .= '" ';
1832684e50aSAndreas Gohr  }
1842684e50aSAndreas Gohr  return $url;
1852684e50aSAndreas Gohr}
1862684e50aSAndreas Gohr
1872684e50aSAndreas Gohr
1882684e50aSAndreas Gohr/**
18915fae107Sandi * This builds the breadcrumb trail and returns it as array
19015fae107Sandi *
19115fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
192f3f0262cSandi */
193f3f0262cSandifunction breadcrumbs(){
1948746e727Sandi  // we prepare the breadcrumbs early for quick session closing
1958746e727Sandi  static $crumbs = null;
1968746e727Sandi  if($crumbs != null) return $crumbs;
1978746e727Sandi
198f3f0262cSandi  global $ID;
199f3f0262cSandi  global $ACT;
200f3f0262cSandi  global $conf;
201e71ce681SAndreas Gohr  $crumbs = $_SESSION[DOKU_COOKIE]['bc'];
202f3f0262cSandi
203f3f0262cSandi  //first visit?
204f3f0262cSandi  if (!is_array($crumbs)){
205f3f0262cSandi    $crumbs = array();
206f3f0262cSandi  }
207f3f0262cSandi  //we only save on show and existing wiki documents
208a77f5846Sjan  $file = wikiFN($ID);
209a77f5846Sjan  if($ACT != 'show' || !@file_exists($file)){
210e71ce681SAndreas Gohr    $_SESSION[DOKU_COOKIE]['bc'] = $crumbs;
211f3f0262cSandi    return $crumbs;
212f3f0262cSandi  }
213a77f5846Sjan
214a77f5846Sjan  // page names
215a77f5846Sjan  $name = noNS($ID);
216a77f5846Sjan  if ($conf['useheading']) {
217a77f5846Sjan    // get page title
218bb0a59d4Sjan    $title = p_get_first_heading($ID);
219a77f5846Sjan    if ($title) {
220a77f5846Sjan      $name = $title;
221a77f5846Sjan    }
222a77f5846Sjan  }
223a77f5846Sjan
224f3f0262cSandi  //remove ID from array
225a77f5846Sjan  if (isset($crumbs[$ID])) {
226a77f5846Sjan    unset($crumbs[$ID]);
227f3f0262cSandi  }
228f3f0262cSandi
229f3f0262cSandi  //add to array
230a77f5846Sjan  $crumbs[$ID] = $name;
231f3f0262cSandi  //reduce size
232f3f0262cSandi  while(count($crumbs) > $conf['breadcrumbs']){
233f3f0262cSandi    array_shift($crumbs);
234f3f0262cSandi  }
235f3f0262cSandi  //save to session
236e71ce681SAndreas Gohr  $_SESSION[DOKU_COOKIE]['bc'] = $crumbs;
237f3f0262cSandi  return $crumbs;
238f3f0262cSandi}
239f3f0262cSandi
240f3f0262cSandi/**
24115fae107Sandi * Filter for page IDs
24215fae107Sandi *
243f3f0262cSandi * This is run on a ID before it is outputted somewhere
244f3f0262cSandi * currently used to replace the colon with something else
245f3f0262cSandi * on Windows systems and to have proper URL encoding
24615fae107Sandi *
24749c713a3Sandi * Urlencoding is ommitted when the second parameter is false
24849c713a3Sandi *
24915fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
250f3f0262cSandi */
25149c713a3Sandifunction idfilter($id,$ue=true){
252f3f0262cSandi  global $conf;
253f3f0262cSandi  if ($conf['useslash'] && $conf['userewrite']){
254f3f0262cSandi    $id = strtr($id,':','/');
255f3f0262cSandi  }elseif (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' &&
256f3f0262cSandi      $conf['userewrite']) {
257f3f0262cSandi    $id = strtr($id,':',';');
258f3f0262cSandi  }
25949c713a3Sandi  if($ue){
260b6c6979fSAndreas Gohr    $id = rawurlencode($id);
261f3f0262cSandi    $id = str_replace('%3A',':',$id); //keep as colon
262f3f0262cSandi    $id = str_replace('%2F','/',$id); //keep as slash
26349c713a3Sandi  }
264f3f0262cSandi  return $id;
265f3f0262cSandi}
266f3f0262cSandi
267f3f0262cSandi/**
268ed7b5f09Sandi * This builds a link to a wikipage
26915fae107Sandi *
2706c7843b5Sandi * It handles URL rewriting and adds additional parameter if
2716c7843b5Sandi * given in $more
2726c7843b5Sandi *
27315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
274f3f0262cSandi */
275b174aeaeSchrisfunction wl($id='',$more='',$abs=false,$sep='&amp;'){
276f3f0262cSandi  global $conf;
2776de3759aSAndreas Gohr  if(is_array($more)){
278b174aeaeSchris    $more = buildURLparams($more,$sep);
2796de3759aSAndreas Gohr  }else{
280b174aeaeSchris    $more = str_replace(',',$sep,$more);
2816de3759aSAndreas Gohr  }
282f3f0262cSandi
283f3f0262cSandi  $id    = idfilter($id);
284ed7b5f09Sandi  if($abs){
285ed7b5f09Sandi    $xlink = DOKU_URL;
286ed7b5f09Sandi  }else{
287ed7b5f09Sandi    $xlink = DOKU_BASE;
288ed7b5f09Sandi  }
289f3f0262cSandi
2906c7843b5Sandi  if($conf['userewrite'] == 2){
2916c7843b5Sandi    $xlink .= DOKU_SCRIPT.'/'.$id;
2926c7843b5Sandi    if($more) $xlink .= '?'.$more;
2936c7843b5Sandi  }elseif($conf['userewrite']){
294f3f0262cSandi    $xlink .= $id;
295f3f0262cSandi    if($more) $xlink .= '?'.$more;
2966c7843b5Sandi  }else{
2976c7843b5Sandi    $xlink .= DOKU_SCRIPT.'?id='.$id;
298b174aeaeSchris    if($more) $xlink .= $sep.$more;
299f3f0262cSandi  }
300f3f0262cSandi
301f3f0262cSandi  return $xlink;
302f3f0262cSandi}
303f3f0262cSandi
304f3f0262cSandi/**
305f5c2808fSBen Coburn * This builds a link to an alternate page format
306f5c2808fSBen Coburn *
307f5c2808fSBen Coburn * Handles URL rewriting if enabled. Follows the style of wl().
308f5c2808fSBen Coburn *
309f5c2808fSBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
310f5c2808fSBen Coburn */
311f5c2808fSBen Coburnfunction exportlink($id='',$format='raw',$more='',$abs=false,$sep='&amp;'){
312f5c2808fSBen Coburn  global $conf;
313f5c2808fSBen Coburn  if(is_array($more)){
314f5c2808fSBen Coburn    $more = buildURLparams($more,$sep);
315f5c2808fSBen Coburn  }else{
316f5c2808fSBen Coburn    $more = str_replace(',',$sep,$more);
317f5c2808fSBen Coburn  }
318f5c2808fSBen Coburn
319f5c2808fSBen Coburn  $format = rawurlencode($format);
320f5c2808fSBen Coburn  $id = idfilter($id);
321f5c2808fSBen Coburn  if($abs){
322f5c2808fSBen Coburn    $xlink = DOKU_URL;
323f5c2808fSBen Coburn  }else{
324f5c2808fSBen Coburn    $xlink = DOKU_BASE;
325f5c2808fSBen Coburn  }
326f5c2808fSBen Coburn
327f5c2808fSBen Coburn  if($conf['userewrite'] == 2){
328f5c2808fSBen Coburn    $xlink .= DOKU_SCRIPT.'/'.$id.'?do=export_'.$format;
329f5c2808fSBen Coburn    if($more) $xlink .= $sep.$more;
330f5c2808fSBen Coburn  }elseif($conf['userewrite'] == 1){
331f5c2808fSBen Coburn    $xlink .= '_export/'.$format.'/'.$id;
332f5c2808fSBen Coburn    if($more) $xlink .= '?'.$more;
333f5c2808fSBen Coburn  }else{
334f5c2808fSBen Coburn    $xlink .= DOKU_SCRIPT.'?do=export_'.$format.$sep.'id='.$id;
335f5c2808fSBen Coburn    if($more) $xlink .= $sep.$more;
336f5c2808fSBen Coburn  }
337f5c2808fSBen Coburn
338f5c2808fSBen Coburn  return $xlink;
339f5c2808fSBen Coburn}
340f5c2808fSBen Coburn
341f5c2808fSBen Coburn/**
3426de3759aSAndreas Gohr * Build a link to a media file
3436de3759aSAndreas Gohr *
3446de3759aSAndreas Gohr * Will return a link to the detail page if $direct is false
3456de3759aSAndreas Gohr */
346b174aeaeSchrisfunction ml($id='',$more='',$direct=true,$sep='&amp;'){
3476de3759aSAndreas Gohr  global $conf;
3486de3759aSAndreas Gohr  if(is_array($more)){
349b174aeaeSchris    $more = buildURLparams($more,$sep);
3506de3759aSAndreas Gohr  }else{
351b174aeaeSchris    $more = str_replace(',',$sep,$more);
3526de3759aSAndreas Gohr  }
3536de3759aSAndreas Gohr
3546de3759aSAndreas Gohr  $xlink = DOKU_BASE;
3556de3759aSAndreas Gohr
3566de3759aSAndreas Gohr  // external URLs are always direct without rewriting
3576de3759aSAndreas Gohr  if(preg_match('#^(https?|ftp)://#i',$id)){
3586de3759aSAndreas Gohr    $xlink .= 'lib/exe/fetch.php';
3596de3759aSAndreas Gohr    if($more){
3606de3759aSAndreas Gohr      $xlink .= '?'.$more;
361b174aeaeSchris      $xlink .= $sep.'media='.rawurlencode($id);
3626de3759aSAndreas Gohr    }else{
363b6c6979fSAndreas Gohr      $xlink .= '?media='.rawurlencode($id);
3646de3759aSAndreas Gohr    }
3656de3759aSAndreas Gohr    return $xlink;
3666de3759aSAndreas Gohr  }
3676de3759aSAndreas Gohr
3686de3759aSAndreas Gohr  $id = idfilter($id);
3696de3759aSAndreas Gohr
3706de3759aSAndreas Gohr  // decide on scriptname
3716de3759aSAndreas Gohr  if($direct){
3726de3759aSAndreas Gohr    if($conf['userewrite'] == 1){
3736de3759aSAndreas Gohr      $script = '_media';
3746de3759aSAndreas Gohr    }else{
3756de3759aSAndreas Gohr      $script = 'lib/exe/fetch.php';
3766de3759aSAndreas Gohr    }
3776de3759aSAndreas Gohr  }else{
3786de3759aSAndreas Gohr    if($conf['userewrite'] == 1){
3796de3759aSAndreas Gohr      $script = '_detail';
3806de3759aSAndreas Gohr    }else{
3816de3759aSAndreas Gohr      $script = 'lib/exe/detail.php';
3826de3759aSAndreas Gohr    }
3836de3759aSAndreas Gohr  }
3846de3759aSAndreas Gohr
3856de3759aSAndreas Gohr  // build URL based on rewrite mode
3866de3759aSAndreas Gohr   if($conf['userewrite']){
3876de3759aSAndreas Gohr     $xlink .= $script.'/'.$id;
3886de3759aSAndreas Gohr     if($more) $xlink .= '?'.$more;
3896de3759aSAndreas Gohr   }else{
3906de3759aSAndreas Gohr     if($more){
391a99d3236SEsther Brunner       $xlink .= $script.'?'.$more;
392b174aeaeSchris       $xlink .= $sep.'media='.$id;
3936de3759aSAndreas Gohr     }else{
394a99d3236SEsther Brunner       $xlink .= $script.'?media='.$id;
3956de3759aSAndreas Gohr     }
3966de3759aSAndreas Gohr   }
3976de3759aSAndreas Gohr
3986de3759aSAndreas Gohr  return $xlink;
3996de3759aSAndreas Gohr}
4006de3759aSAndreas Gohr
4016de3759aSAndreas Gohr
4026de3759aSAndreas Gohr
4036de3759aSAndreas Gohr/**
404f3f0262cSandi * Just builds a link to a script
40515fae107Sandi *
406ed7b5f09Sandi * @todo   maybe obsolete
40715fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
408f3f0262cSandi */
409f3f0262cSandifunction script($script='doku.php'){
410ed7b5f09Sandi#  $link = getBaseURL();
411ed7b5f09Sandi#  $link .= $script;
412ed7b5f09Sandi#  return $link;
413ed7b5f09Sandi  return DOKU_BASE.DOKU_SCRIPT;
414f3f0262cSandi}
415f3f0262cSandi
416f3f0262cSandi/**
41715fae107Sandi * Spamcheck against wordlist
41815fae107Sandi *
419f3f0262cSandi * Checks the wikitext against a list of blocked expressions
420f3f0262cSandi * returns true if the text contains any bad words
42115fae107Sandi *
42215fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
423f3f0262cSandi */
424f3f0262cSandifunction checkwordblock(){
425f3f0262cSandi  global $TEXT;
426f3f0262cSandi  global $conf;
427f3f0262cSandi
428f3f0262cSandi  if(!$conf['usewordblock']) return false;
429f3f0262cSandi
430041d1964SAndreas Gohr  // we prepare the text a tiny bit to prevent spammers circumventing URL checks
431041d1964SAndreas Gohr  $text = preg_replace('!(\b)(www\.[\w.:?\-;,]+?\.[\w.:?\-;,]+?[\w/\#~:.?+=&%@\!\-.:?\-;,]+?)([.:?\-;,]*[^\w/\#~:.?+=&%@\!\-.:?\-;,])!i','\1http://\2 \2\3',$TEXT);
432041d1964SAndreas Gohr
433b9ac8716Schris  $wordblocks = getWordblocks();
4343e2965d7Sandi  //how many lines to read at once (to work around some PCRE limits)
4353e2965d7Sandi  if(version_compare(phpversion(),'4.3.0','<')){
4363e2965d7Sandi    //old versions of PCRE define a maximum of parenthesises even if no
4373e2965d7Sandi    //backreferences are used - the maximum is 99
4383e2965d7Sandi    //this is very bad performancewise and may even be too high still
4393e2965d7Sandi    $chunksize = 40;
4403e2965d7Sandi  }else{
441a51d08efSAndreas Gohr    //read file in chunks of 200 - this should work around the
4423e2965d7Sandi    //MAX_PATTERN_SIZE in modern PCRE
443a51d08efSAndreas Gohr    $chunksize = 200;
4443e2965d7Sandi  }
445b9ac8716Schris  while($blocks = array_splice($wordblocks,0,$chunksize)){
446f3f0262cSandi    $re = array();
447f3f0262cSandi    #build regexp from blocks
448f3f0262cSandi    foreach($blocks as $block){
449f3f0262cSandi      $block = preg_replace('/#.*$/','',$block);
450f3f0262cSandi      $block = trim($block);
451f3f0262cSandi      if(empty($block)) continue;
452f3f0262cSandi      $re[]  = $block;
453f3f0262cSandi    }
454041d1964SAndreas Gohr    if(preg_match('#('.join('|',$re).')#si',$text, $match=array())) {
455b9ac8716Schris      return true;
456b9ac8716Schris    }
457703f6fdeSandi  }
458f3f0262cSandi  return false;
459f3f0262cSandi}
460f3f0262cSandi
461f3f0262cSandi/**
46215fae107Sandi * Return the IP of the client
46315fae107Sandi *
4646d8affe6SAndreas Gohr * Honours X-Forwarded-For and X-Real-IP Proxy Headers
46515fae107Sandi *
4666d8affe6SAndreas Gohr * It returns a comma separated list of IPs if the above mentioned
4676d8affe6SAndreas Gohr * headers are set. If the single parameter is set, it tries to return
4686d8affe6SAndreas Gohr * a routable public address, prefering the ones suplied in the X
4696d8affe6SAndreas Gohr * headers
4706d8affe6SAndreas Gohr *
4716d8affe6SAndreas Gohr * @param  boolean $single If set only a single IP is returned
47215fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
473f3f0262cSandi */
4746d8affe6SAndreas Gohrfunction clientIP($single=false){
4756d8affe6SAndreas Gohr  $ip = array();
4766d8affe6SAndreas Gohr  $ip[] = $_SERVER['REMOTE_ADDR'];
477bb4866bdSchris  if(!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
4786d8affe6SAndreas Gohr    $ip = array_merge($ip,explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']));
479bb4866bdSchris  if(!empty($_SERVER['HTTP_X_REAL_IP']))
4806d8affe6SAndreas Gohr    $ip = array_merge($ip,explode(',',$_SERVER['HTTP_X_REAL_IP']));
4816d8affe6SAndreas Gohr
4826d8affe6SAndreas Gohr  // remove any non-IP stuff
4836d8affe6SAndreas Gohr  $cnt = count($ip);
4844ff28443Schris  $match = array();
4856d8affe6SAndreas Gohr  for($i=0; $i<$cnt; $i++){
4864ff28443Schris    if(preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/',$ip[$i],$match)) {
4874ff28443Schris      $ip[$i] = $match[0];
4884ff28443Schris    } else {
4894ff28443Schris      $ip[$i] = '';
4904ff28443Schris    }
4916d8affe6SAndreas Gohr    if(empty($ip[$i])) unset($ip[$i]);
492f3f0262cSandi  }
4936d8affe6SAndreas Gohr  $ip = array_values(array_unique($ip));
4946d8affe6SAndreas Gohr  if(!$ip[0]) $ip[0] = '0.0.0.0'; // for some strange reason we don't have a IP
4956d8affe6SAndreas Gohr
4966d8affe6SAndreas Gohr  if(!$single) return join(',',$ip);
4976d8affe6SAndreas Gohr
4986d8affe6SAndreas Gohr  // decide which IP to use, trying to avoid local addresses
4996d8affe6SAndreas Gohr  $ip = array_reverse($ip);
5006d8affe6SAndreas Gohr  foreach($ip as $i){
5016d8affe6SAndreas Gohr    if(preg_match('/^(127\.|10\.|192\.168\.|172\.((1[6-9])|(2[0-9])|(3[0-1]))\.)/',$i)){
5026d8affe6SAndreas Gohr      continue;
5036d8affe6SAndreas Gohr    }else{
5046d8affe6SAndreas Gohr      return $i;
5056d8affe6SAndreas Gohr    }
5066d8affe6SAndreas Gohr  }
5076d8affe6SAndreas Gohr  // still here? just use the first (last) address
5086d8affe6SAndreas Gohr  return $ip[0];
509f3f0262cSandi}
510f3f0262cSandi
511f3f0262cSandi/**
51215fae107Sandi * Checks if a given page is currently locked.
51315fae107Sandi *
514f3f0262cSandi * removes stale lockfiles
51515fae107Sandi *
51615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
517f3f0262cSandi */
518f3f0262cSandifunction checklock($id){
519f3f0262cSandi  global $conf;
520c9b4bd1eSBen Coburn  $lock = wikiLockFN($id);
521f3f0262cSandi
522f3f0262cSandi  //no lockfile
523f3f0262cSandi  if(!@file_exists($lock)) return false;
524f3f0262cSandi
525f3f0262cSandi  //lockfile expired
526f3f0262cSandi  if((time() - filemtime($lock)) > $conf['locktime']){
527d8186216SBen Coburn    @unlink($lock);
528f3f0262cSandi    return false;
529f3f0262cSandi  }
530f3f0262cSandi
531f3f0262cSandi  //my own lock
532f3f0262cSandi  $ip = io_readFile($lock);
533f3f0262cSandi  if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){
534f3f0262cSandi    return false;
535f3f0262cSandi  }
536f3f0262cSandi
537f3f0262cSandi  return $ip;
538f3f0262cSandi}
539f3f0262cSandi
540f3f0262cSandi/**
54115fae107Sandi * Lock a page for editing
54215fae107Sandi *
54315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
544f3f0262cSandi */
545f3f0262cSandifunction lock($id){
546c9b4bd1eSBen Coburn  $lock = wikiLockFN($id);
547f3f0262cSandi  if($_SERVER['REMOTE_USER']){
548f3f0262cSandi    io_saveFile($lock,$_SERVER['REMOTE_USER']);
549f3f0262cSandi  }else{
550f3f0262cSandi    io_saveFile($lock,clientIP());
551f3f0262cSandi  }
552f3f0262cSandi}
553f3f0262cSandi
554f3f0262cSandi/**
55515fae107Sandi * Unlock a page if it was locked by the user
556f3f0262cSandi *
55715fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
55815fae107Sandi * @return bool true if a lock was removed
559f3f0262cSandi */
560f3f0262cSandifunction unlock($id){
561c9b4bd1eSBen Coburn  $lock = wikiLockFN($id);
562f3f0262cSandi  if(@file_exists($lock)){
563f3f0262cSandi    $ip = io_readFile($lock);
564f3f0262cSandi    if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){
565f3f0262cSandi      @unlink($lock);
566f3f0262cSandi      return true;
567f3f0262cSandi    }
568f3f0262cSandi  }
569f3f0262cSandi  return false;
570f3f0262cSandi}
571f3f0262cSandi
572f3f0262cSandi/**
573f3f0262cSandi * convert line ending to unix format
574f3f0262cSandi *
57515fae107Sandi * @see    formText() for 2crlf conversion
57615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
577f3f0262cSandi */
578f3f0262cSandifunction cleanText($text){
579f3f0262cSandi  $text = preg_replace("/(\015\012)|(\015)/","\012",$text);
580f3f0262cSandi  return $text;
581f3f0262cSandi}
582f3f0262cSandi
583f3f0262cSandi/**
584f3f0262cSandi * Prepares text for print in Webforms by encoding special chars.
585f3f0262cSandi * It also converts line endings to Windows format which is
586f3f0262cSandi * pseudo standard for webforms.
587f3f0262cSandi *
58815fae107Sandi * @see    cleanText() for 2unix conversion
58915fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
590f3f0262cSandi */
591f3f0262cSandifunction formText($text){
592f3f0262cSandi  $text = preg_replace("/\012/","\015\012",$text);
593f3f0262cSandi  return htmlspecialchars($text);
594f3f0262cSandi}
595f3f0262cSandi
596f3f0262cSandi/**
59715fae107Sandi * Returns the specified local text in raw format
59815fae107Sandi *
59915fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
600f3f0262cSandi */
601f3f0262cSandifunction rawLocale($id){
602f3f0262cSandi  return io_readFile(localeFN($id));
603f3f0262cSandi}
604f3f0262cSandi
605f3f0262cSandi/**
606f3f0262cSandi * Returns the raw WikiText
60715fae107Sandi *
60815fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
609f3f0262cSandi */
610f3f0262cSandifunction rawWiki($id,$rev=''){
611cc7d0c94SBen Coburn  return io_readWikiPage(wikiFN($id, $rev), $id, $rev);
612f3f0262cSandi}
613f3f0262cSandi
614f3f0262cSandi/**
6157146cee2SAndreas Gohr * Returns the pagetemplate contents for the ID's namespace
6167146cee2SAndreas Gohr *
6177146cee2SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
6187146cee2SAndreas Gohr */
619b7d5a5f0SAndreas Gohrfunction pageTemplate($data){
620b7d5a5f0SAndreas Gohr  $id = $data[0];
621a15ce62dSEsther Brunner  global $conf;
622a15ce62dSEsther Brunner  global $INFO;
623a15ce62dSEsther Brunner  $tpl = io_readFile(dirname(wikiFN($id)).'/_template.txt');
624a15ce62dSEsther Brunner  $tpl = str_replace('@ID@',$id,$tpl);
625a15ce62dSEsther Brunner  $tpl = str_replace('@NS@',getNS($id),$tpl);
626a15ce62dSEsther Brunner  $tpl = str_replace('@PAGE@',strtr(noNS($id),'_',' '),$tpl);
627a15ce62dSEsther Brunner  $tpl = str_replace('@USER@',$_SERVER['REMOTE_USER'],$tpl);
628a15ce62dSEsther Brunner  $tpl = str_replace('@NAME@',$INFO['userinfo']['name'],$tpl);
629a15ce62dSEsther Brunner  $tpl = str_replace('@MAIL@',$INFO['userinfo']['mail'],$tpl);
630a15ce62dSEsther Brunner  $tpl = str_replace('@DATE@',date($conf['dformat']),$tpl);
631a15ce62dSEsther Brunner  return $tpl;
6327146cee2SAndreas Gohr}
6337146cee2SAndreas Gohr
6347146cee2SAndreas Gohr
6357146cee2SAndreas Gohr/**
63615fae107Sandi * Returns the raw Wiki Text in three slices.
63715fae107Sandi *
63815fae107Sandi * The range parameter needs to have the form "from-to"
63915cfe303Sandi * and gives the range of the section in bytes - no
64015cfe303Sandi * UTF-8 awareness is needed.
641f3f0262cSandi * The returned order is prefix, section and suffix.
64215fae107Sandi *
64315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
644f3f0262cSandi */
645f3f0262cSandifunction rawWikiSlices($range,$id,$rev=''){
646f3f0262cSandi  list($from,$to) = split('-',$range,2);
647cc7d0c94SBen Coburn  $text = io_readWikiPage(wikiFN($id, $rev), $id, $rev);
648f3f0262cSandi  if(!$from) $from = 0;
649c3d8e19bSandi  if(!$to)   $to   = strlen($text)+1;
650f3f0262cSandi
65115cfe303Sandi  $slices[0] = substr($text,0,$from-1);
65215cfe303Sandi  $slices[1] = substr($text,$from-1,$to-$from);
65315cfe303Sandi  $slices[2] = substr($text,$to);
654f3f0262cSandi
655f3f0262cSandi  return $slices;
656f3f0262cSandi}
657f3f0262cSandi
658f3f0262cSandi/**
65915fae107Sandi * Joins wiki text slices
66015fae107Sandi *
661f3f0262cSandi * function to join the text slices with correct lineendings again.
662f3f0262cSandi * When the pretty parameter is set to true it adds additional empty
663f3f0262cSandi * lines between sections if needed (used on saving).
66415fae107Sandi *
66515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
666f3f0262cSandi */
667f3f0262cSandifunction con($pre,$text,$suf,$pretty=false){
668f3f0262cSandi
669f3f0262cSandi  if($pretty){
670f3f0262cSandi    if($pre && substr($pre,-1) != "\n") $pre .= "\n";
671f3f0262cSandi    if($suf && substr($text,-1) != "\n") $text .= "\n";
672f3f0262cSandi  }
673f3f0262cSandi
674f3f0262cSandi  if($pre) $pre .= "\n";
675f3f0262cSandi  if($suf) $text .= "\n";
676f3f0262cSandi  return $pre.$text.$suf;
677f3f0262cSandi}
678f3f0262cSandi
679f3f0262cSandi/**
680a701424fSBen Coburn * Saves a wikitext by calling io_writeWikiPage.
681a701424fSBen Coburn * Also directs changelog and attic updates.
68215fae107Sandi *
68315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
68471726d78SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
685f3f0262cSandi */
686b6912aeaSAndreas Gohrfunction saveWikiText($id,$text,$summary,$minor=false){
687a701424fSBen Coburn  /* Note to developers:
688a701424fSBen Coburn     This code is subtle and delicate. Test the behavior of
689a701424fSBen Coburn     the attic and changelog with dokuwiki and external edits
690a701424fSBen Coburn     after any changes. External edits change the wiki page
691a701424fSBen Coburn     directly without using php or dokuwiki.
692a701424fSBen Coburn  */
693f3f0262cSandi  global $conf;
694f3f0262cSandi  global $lang;
69571726d78SBen Coburn  global $REV;
696f3f0262cSandi  // ignore if no changes were made
697f3f0262cSandi  if($text == rawWiki($id,'')){
698f3f0262cSandi    return;
699f3f0262cSandi  }
700f3f0262cSandi
701f3f0262cSandi  $file = wikiFN($id);
702a701424fSBen Coburn  $old = @filemtime($file); // from page
70371726d78SBen Coburn  $wasRemoved = empty($text);
704d8186216SBen Coburn  $wasCreated = !@file_exists($file);
70571726d78SBen Coburn  $wasReverted = ($REV==true);
706e45b34cdSBen Coburn  $newRev = false;
707a701424fSBen Coburn  $oldRev = getRevisions($id, -1, 1, 1024); // from changelog
708a701424fSBen Coburn  $oldRev = (int)(empty($oldRev)?0:$oldRev[0]);
709a701424fSBen Coburn  if(!@file_exists(wikiFN($id, $old)) && @file_exists($file) && $old>=$oldRev) {
71046844156SBen Coburn    // add old revision to the attic if missing
71146844156SBen Coburn    saveOldRevision($id);
71246844156SBen Coburn    // add a changelog entry if this edit came from outside dokuwiki
713a701424fSBen Coburn    if ($old>$oldRev) {
71446844156SBen Coburn      addLogEntry($old, $id);
71546844156SBen Coburn      // send notify mails
71646844156SBen Coburn      notify($id,'admin',$oldRev,'',false);
71746844156SBen Coburn      notify($id,'subscribers',$oldRev,'',false);
71846844156SBen Coburn      // remove soon to be stale instructions
71946844156SBen Coburn      $cache = new cache_instructions($id, $file);
72046844156SBen Coburn      $cache->removeCache();
72146844156SBen Coburn    }
72246844156SBen Coburn  }
723f3f0262cSandi
72471726d78SBen Coburn  if ($wasRemoved){
725e45b34cdSBen Coburn    // pre-save deleted revision
726e45b34cdSBen Coburn    @touch($file);
72746844156SBen Coburn    clearstatcache();
728e45b34cdSBen Coburn    $newRev = saveOldRevision($id);
729e1f3d9e1SEsther Brunner    // remove empty file
730f3f0262cSandi    @unlink($file);
73171726d78SBen Coburn    // remove old meta info...
732e1f3d9e1SEsther Brunner    $mfiles = metaFiles($id);
73371726d78SBen Coburn    $changelog = metaFN($id, '.changes');
734e1f3d9e1SEsther Brunner    foreach ($mfiles as $mfile) {
73571726d78SBen Coburn      // but keep per-page changelog to preserve page history
736d8186216SBen Coburn      if (@file_exists($mfile) && $mfile!==$changelog) { @unlink($mfile); }
737b158d625SSteven Danz    }
738f3f0262cSandi    $del = true;
7393ce054b3Sandi    // autoset summary on deletion
7403ce054b3Sandi    if(empty($summary)) $summary = $lang['deleted'];
74153d6ccfeSandi    // remove empty namespaces
742cc7d0c94SBen Coburn    io_sweepNS($id, 'datadir');
743cc7d0c94SBen Coburn    io_sweepNS($id, 'mediadir');
744f3f0262cSandi  }else{
745cc7d0c94SBen Coburn    // save file (namespace dir is created in io_writeWikiPage)
746cc7d0c94SBen Coburn    io_writeWikiPage($file, $text, $id);
74746844156SBen Coburn    // pre-save the revision, to keep the attic in sync
74846844156SBen Coburn    $newRev = saveOldRevision($id);
749f3f0262cSandi    $del = false;
750f3f0262cSandi  }
751f3f0262cSandi
75271726d78SBen Coburn  // select changelog line type
75371726d78SBen Coburn  $extra = '';
75471726d78SBen Coburn  $type = 'E';
75571726d78SBen Coburn  if ($wasReverted) {
75671726d78SBen Coburn    $type = 'R';
75771726d78SBen Coburn    $extra = $REV;
75871726d78SBen Coburn  }
75971726d78SBen Coburn  else if ($wasCreated) { $type = 'C'; }
76071726d78SBen Coburn  else if ($wasRemoved) { $type = 'D'; }
76171726d78SBen Coburn  else if ($minor && $conf['useacl'] && $_SERVER['REMOTE_USER']) { $type = 'e'; } //minor edits only for logged in users
76271726d78SBen Coburn
763e45b34cdSBen Coburn  addLogEntry($newRev, $id, $type, $summary, $extra);
76426a0801fSAndreas Gohr  // send notify mails
76590033e9dSAndreas Gohr  notify($id,'admin',$old,$summary,$minor);
76690033e9dSAndreas Gohr  notify($id,'subscribers',$old,$summary,$minor);
767f3f0262cSandi
768ce6b63d9Schris  // update the purgefile (timestamp of the last time anything within the wiki was changed)
76998407a7aSandi  io_saveFile($conf['cachedir'].'/purgefile',time());
770f3f0262cSandi}
771f3f0262cSandi
772f3f0262cSandi/**
773f3f0262cSandi * moves the current version to the attic and returns its
774f3f0262cSandi * revision date
77515fae107Sandi *
77615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
777f3f0262cSandi */
778f3f0262cSandifunction saveOldRevision($id){
779f3f0262cSandi  global $conf;
780f3f0262cSandi  $oldf = wikiFN($id);
781f3f0262cSandi  if(!@file_exists($oldf)) return '';
782f3f0262cSandi  $date = filemtime($oldf);
783f3f0262cSandi  $newf = wikiFN($id,$date);
784cc7d0c94SBen Coburn  io_writeWikiPage($newf, rawWiki($id), $id, $date);
785f3f0262cSandi  return $date;
786f3f0262cSandi}
787f3f0262cSandi
788f3f0262cSandi/**
78926a0801fSAndreas Gohr * Sends a notify mail on page change
79026a0801fSAndreas Gohr *
79126a0801fSAndreas Gohr * @param  string  $id       The changed page
79226a0801fSAndreas Gohr * @param  string  $who      Who to notify (admin|subscribers)
79326a0801fSAndreas Gohr * @param  int     $rev      Old page revision
79426a0801fSAndreas Gohr * @param  string  $summary  What changed
79590033e9dSAndreas Gohr * @param  boolean $minor    Is this a minor edit?
79602a498e7Schris * @param  array   $replace  Additional string substitutions, @KEY@ to be replaced by value
79715fae107Sandi *
79815fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
799f3f0262cSandi */
80002a498e7Schrisfunction notify($id,$who,$rev='',$summary='',$minor=false,$replace=array()){
801f3f0262cSandi  global $lang;
802f3f0262cSandi  global $conf;
803b158d625SSteven Danz
80426a0801fSAndreas Gohr  // decide if there is something to do
80526a0801fSAndreas Gohr  if($who == 'admin'){
80626a0801fSAndreas Gohr    if(empty($conf['notify'])) return; //notify enabled?
807f3f0262cSandi    $text = rawLocale('mailtext');
80826a0801fSAndreas Gohr    $to   = $conf['notify'];
80926a0801fSAndreas Gohr    $bcc  = '';
81026a0801fSAndreas Gohr  }elseif($who == 'subscribers'){
81126a0801fSAndreas Gohr    if(!$conf['subscribers']) return; //subscribers enabled?
81290033e9dSAndreas Gohr    if($conf['useacl'] && $_SERVER['REMOTE_USER'] && $minor) return; //skip minors
81326a0801fSAndreas Gohr    $bcc  = subscriber_addresslist($id);
81426a0801fSAndreas Gohr    if(empty($bcc)) return;
81526a0801fSAndreas Gohr    $to   = '';
81626a0801fSAndreas Gohr    $text = rawLocale('subscribermail');
817a06e4bdbSSebastian Harl  }elseif($who == 'register'){
818a06e4bdbSSebastian Harl    if(empty($conf['registernotify'])) return;
819a06e4bdbSSebastian Harl    $text = rawLocale('registermail');
820a06e4bdbSSebastian Harl    $to   = $conf['registernotify'];
821a06e4bdbSSebastian Harl    $bcc  = '';
82226a0801fSAndreas Gohr  }else{
82326a0801fSAndreas Gohr    return; //just to be safe
82426a0801fSAndreas Gohr  }
82526a0801fSAndreas Gohr
826f3f0262cSandi  $text = str_replace('@DATE@',date($conf['dformat']),$text);
827f3f0262cSandi  $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text);
828f3f0262cSandi  $text = str_replace('@IPADDRESS@',$_SERVER['REMOTE_ADDR'],$text);
829f3f0262cSandi  $text = str_replace('@HOSTNAME@',gethostbyaddr($_SERVER['REMOTE_ADDR']),$text);
830ed7b5f09Sandi  $text = str_replace('@NEWPAGE@',wl($id,'',true),$text);
83126a0801fSAndreas Gohr  $text = str_replace('@PAGE@',$id,$text);
83226a0801fSAndreas Gohr  $text = str_replace('@TITLE@',$conf['title'],$text);
833ed7b5f09Sandi  $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text);
834f3f0262cSandi  $text = str_replace('@SUMMARY@',$summary,$text);
8357a82afdcSandi  $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text);
836f3f0262cSandi
83702a498e7Schris  foreach ($replace as $key => $substitution) {
83802a498e7Schris    $text = str_replace('@'.strtoupper($key).'@',$substitution, $text);
83902a498e7Schris  }
84002a498e7Schris
841a06e4bdbSSebastian Harl  if($who == 'register'){
842a06e4bdbSSebastian Harl    $subject = $lang['mail_new_user'].' '.$summary;
843a06e4bdbSSebastian Harl  }elseif($rev){
844f3f0262cSandi    $subject = $lang['mail_changed'].' '.$id;
845ed7b5f09Sandi    $text = str_replace('@OLDPAGE@',wl($id,"rev=$rev",true),$text);
846ccdfa6c0SAndreas Gohr    require_once(DOKU_INC.'inc/DifferenceEngine.php');
847f3f0262cSandi    $df  = new Diff(split("\n",rawWiki($id,$rev)),
848f3f0262cSandi                    split("\n",rawWiki($id)));
849f3f0262cSandi    $dformat = new UnifiedDiffFormatter();
850f3f0262cSandi    $diff    = $dformat->format($df);
851f3f0262cSandi  }else{
852f3f0262cSandi    $subject=$lang['mail_newpage'].' '.$id;
853f3f0262cSandi    $text = str_replace('@OLDPAGE@','none',$text);
854f3f0262cSandi    $diff = rawWiki($id);
855f3f0262cSandi  }
856f3f0262cSandi  $text = str_replace('@DIFF@',$diff,$text);
857241f3a36Sandi  $subject = '['.$conf['title'].'] '.$subject;
858f3f0262cSandi
85926a0801fSAndreas Gohr  mail_send($to,$subject,$text,$conf['mailfrom'],'',$bcc);
860f3f0262cSandi}
861f3f0262cSandi
86215fae107Sandi/**
863f3f0262cSandi * extracts the query from a google referer
86415fae107Sandi *
8656b13307fSandi * @todo   should be more generic and support yahoo et al
86615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
867f3f0262cSandi */
868f3f0262cSandifunction getGoogleQuery(){
869f3f0262cSandi  $url = parse_url($_SERVER['HTTP_REFERER']);
8705c3f206fSandi  if(!$url) return '';
871f3f0262cSandi
872f3f0262cSandi  if(!preg_match("#google\.#i",$url['host'])) return '';
873f3f0262cSandi  $query = array();
874f3f0262cSandi  parse_str($url['query'],$query);
875f3f0262cSandi
876f3f0262cSandi  return $query['q'];
877f3f0262cSandi}
878f3f0262cSandi
879f3f0262cSandi/**
88015fae107Sandi * Try to set correct locale
88115fae107Sandi *
882095bfd5cSandi * @deprecated No longer used
88315fae107Sandi * @author     Andreas Gohr <andi@splitbrain.org>
884f3f0262cSandi */
885f3f0262cSandifunction setCorrectLocale(){
886f3f0262cSandi  global $conf;
887f3f0262cSandi  global $lang;
888f3f0262cSandi
889f3f0262cSandi  $enc = strtoupper($lang['encoding']);
890f3f0262cSandi  foreach ($lang['locales'] as $loc){
891f3f0262cSandi    //try locale
892f3f0262cSandi    if(@setlocale(LC_ALL,$loc)) return;
893f3f0262cSandi    //try loceale with encoding
894f3f0262cSandi    if(@setlocale(LC_ALL,"$loc.$enc")) return;
895f3f0262cSandi  }
896f3f0262cSandi  //still here? try to set from environment
897f3f0262cSandi  @setlocale(LC_ALL,"");
898f3f0262cSandi}
899f3f0262cSandi
900f3f0262cSandi/**
901f3f0262cSandi * Return the human readable size of a file
902f3f0262cSandi *
903f3f0262cSandi * @param       int    $size   A file size
904f3f0262cSandi * @param       int    $dec    A number of decimal places
905f3f0262cSandi * @author      Martin Benjamin <b.martin@cybernet.ch>
906f3f0262cSandi * @author      Aidan Lister <aidan@php.net>
907f3f0262cSandi * @version     1.0.0
908f3f0262cSandi */
909f31d5b73Sandifunction filesize_h($size, $dec = 1){
910f3f0262cSandi  $sizes = array('B', 'KB', 'MB', 'GB');
911f3f0262cSandi  $count = count($sizes);
912f3f0262cSandi  $i = 0;
913f3f0262cSandi
914f3f0262cSandi  while ($size >= 1024 && ($i < $count - 1)) {
915f3f0262cSandi    $size /= 1024;
916f3f0262cSandi    $i++;
917f3f0262cSandi  }
918f3f0262cSandi
919f3f0262cSandi  return round($size, $dec) . ' ' . $sizes[$i];
920f3f0262cSandi}
921f3f0262cSandi
92215fae107Sandi/**
92300a7b5adSEsther Brunner * return an obfuscated email address in line with $conf['mailguard'] setting
92400a7b5adSEsther Brunner *
92500a7b5adSEsther Brunner * @author Harry Fuecks <hfuecks@gmail.com>
92600a7b5adSEsther Brunner * @author Christopher Smith <chris@jalakai.co.uk>
92700a7b5adSEsther Brunner */
92800a7b5adSEsther Brunnerfunction obfuscate($email) {
92900a7b5adSEsther Brunner  global $conf;
93000a7b5adSEsther Brunner
93100a7b5adSEsther Brunner  switch ($conf['mailguard']) {
93200a7b5adSEsther Brunner    case 'visible' :
93300a7b5adSEsther Brunner      $obfuscate = array('@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] ');
93400a7b5adSEsther Brunner      return strtr($email, $obfuscate);
93500a7b5adSEsther Brunner
93600a7b5adSEsther Brunner    case 'hex' :
93700a7b5adSEsther Brunner      $encode = '';
93800a7b5adSEsther Brunner      for ($x=0; $x < strlen($email); $x++) $encode .= '&#x' . bin2hex($email{$x}).';';
93900a7b5adSEsther Brunner      return $encode;
94000a7b5adSEsther Brunner
94100a7b5adSEsther Brunner    case 'none' :
94200a7b5adSEsther Brunner    default :
94300a7b5adSEsther Brunner      return $email;
94400a7b5adSEsther Brunner  }
94500a7b5adSEsther Brunner}
94600a7b5adSEsther Brunner
94700a7b5adSEsther Brunner/**
948b158d625SSteven Danz * Let us know if a user is tracking a page
949b158d625SSteven Danz *
9501380fc45SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
951b158d625SSteven Danz */
9521380fc45SAndreas Gohrfunction is_subscribed($id,$uid){
9531380fc45SAndreas Gohr  $file=metaFN($id,'.mlist');
9541380fc45SAndreas Gohr  if (@file_exists($file)) {
955b158d625SSteven Danz    $mlist = file($file);
9561380fc45SAndreas Gohr    $pos = array_search($uid."\n",$mlist);
9571380fc45SAndreas Gohr    return is_int($pos);
958b158d625SSteven Danz  }
9591380fc45SAndreas Gohr
960b158d625SSteven Danz  return false;
961b158d625SSteven Danz}
962340756e4Sandi
963f9eb5648Ssteven-danz/**
964f9eb5648Ssteven-danz * Return a string with the email addresses of all the
965f9eb5648Ssteven-danz * users subscribed to a page
966f9eb5648Ssteven-danz *
96726a0801fSAndreas Gohr * @author Steven Danz <steven-danz@kc.rr.com>
968f9eb5648Ssteven-danz */
969f9eb5648Ssteven-danzfunction subscriber_addresslist($id){
970f9eb5648Ssteven-danz  global $conf;
971cd52f92dSchris  global $auth;
972f9eb5648Ssteven-danz
973f9eb5648Ssteven-danz  $emails = '';
974f9eb5648Ssteven-danz
97526a0801fSAndreas Gohr  if (!$conf['subscribers']) return;
97626a0801fSAndreas Gohr
977f9eb5648Ssteven-danz  $mlist = array();
978f9eb5648Ssteven-danz  $file=metaFN($id,'.mlist');
979d8186216SBen Coburn  if (@file_exists($file)) {
980f9eb5648Ssteven-danz    $mlist = file($file);
981f9eb5648Ssteven-danz  }
982f9eb5648Ssteven-danz  if(count($mlist) > 0) {
983f9eb5648Ssteven-danz    foreach ($mlist as $who) {
984f9eb5648Ssteven-danz      $who = rtrim($who);
985cd52f92dSchris      $info = $auth->getUserData($who);
986f9eb5648Ssteven-danz      $level = auth_aclcheck($id,$who,$info['grps']);
987f9eb5648Ssteven-danz      if ($level >= AUTH_READ) {
988f9eb5648Ssteven-danz        if (strcasecmp($info['mail'],$conf['notify']) != 0) {
989f9eb5648Ssteven-danz          if (empty($emails)) {
990f9eb5648Ssteven-danz            $emails = $info['mail'];
991f9eb5648Ssteven-danz          } else {
992f9eb5648Ssteven-danz            $emails = "$emails,".$info['mail'];
993f9eb5648Ssteven-danz          }
994f9eb5648Ssteven-danz        }
995f9eb5648Ssteven-danz      }
996f9eb5648Ssteven-danz    }
997f9eb5648Ssteven-danz  }
998f9eb5648Ssteven-danz
999f9eb5648Ssteven-danz  return $emails;
1000f9eb5648Ssteven-danz}
1001f9eb5648Ssteven-danz
100289541d4bSAndreas Gohr/**
100389541d4bSAndreas Gohr * Removes quoting backslashes
100489541d4bSAndreas Gohr *
100589541d4bSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
100689541d4bSAndreas Gohr */
100789541d4bSAndreas Gohrfunction unslash($string,$char="'"){
100889541d4bSAndreas Gohr  return str_replace('\\'.$char,$char,$string);
100989541d4bSAndreas Gohr}
101089541d4bSAndreas Gohr
1011340756e4Sandi//Setup VIM: ex: et ts=2 enc=utf-8 :
1012