xref: /dokuwiki/inc/common.php (revision b1c94f1d8dde4ac744afbebf541d29c1f13e65f2)
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){
4397c91fb2Shenning.noren  echo str_repeat(' ', $intend)."$string\n";
4402b0b681SAndreas Gohr}
4502b0b681SAndreas Gohr
4602b0b681SAndreas Gohr/**
4702b0b681SAndreas Gohr * strips control characters (<32) from the given string
4802b0b681SAndreas Gohr *
4902b0b681SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
5002b0b681SAndreas Gohr */
5102b0b681SAndreas Gohrfunction stripctl($string){
5202b0b681SAndreas Gohr  return preg_replace('/[\x00-\x1F]+/s','',$string);
53d5197206Schris}
54d5197206Schris
55d5197206Schris/**
5615fae107Sandi * Return info about the current document as associative
57f3f0262cSandi * array.
5815fae107Sandi *
5915fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
60f3f0262cSandi */
61f3f0262cSandifunction pageinfo(){
62f3f0262cSandi  global $ID;
63f3f0262cSandi  global $REV;
64f3f0262cSandi  global $USERINFO;
65f3f0262cSandi  global $conf;
66f3f0262cSandi
676afe8dcaSchris  // include ID & REV not redundant, as some parts of DokuWiki may temporarily change $ID, e.g. p_wiki_xhtml
686afe8dcaSchris  // FIXME ... perhaps it would be better to ensure the temporary changes weren't necessary
696afe8dcaSchris  $info['id'] = $ID;
706afe8dcaSchris  $info['rev'] = $REV;
716afe8dcaSchris
72f3f0262cSandi  if($_SERVER['REMOTE_USER']){
73f3f0262cSandi    $info['userinfo']   = $USERINFO;
74f3f0262cSandi    $info['perm']       = auth_quickaclcheck($ID);
751380fc45SAndreas Gohr    $info['subscribed'] = is_subscribed($ID,$_SERVER['REMOTE_USER']);
76ee4c4a1bSAndreas Gohr    $info['client']     = $_SERVER['REMOTE_USER'];
7717ee7f66SAndreas Gohr
78f8cc712eSAndreas Gohr    // set info about manager/admin status
79f8cc712eSAndreas Gohr    $info['isadmin']   = false;
80f8cc712eSAndreas Gohr    $info['ismanager'] = false;
81f8cc712eSAndreas Gohr    if($info['perm'] == AUTH_ADMIN){
82f8cc712eSAndreas Gohr      $info['isadmin']   = true;
83f8cc712eSAndreas Gohr      $info['ismanager'] = true;
84f8cc712eSAndreas Gohr    }elseif(auth_ismanager()){
85f8cc712eSAndreas Gohr      $info['ismanager'] = true;
86f8cc712eSAndreas Gohr    }
87f8cc712eSAndreas Gohr
8817ee7f66SAndreas Gohr    // if some outside auth were used only REMOTE_USER is set
8917ee7f66SAndreas Gohr    if(!$info['userinfo']['name']){
9017ee7f66SAndreas Gohr      $info['userinfo']['name'] = $_SERVER['REMOTE_USER'];
9117ee7f66SAndreas Gohr    }
92ee4c4a1bSAndreas Gohr
93f3f0262cSandi  }else{
94f3f0262cSandi    $info['perm']       = auth_aclcheck($ID,'',null);
951380fc45SAndreas Gohr    $info['subscribed'] = false;
96ee4c4a1bSAndreas Gohr    $info['client']     = clientIP(true);
97f3f0262cSandi  }
98f3f0262cSandi
99f3f0262cSandi  $info['namespace'] = getNS($ID);
100f3f0262cSandi  $info['locked']    = checklock($ID);
1012ca9d91cSBen Coburn  $info['filepath']  = realpath(wikiFN($ID));
1022ca9d91cSBen Coburn  $info['exists']    = @file_exists($info['filepath']);
1032ca9d91cSBen Coburn  if($REV){
1042ca9d91cSBen Coburn    //check if current revision was meant
1052ca9d91cSBen Coburn    if($info['exists'] && (@filemtime($info['filepath'])==$REV)){
1062ca9d91cSBen Coburn      $REV = '';
1072ca9d91cSBen Coburn    }else{
1082ca9d91cSBen Coburn      //really use old revision
109f3f0262cSandi      $info['filepath'] = realpath(wikiFN($ID,$REV));
110f3f0262cSandi      $info['exists']   = @file_exists($info['filepath']);
111f3f0262cSandi    }
112f3f0262cSandi  }
113c112d578Sandi  $info['rev'] = $REV;
114f3f0262cSandi  if($info['exists']){
115f3f0262cSandi    $info['writable'] = (is_writable($info['filepath']) &&
116f3f0262cSandi                         ($info['perm'] >= AUTH_EDIT));
117f3f0262cSandi  }else{
118f3f0262cSandi    $info['writable'] = ($info['perm'] >= AUTH_CREATE);
119f3f0262cSandi  }
120f3f0262cSandi  $info['editable']  = ($info['writable'] && empty($info['lock']));
121f3f0262cSandi  $info['lastmod']   = @filemtime($info['filepath']);
122f3f0262cSandi
12371726d78SBen Coburn  //load page meta data
12471726d78SBen Coburn  $info['meta'] = p_get_metadata($ID);
12571726d78SBen Coburn
126652610a2Sandi  //who's the editor
127652610a2Sandi  if($REV){
12871726d78SBen Coburn    $revinfo = getRevisionInfo($ID, $REV, 1024);
129652610a2Sandi  }else{
130aa27cf05SAndreas Gohr    if (is_array($info['meta']['last_change'])) {
131aa27cf05SAndreas Gohr       $revinfo = $info['meta']['last_change'];
132aa27cf05SAndreas Gohr    } else {
133cd00a034SBen Coburn      $revinfo = getRevisionInfo($ID, $info['lastmod'], 1024);
134cd00a034SBen Coburn      // cache most recent changelog line in metadata if missing and still valid
135cd00a034SBen Coburn      if ($revinfo!==false) {
136cd00a034SBen Coburn        $info['meta']['last_change'] = $revinfo;
137cd00a034SBen Coburn        p_set_metadata($ID, array('last_change' => $revinfo));
138cd00a034SBen Coburn      }
139cd00a034SBen Coburn    }
140cd00a034SBen Coburn  }
141cd00a034SBen Coburn  //and check for an external edit
142cd00a034SBen Coburn  if($revinfo!==false && $revinfo['date']!=$info['lastmod']){
143cd00a034SBen Coburn    // cached changelog line no longer valid
144cd00a034SBen Coburn    $revinfo = false;
145cd00a034SBen Coburn    $info['meta']['last_change'] = $revinfo;
146cd00a034SBen Coburn    p_set_metadata($ID, array('last_change' => $revinfo));
147652610a2Sandi  }
148bb4866bdSchris
149652610a2Sandi  $info['ip']     = $revinfo['ip'];
150652610a2Sandi  $info['user']   = $revinfo['user'];
151652610a2Sandi  $info['sum']    = $revinfo['sum'];
15271726d78SBen Coburn  // See also $INFO['meta']['last_change'] which is the most recent log line for page $ID.
153ebf1501fSBen Coburn  // Use $INFO['meta']['last_change']['type']===DOKU_CHANGE_TYPE_MINOR_EDIT in place of $info['minor'].
15459f257aeSchris
15588f522e9Sandi  if($revinfo['user']){
15688f522e9Sandi    $info['editor'] = $revinfo['user'];
15788f522e9Sandi  }else{
15888f522e9Sandi    $info['editor'] = $revinfo['ip'];
15988f522e9Sandi  }
160652610a2Sandi
161ee4c4a1bSAndreas Gohr  // draft
162ee4c4a1bSAndreas Gohr  $draft = getCacheName($info['client'].$ID,'.draft');
163ee4c4a1bSAndreas Gohr  if(@file_exists($draft)){
164ee4c4a1bSAndreas Gohr    if(@filemtime($draft) < @filemtime(wikiFN($ID))){
165ee4c4a1bSAndreas Gohr      // remove stale draft
166ee4c4a1bSAndreas Gohr      @unlink($draft);
167ee4c4a1bSAndreas Gohr    }else{
168ee4c4a1bSAndreas Gohr      $info['draft'] = $draft;
169ee4c4a1bSAndreas Gohr    }
170ee4c4a1bSAndreas Gohr  }
171ee4c4a1bSAndreas Gohr
172f3f0262cSandi  return $info;
173f3f0262cSandi}
174f3f0262cSandi
175f3f0262cSandi/**
1762684e50aSAndreas Gohr * Build an string of URL parameters
1772684e50aSAndreas Gohr *
1782684e50aSAndreas Gohr * @author Andreas Gohr
1792684e50aSAndreas Gohr */
180b174aeaeSchrisfunction buildURLparams($params, $sep='&amp;'){
1812684e50aSAndreas Gohr  $url = '';
1822684e50aSAndreas Gohr  $amp = false;
1832684e50aSAndreas Gohr  foreach($params as $key => $val){
184b174aeaeSchris    if($amp) $url .= $sep;
1852684e50aSAndreas Gohr
1862684e50aSAndreas Gohr    $url .= $key.'=';
187b6c6979fSAndreas Gohr    $url .= rawurlencode($val);
1882684e50aSAndreas Gohr    $amp = true;
1892684e50aSAndreas Gohr  }
1902684e50aSAndreas Gohr  return $url;
1912684e50aSAndreas Gohr}
1922684e50aSAndreas Gohr
1932684e50aSAndreas Gohr/**
1942684e50aSAndreas Gohr * Build an string of html tag attributes
1952684e50aSAndreas Gohr *
1967bff22c0SAndreas Gohr * Skips keys starting with '_', values get HTML encoded
1977bff22c0SAndreas Gohr *
1982684e50aSAndreas Gohr * @author Andreas Gohr
1992684e50aSAndreas Gohr */
2004b030ce7SAndreas Gohrfunction buildAttributes($params,$skipempty=false){
2012684e50aSAndreas Gohr  $url = '';
2022684e50aSAndreas Gohr  foreach($params as $key => $val){
2037bff22c0SAndreas Gohr    if($key{0} == '_') continue;
204*b1c94f1dSAndreas Gohr    if($val === '' && $skipempty) continue;
2057bff22c0SAndreas Gohr
2062684e50aSAndreas Gohr    $url .= $key.'="';
2072684e50aSAndreas Gohr    $url .= htmlspecialchars ($val);
2082684e50aSAndreas Gohr    $url .= '" ';
2092684e50aSAndreas Gohr  }
2102684e50aSAndreas Gohr  return $url;
2112684e50aSAndreas Gohr}
2122684e50aSAndreas Gohr
2132684e50aSAndreas Gohr
2142684e50aSAndreas Gohr/**
21515fae107Sandi * This builds the breadcrumb trail and returns it as array
21615fae107Sandi *
21715fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
218f3f0262cSandi */
219f3f0262cSandifunction breadcrumbs(){
2208746e727Sandi  // we prepare the breadcrumbs early for quick session closing
2218746e727Sandi  static $crumbs = null;
2228746e727Sandi  if($crumbs != null) return $crumbs;
2238746e727Sandi
224f3f0262cSandi  global $ID;
225f3f0262cSandi  global $ACT;
226f3f0262cSandi  global $conf;
227e71ce681SAndreas Gohr  $crumbs = $_SESSION[DOKU_COOKIE]['bc'];
228f3f0262cSandi
229f3f0262cSandi  //first visit?
230f3f0262cSandi  if (!is_array($crumbs)){
231f3f0262cSandi    $crumbs = array();
232f3f0262cSandi  }
233f3f0262cSandi  //we only save on show and existing wiki documents
234a77f5846Sjan  $file = wikiFN($ID);
235a77f5846Sjan  if($ACT != 'show' || !@file_exists($file)){
236e71ce681SAndreas Gohr    $_SESSION[DOKU_COOKIE]['bc'] = $crumbs;
237f3f0262cSandi    return $crumbs;
238f3f0262cSandi  }
239a77f5846Sjan
240a77f5846Sjan  // page names
2411a84a0f3SAnika Henke  $name = noNSorNS($ID);
242a77f5846Sjan  if ($conf['useheading']) {
243a77f5846Sjan    // get page title
244955cd091SChris Smith    $title = p_get_first_heading($ID,true);
245a77f5846Sjan    if ($title) {
246a77f5846Sjan      $name = $title;
247a77f5846Sjan    }
248a77f5846Sjan  }
249a77f5846Sjan
250f3f0262cSandi  //remove ID from array
251a77f5846Sjan  if (isset($crumbs[$ID])) {
252a77f5846Sjan    unset($crumbs[$ID]);
253f3f0262cSandi  }
254f3f0262cSandi
255f3f0262cSandi  //add to array
256a77f5846Sjan  $crumbs[$ID] = $name;
257f3f0262cSandi  //reduce size
258f3f0262cSandi  while(count($crumbs) > $conf['breadcrumbs']){
259f3f0262cSandi    array_shift($crumbs);
260f3f0262cSandi  }
261f3f0262cSandi  //save to session
262e71ce681SAndreas Gohr  $_SESSION[DOKU_COOKIE]['bc'] = $crumbs;
263f3f0262cSandi  return $crumbs;
264f3f0262cSandi}
265f3f0262cSandi
266f3f0262cSandi/**
26715fae107Sandi * Filter for page IDs
26815fae107Sandi *
269f3f0262cSandi * This is run on a ID before it is outputted somewhere
270f3f0262cSandi * currently used to replace the colon with something else
271f3f0262cSandi * on Windows systems and to have proper URL encoding
27215fae107Sandi *
27349c713a3Sandi * Urlencoding is ommitted when the second parameter is false
27449c713a3Sandi *
27515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
276f3f0262cSandi */
27749c713a3Sandifunction idfilter($id,$ue=true){
278f3f0262cSandi  global $conf;
279f3f0262cSandi  if ($conf['useslash'] && $conf['userewrite']){
280f3f0262cSandi    $id = strtr($id,':','/');
281f3f0262cSandi  }elseif (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' &&
282f3f0262cSandi      $conf['userewrite']) {
283f3f0262cSandi    $id = strtr($id,':',';');
284f3f0262cSandi  }
28549c713a3Sandi  if($ue){
286b6c6979fSAndreas Gohr    $id = rawurlencode($id);
287f3f0262cSandi    $id = str_replace('%3A',':',$id); //keep as colon
288f3f0262cSandi    $id = str_replace('%2F','/',$id); //keep as slash
28949c713a3Sandi  }
290f3f0262cSandi  return $id;
291f3f0262cSandi}
292f3f0262cSandi
293f3f0262cSandi/**
294ed7b5f09Sandi * This builds a link to a wikipage
29515fae107Sandi *
2966c7843b5Sandi * It handles URL rewriting and adds additional parameter if
2976c7843b5Sandi * given in $more
2986c7843b5Sandi *
29915fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
300f3f0262cSandi */
301b174aeaeSchrisfunction wl($id='',$more='',$abs=false,$sep='&amp;'){
302f3f0262cSandi  global $conf;
3036de3759aSAndreas Gohr  if(is_array($more)){
304b174aeaeSchris    $more = buildURLparams($more,$sep);
3056de3759aSAndreas Gohr  }else{
306b174aeaeSchris    $more = str_replace(',',$sep,$more);
3076de3759aSAndreas Gohr  }
308f3f0262cSandi
309f3f0262cSandi  $id    = idfilter($id);
310ed7b5f09Sandi  if($abs){
311ed7b5f09Sandi    $xlink = DOKU_URL;
312ed7b5f09Sandi  }else{
313ed7b5f09Sandi    $xlink = DOKU_BASE;
314ed7b5f09Sandi  }
315f3f0262cSandi
3166c7843b5Sandi  if($conf['userewrite'] == 2){
3176c7843b5Sandi    $xlink .= DOKU_SCRIPT.'/'.$id;
3186c7843b5Sandi    if($more) $xlink .= '?'.$more;
3196c7843b5Sandi  }elseif($conf['userewrite']){
320f3f0262cSandi    $xlink .= $id;
321f3f0262cSandi    if($more) $xlink .= '?'.$more;
3226c7843b5Sandi  }else{
3236c7843b5Sandi    $xlink .= DOKU_SCRIPT.'?id='.$id;
324b174aeaeSchris    if($more) $xlink .= $sep.$more;
325f3f0262cSandi  }
326f3f0262cSandi
327f3f0262cSandi  return $xlink;
328f3f0262cSandi}
329f3f0262cSandi
330f3f0262cSandi/**
331f5c2808fSBen Coburn * This builds a link to an alternate page format
332f5c2808fSBen Coburn *
333f5c2808fSBen Coburn * Handles URL rewriting if enabled. Follows the style of wl().
334f5c2808fSBen Coburn *
335f5c2808fSBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
336f5c2808fSBen Coburn */
337f5c2808fSBen Coburnfunction exportlink($id='',$format='raw',$more='',$abs=false,$sep='&amp;'){
338f5c2808fSBen Coburn  global $conf;
339f5c2808fSBen Coburn  if(is_array($more)){
340f5c2808fSBen Coburn    $more = buildURLparams($more,$sep);
341f5c2808fSBen Coburn  }else{
342f5c2808fSBen Coburn    $more = str_replace(',',$sep,$more);
343f5c2808fSBen Coburn  }
344f5c2808fSBen Coburn
345f5c2808fSBen Coburn  $format = rawurlencode($format);
346f5c2808fSBen Coburn  $id = idfilter($id);
347f5c2808fSBen Coburn  if($abs){
348f5c2808fSBen Coburn    $xlink = DOKU_URL;
349f5c2808fSBen Coburn  }else{
350f5c2808fSBen Coburn    $xlink = DOKU_BASE;
351f5c2808fSBen Coburn  }
352f5c2808fSBen Coburn
353f5c2808fSBen Coburn  if($conf['userewrite'] == 2){
354f5c2808fSBen Coburn    $xlink .= DOKU_SCRIPT.'/'.$id.'?do=export_'.$format;
355f5c2808fSBen Coburn    if($more) $xlink .= $sep.$more;
356f5c2808fSBen Coburn  }elseif($conf['userewrite'] == 1){
357f5c2808fSBen Coburn    $xlink .= '_export/'.$format.'/'.$id;
358f5c2808fSBen Coburn    if($more) $xlink .= '?'.$more;
359f5c2808fSBen Coburn  }else{
360f5c2808fSBen Coburn    $xlink .= DOKU_SCRIPT.'?do=export_'.$format.$sep.'id='.$id;
361f5c2808fSBen Coburn    if($more) $xlink .= $sep.$more;
362f5c2808fSBen Coburn  }
363f5c2808fSBen Coburn
364f5c2808fSBen Coburn  return $xlink;
365f5c2808fSBen Coburn}
366f5c2808fSBen Coburn
367f5c2808fSBen Coburn/**
3686de3759aSAndreas Gohr * Build a link to a media file
3696de3759aSAndreas Gohr *
3706de3759aSAndreas Gohr * Will return a link to the detail page if $direct is false
3716de3759aSAndreas Gohr */
37255b2b31bSAndreas Gohrfunction ml($id='',$more='',$direct=true,$sep='&amp;',$abs=false){
3736de3759aSAndreas Gohr  global $conf;
3746de3759aSAndreas Gohr  if(is_array($more)){
375b174aeaeSchris    $more = buildURLparams($more,$sep);
3766de3759aSAndreas Gohr  }else{
377b174aeaeSchris    $more = str_replace(',',$sep,$more);
3786de3759aSAndreas Gohr  }
3796de3759aSAndreas Gohr
38055b2b31bSAndreas Gohr  if($abs){
38155b2b31bSAndreas Gohr    $xlink = DOKU_URL;
38255b2b31bSAndreas Gohr  }else{
3836de3759aSAndreas Gohr    $xlink = DOKU_BASE;
38455b2b31bSAndreas Gohr  }
3856de3759aSAndreas Gohr
3866de3759aSAndreas Gohr  // external URLs are always direct without rewriting
3876de3759aSAndreas Gohr  if(preg_match('#^(https?|ftp)://#i',$id)){
3886de3759aSAndreas Gohr    $xlink .= 'lib/exe/fetch.php';
3896de3759aSAndreas Gohr    if($more){
3906de3759aSAndreas Gohr      $xlink .= '?'.$more;
391b174aeaeSchris      $xlink .= $sep.'media='.rawurlencode($id);
3926de3759aSAndreas Gohr    }else{
393b6c6979fSAndreas Gohr      $xlink .= '?media='.rawurlencode($id);
3946de3759aSAndreas Gohr    }
3956de3759aSAndreas Gohr    return $xlink;
3966de3759aSAndreas Gohr  }
3976de3759aSAndreas Gohr
3986de3759aSAndreas Gohr  $id = idfilter($id);
3996de3759aSAndreas Gohr
4006de3759aSAndreas Gohr  // decide on scriptname
4016de3759aSAndreas Gohr  if($direct){
4026de3759aSAndreas Gohr    if($conf['userewrite'] == 1){
4036de3759aSAndreas Gohr      $script = '_media';
4046de3759aSAndreas Gohr    }else{
4056de3759aSAndreas Gohr      $script = 'lib/exe/fetch.php';
4066de3759aSAndreas Gohr    }
4076de3759aSAndreas Gohr  }else{
4086de3759aSAndreas Gohr    if($conf['userewrite'] == 1){
4096de3759aSAndreas Gohr      $script = '_detail';
4106de3759aSAndreas Gohr    }else{
4116de3759aSAndreas Gohr      $script = 'lib/exe/detail.php';
4126de3759aSAndreas Gohr    }
4136de3759aSAndreas Gohr  }
4146de3759aSAndreas Gohr
4156de3759aSAndreas Gohr  // build URL based on rewrite mode
4166de3759aSAndreas Gohr   if($conf['userewrite']){
4176de3759aSAndreas Gohr     $xlink .= $script.'/'.$id;
4186de3759aSAndreas Gohr     if($more) $xlink .= '?'.$more;
4196de3759aSAndreas Gohr   }else{
4206de3759aSAndreas Gohr     if($more){
421a99d3236SEsther Brunner       $xlink .= $script.'?'.$more;
422b174aeaeSchris       $xlink .= $sep.'media='.$id;
4236de3759aSAndreas Gohr     }else{
424a99d3236SEsther Brunner       $xlink .= $script.'?media='.$id;
4256de3759aSAndreas Gohr     }
4266de3759aSAndreas Gohr   }
4276de3759aSAndreas Gohr
4286de3759aSAndreas Gohr  return $xlink;
4296de3759aSAndreas Gohr}
4306de3759aSAndreas Gohr
4316de3759aSAndreas Gohr
4326de3759aSAndreas Gohr
4336de3759aSAndreas Gohr/**
434f3f0262cSandi * Just builds a link to a script
43515fae107Sandi *
436ed7b5f09Sandi * @todo   maybe obsolete
43715fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
438f3f0262cSandi */
439f3f0262cSandifunction script($script='doku.php'){
440ed7b5f09Sandi#  $link = getBaseURL();
441ed7b5f09Sandi#  $link .= $script;
442ed7b5f09Sandi#  return $link;
443ed7b5f09Sandi  return DOKU_BASE.DOKU_SCRIPT;
444f3f0262cSandi}
445f3f0262cSandi
446f3f0262cSandi/**
44715fae107Sandi * Spamcheck against wordlist
44815fae107Sandi *
449f3f0262cSandi * Checks the wikitext against a list of blocked expressions
450f3f0262cSandi * returns true if the text contains any bad words
45115fae107Sandi *
45215fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
453f3f0262cSandi */
454f3f0262cSandifunction checkwordblock(){
455f3f0262cSandi  global $TEXT;
456f3f0262cSandi  global $conf;
457f3f0262cSandi
458f3f0262cSandi  if(!$conf['usewordblock']) return false;
459f3f0262cSandi
460041d1964SAndreas Gohr  // we prepare the text a tiny bit to prevent spammers circumventing URL checks
461041d1964SAndreas Gohr  $text = preg_replace('!(\b)(www\.[\w.:?\-;,]+?\.[\w.:?\-;,]+?[\w/\#~:.?+=&%@\!\-.:?\-;,]+?)([.:?\-;,]*[^\w/\#~:.?+=&%@\!\-.:?\-;,])!i','\1http://\2 \2\3',$TEXT);
462041d1964SAndreas Gohr
463b9ac8716Schris  $wordblocks = getWordblocks();
4643e2965d7Sandi  //how many lines to read at once (to work around some PCRE limits)
4653e2965d7Sandi  if(version_compare(phpversion(),'4.3.0','<')){
4663e2965d7Sandi    //old versions of PCRE define a maximum of parenthesises even if no
4673e2965d7Sandi    //backreferences are used - the maximum is 99
4683e2965d7Sandi    //this is very bad performancewise and may even be too high still
4693e2965d7Sandi    $chunksize = 40;
4703e2965d7Sandi  }else{
471a51d08efSAndreas Gohr    //read file in chunks of 200 - this should work around the
4723e2965d7Sandi    //MAX_PATTERN_SIZE in modern PCRE
473a51d08efSAndreas Gohr    $chunksize = 200;
4743e2965d7Sandi  }
475b9ac8716Schris  while($blocks = array_splice($wordblocks,0,$chunksize)){
476f3f0262cSandi    $re = array();
477f3f0262cSandi    #build regexp from blocks
478f3f0262cSandi    foreach($blocks as $block){
479f3f0262cSandi      $block = preg_replace('/#.*$/','',$block);
480f3f0262cSandi      $block = trim($block);
481f3f0262cSandi      if(empty($block)) continue;
482f3f0262cSandi      $re[]  = $block;
483f3f0262cSandi    }
484c2525298SAndreas Gohr    if(count($re) && preg_match('#('.join('|',$re).')#si',$text)) {
485b9ac8716Schris      return true;
486b9ac8716Schris    }
487703f6fdeSandi  }
488f3f0262cSandi  return false;
489f3f0262cSandi}
490f3f0262cSandi
491f3f0262cSandi/**
49215fae107Sandi * Return the IP of the client
49315fae107Sandi *
4946d8affe6SAndreas Gohr * Honours X-Forwarded-For and X-Real-IP Proxy Headers
49515fae107Sandi *
4966d8affe6SAndreas Gohr * It returns a comma separated list of IPs if the above mentioned
4976d8affe6SAndreas Gohr * headers are set. If the single parameter is set, it tries to return
4986d8affe6SAndreas Gohr * a routable public address, prefering the ones suplied in the X
4996d8affe6SAndreas Gohr * headers
5006d8affe6SAndreas Gohr *
5016d8affe6SAndreas Gohr * @param  boolean $single If set only a single IP is returned
50215fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
503f3f0262cSandi */
5046d8affe6SAndreas Gohrfunction clientIP($single=false){
5056d8affe6SAndreas Gohr  $ip = array();
5066d8affe6SAndreas Gohr  $ip[] = $_SERVER['REMOTE_ADDR'];
507bb4866bdSchris  if(!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
5086d8affe6SAndreas Gohr    $ip = array_merge($ip,explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']));
509bb4866bdSchris  if(!empty($_SERVER['HTTP_X_REAL_IP']))
5106d8affe6SAndreas Gohr    $ip = array_merge($ip,explode(',',$_SERVER['HTTP_X_REAL_IP']));
5116d8affe6SAndreas Gohr
5126d8affe6SAndreas Gohr  // remove any non-IP stuff
5136d8affe6SAndreas Gohr  $cnt = count($ip);
5144ff28443Schris  $match = array();
5156d8affe6SAndreas Gohr  for($i=0; $i<$cnt; $i++){
5164ff28443Schris    if(preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/',$ip[$i],$match)) {
5174ff28443Schris      $ip[$i] = $match[0];
5184ff28443Schris    } else {
5194ff28443Schris      $ip[$i] = '';
5204ff28443Schris    }
5216d8affe6SAndreas Gohr    if(empty($ip[$i])) unset($ip[$i]);
522f3f0262cSandi  }
5236d8affe6SAndreas Gohr  $ip = array_values(array_unique($ip));
5246d8affe6SAndreas Gohr  if(!$ip[0]) $ip[0] = '0.0.0.0'; // for some strange reason we don't have a IP
5256d8affe6SAndreas Gohr
5266d8affe6SAndreas Gohr  if(!$single) return join(',',$ip);
5276d8affe6SAndreas Gohr
5286d8affe6SAndreas Gohr  // decide which IP to use, trying to avoid local addresses
5296d8affe6SAndreas Gohr  $ip = array_reverse($ip);
5306d8affe6SAndreas Gohr  foreach($ip as $i){
5316d8affe6SAndreas Gohr    if(preg_match('/^(127\.|10\.|192\.168\.|172\.((1[6-9])|(2[0-9])|(3[0-1]))\.)/',$i)){
5326d8affe6SAndreas Gohr      continue;
5336d8affe6SAndreas Gohr    }else{
5346d8affe6SAndreas Gohr      return $i;
5356d8affe6SAndreas Gohr    }
5366d8affe6SAndreas Gohr  }
5376d8affe6SAndreas Gohr  // still here? just use the first (last) address
5386d8affe6SAndreas Gohr  return $ip[0];
539f3f0262cSandi}
540f3f0262cSandi
541f3f0262cSandi/**
54215fae107Sandi * Checks if a given page is currently locked.
54315fae107Sandi *
544f3f0262cSandi * removes stale lockfiles
54515fae107Sandi *
54615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
547f3f0262cSandi */
548f3f0262cSandifunction checklock($id){
549f3f0262cSandi  global $conf;
550c9b4bd1eSBen Coburn  $lock = wikiLockFN($id);
551f3f0262cSandi
552f3f0262cSandi  //no lockfile
553f3f0262cSandi  if(!@file_exists($lock)) return false;
554f3f0262cSandi
555f3f0262cSandi  //lockfile expired
556f3f0262cSandi  if((time() - filemtime($lock)) > $conf['locktime']){
557d8186216SBen Coburn    @unlink($lock);
558f3f0262cSandi    return false;
559f3f0262cSandi  }
560f3f0262cSandi
561f3f0262cSandi  //my own lock
562f3f0262cSandi  $ip = io_readFile($lock);
563f3f0262cSandi  if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){
564f3f0262cSandi    return false;
565f3f0262cSandi  }
566f3f0262cSandi
567f3f0262cSandi  return $ip;
568f3f0262cSandi}
569f3f0262cSandi
570f3f0262cSandi/**
57115fae107Sandi * Lock a page for editing
57215fae107Sandi *
57315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
574f3f0262cSandi */
575f3f0262cSandifunction lock($id){
576c9b4bd1eSBen Coburn  $lock = wikiLockFN($id);
577f3f0262cSandi  if($_SERVER['REMOTE_USER']){
578f3f0262cSandi    io_saveFile($lock,$_SERVER['REMOTE_USER']);
579f3f0262cSandi  }else{
580f3f0262cSandi    io_saveFile($lock,clientIP());
581f3f0262cSandi  }
582f3f0262cSandi}
583f3f0262cSandi
584f3f0262cSandi/**
58515fae107Sandi * Unlock a page if it was locked by the user
586f3f0262cSandi *
58715fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
58815fae107Sandi * @return bool true if a lock was removed
589f3f0262cSandi */
590f3f0262cSandifunction unlock($id){
591c9b4bd1eSBen Coburn  $lock = wikiLockFN($id);
592f3f0262cSandi  if(@file_exists($lock)){
593f3f0262cSandi    $ip = io_readFile($lock);
594f3f0262cSandi    if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){
595f3f0262cSandi      @unlink($lock);
596f3f0262cSandi      return true;
597f3f0262cSandi    }
598f3f0262cSandi  }
599f3f0262cSandi  return false;
600f3f0262cSandi}
601f3f0262cSandi
602f3f0262cSandi/**
603f3f0262cSandi * convert line ending to unix format
604f3f0262cSandi *
60515fae107Sandi * @see    formText() for 2crlf conversion
60615fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
607f3f0262cSandi */
608f3f0262cSandifunction cleanText($text){
609f3f0262cSandi  $text = preg_replace("/(\015\012)|(\015)/","\012",$text);
610f3f0262cSandi  return $text;
611f3f0262cSandi}
612f3f0262cSandi
613f3f0262cSandi/**
614f3f0262cSandi * Prepares text for print in Webforms by encoding special chars.
615f3f0262cSandi * It also converts line endings to Windows format which is
616f3f0262cSandi * pseudo standard for webforms.
617f3f0262cSandi *
61815fae107Sandi * @see    cleanText() for 2unix conversion
61915fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
620f3f0262cSandi */
621f3f0262cSandifunction formText($text){
6225b7d45a5SAndreas Gohr  $text = str_replace("\012","\015\012",$text);
623f3f0262cSandi  return htmlspecialchars($text);
624f3f0262cSandi}
625f3f0262cSandi
626f3f0262cSandi/**
62715fae107Sandi * Returns the specified local text in raw format
62815fae107Sandi *
62915fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
630f3f0262cSandi */
631f3f0262cSandifunction rawLocale($id){
632f3f0262cSandi  return io_readFile(localeFN($id));
633f3f0262cSandi}
634f3f0262cSandi
635f3f0262cSandi/**
636f3f0262cSandi * Returns the raw WikiText
63715fae107Sandi *
63815fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
639f3f0262cSandi */
640f3f0262cSandifunction rawWiki($id,$rev=''){
641cc7d0c94SBen Coburn  return io_readWikiPage(wikiFN($id, $rev), $id, $rev);
642f3f0262cSandi}
643f3f0262cSandi
644f3f0262cSandi/**
6457146cee2SAndreas Gohr * Returns the pagetemplate contents for the ID's namespace
6467146cee2SAndreas Gohr *
6477146cee2SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
6487146cee2SAndreas Gohr */
649b7d5a5f0SAndreas Gohrfunction pageTemplate($data){
650b7d5a5f0SAndreas Gohr  $id = $data[0];
651a15ce62dSEsther Brunner  global $conf;
652a15ce62dSEsther Brunner  global $INFO;
653a15ce62dSEsther Brunner  $tpl = io_readFile(dirname(wikiFN($id)).'/_template.txt');
654a15ce62dSEsther Brunner  $tpl = str_replace('@ID@',$id,$tpl);
655a15ce62dSEsther Brunner  $tpl = str_replace('@NS@',getNS($id),$tpl);
656a15ce62dSEsther Brunner  $tpl = str_replace('@PAGE@',strtr(noNS($id),'_',' '),$tpl);
657a15ce62dSEsther Brunner  $tpl = str_replace('@USER@',$_SERVER['REMOTE_USER'],$tpl);
658a15ce62dSEsther Brunner  $tpl = str_replace('@NAME@',$INFO['userinfo']['name'],$tpl);
659a15ce62dSEsther Brunner  $tpl = str_replace('@MAIL@',$INFO['userinfo']['mail'],$tpl);
660a15ce62dSEsther Brunner  $tpl = str_replace('@DATE@',date($conf['dformat']),$tpl);
661a15ce62dSEsther Brunner  return $tpl;
6627146cee2SAndreas Gohr}
6637146cee2SAndreas Gohr
6647146cee2SAndreas Gohr
6657146cee2SAndreas Gohr/**
66615fae107Sandi * Returns the raw Wiki Text in three slices.
66715fae107Sandi *
66815fae107Sandi * The range parameter needs to have the form "from-to"
66915cfe303Sandi * and gives the range of the section in bytes - no
67015cfe303Sandi * UTF-8 awareness is needed.
671f3f0262cSandi * The returned order is prefix, section and suffix.
67215fae107Sandi *
67315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
674f3f0262cSandi */
675f3f0262cSandifunction rawWikiSlices($range,$id,$rev=''){
676f3f0262cSandi  list($from,$to) = split('-',$range,2);
677cc7d0c94SBen Coburn  $text = io_readWikiPage(wikiFN($id, $rev), $id, $rev);
678f3f0262cSandi  if(!$from) $from = 0;
679c3d8e19bSandi  if(!$to)   $to   = strlen($text)+1;
680f3f0262cSandi
68115cfe303Sandi  $slices[0] = substr($text,0,$from-1);
68215cfe303Sandi  $slices[1] = substr($text,$from-1,$to-$from);
68315cfe303Sandi  $slices[2] = substr($text,$to);
684f3f0262cSandi
685f3f0262cSandi  return $slices;
686f3f0262cSandi}
687f3f0262cSandi
688f3f0262cSandi/**
68915fae107Sandi * Joins wiki text slices
69015fae107Sandi *
691f3f0262cSandi * function to join the text slices with correct lineendings again.
692f3f0262cSandi * When the pretty parameter is set to true it adds additional empty
693f3f0262cSandi * lines between sections if needed (used on saving).
69415fae107Sandi *
69515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
696f3f0262cSandi */
697f3f0262cSandifunction con($pre,$text,$suf,$pretty=false){
698f3f0262cSandi
699f3f0262cSandi  if($pretty){
700f3f0262cSandi    if($pre && substr($pre,-1) != "\n") $pre .= "\n";
701f3f0262cSandi    if($suf && substr($text,-1) != "\n") $text .= "\n";
702f3f0262cSandi  }
703f3f0262cSandi
704f3f0262cSandi  if($pre) $pre .= "\n";
705f3f0262cSandi  if($suf) $text .= "\n";
706f3f0262cSandi  return $pre.$text.$suf;
707f3f0262cSandi}
708f3f0262cSandi
709f3f0262cSandi/**
710a701424fSBen Coburn * Saves a wikitext by calling io_writeWikiPage.
711a701424fSBen Coburn * Also directs changelog and attic updates.
71215fae107Sandi *
71315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
71471726d78SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
715f3f0262cSandi */
716b6912aeaSAndreas Gohrfunction saveWikiText($id,$text,$summary,$minor=false){
717a701424fSBen Coburn  /* Note to developers:
718a701424fSBen Coburn     This code is subtle and delicate. Test the behavior of
719a701424fSBen Coburn     the attic and changelog with dokuwiki and external edits
720a701424fSBen Coburn     after any changes. External edits change the wiki page
721a701424fSBen Coburn     directly without using php or dokuwiki.
722a701424fSBen Coburn  */
723f3f0262cSandi  global $conf;
724f3f0262cSandi  global $lang;
72571726d78SBen Coburn  global $REV;
726f3f0262cSandi  // ignore if no changes were made
727f3f0262cSandi  if($text == rawWiki($id,'')){
728f3f0262cSandi    return;
729f3f0262cSandi  }
730f3f0262cSandi
731f3f0262cSandi  $file = wikiFN($id);
732a701424fSBen Coburn  $old = @filemtime($file); // from page
73371726d78SBen Coburn  $wasRemoved = empty($text);
734d8186216SBen Coburn  $wasCreated = !@file_exists($file);
73571726d78SBen Coburn  $wasReverted = ($REV==true);
736e45b34cdSBen Coburn  $newRev = false;
737a701424fSBen Coburn  $oldRev = getRevisions($id, -1, 1, 1024); // from changelog
738a701424fSBen Coburn  $oldRev = (int)(empty($oldRev)?0:$oldRev[0]);
739a701424fSBen Coburn  if(!@file_exists(wikiFN($id, $old)) && @file_exists($file) && $old>=$oldRev) {
74046844156SBen Coburn    // add old revision to the attic if missing
74146844156SBen Coburn    saveOldRevision($id);
74246844156SBen Coburn    // add a changelog entry if this edit came from outside dokuwiki
743a701424fSBen Coburn    if ($old>$oldRev) {
744ebf1501fSBen Coburn      addLogEntry($old, $id, DOKU_CHANGE_TYPE_EDIT, $lang['external_edit'], '', array('ExternalEdit'=>true));
74546844156SBen Coburn      // remove soon to be stale instructions
74646844156SBen Coburn      $cache = new cache_instructions($id, $file);
74746844156SBen Coburn      $cache->removeCache();
74846844156SBen Coburn    }
74946844156SBen Coburn  }
750f3f0262cSandi
75171726d78SBen Coburn  if ($wasRemoved){
752e45b34cdSBen Coburn    // pre-save deleted revision
753e45b34cdSBen Coburn    @touch($file);
75446844156SBen Coburn    clearstatcache();
755e45b34cdSBen Coburn    $newRev = saveOldRevision($id);
756e1f3d9e1SEsther Brunner    // remove empty file
757f3f0262cSandi    @unlink($file);
75871726d78SBen Coburn    // remove old meta info...
759e1f3d9e1SEsther Brunner    $mfiles = metaFiles($id);
76071726d78SBen Coburn    $changelog = metaFN($id, '.changes');
761e1f3d9e1SEsther Brunner    foreach ($mfiles as $mfile) {
76271726d78SBen Coburn      // but keep per-page changelog to preserve page history
763d8186216SBen Coburn      if (@file_exists($mfile) && $mfile!==$changelog) { @unlink($mfile); }
764b158d625SSteven Danz    }
765f3f0262cSandi    $del = true;
7663ce054b3Sandi    // autoset summary on deletion
7673ce054b3Sandi    if(empty($summary)) $summary = $lang['deleted'];
76853d6ccfeSandi    // remove empty namespaces
769cc7d0c94SBen Coburn    io_sweepNS($id, 'datadir');
770cc7d0c94SBen Coburn    io_sweepNS($id, 'mediadir');
771f3f0262cSandi  }else{
772cc7d0c94SBen Coburn    // save file (namespace dir is created in io_writeWikiPage)
773cc7d0c94SBen Coburn    io_writeWikiPage($file, $text, $id);
77446844156SBen Coburn    // pre-save the revision, to keep the attic in sync
77546844156SBen Coburn    $newRev = saveOldRevision($id);
776f3f0262cSandi    $del = false;
777f3f0262cSandi  }
778f3f0262cSandi
77971726d78SBen Coburn  // select changelog line type
78071726d78SBen Coburn  $extra = '';
781ebf1501fSBen Coburn  $type = DOKU_CHANGE_TYPE_EDIT;
78271726d78SBen Coburn  if ($wasReverted) {
783ebf1501fSBen Coburn    $type = DOKU_CHANGE_TYPE_REVERT;
78471726d78SBen Coburn    $extra = $REV;
78571726d78SBen Coburn  }
786ebf1501fSBen Coburn  else if ($wasCreated) { $type = DOKU_CHANGE_TYPE_CREATE; }
787ebf1501fSBen Coburn  else if ($wasRemoved) { $type = DOKU_CHANGE_TYPE_DELETE; }
788ebf1501fSBen Coburn  else if ($minor && $conf['useacl'] && $_SERVER['REMOTE_USER']) { $type = DOKU_CHANGE_TYPE_MINOR_EDIT; } //minor edits only for logged in users
78971726d78SBen Coburn
790e45b34cdSBen Coburn  addLogEntry($newRev, $id, $type, $summary, $extra);
79126a0801fSAndreas Gohr  // send notify mails
79290033e9dSAndreas Gohr  notify($id,'admin',$old,$summary,$minor);
79390033e9dSAndreas Gohr  notify($id,'subscribers',$old,$summary,$minor);
794f3f0262cSandi
795ce6b63d9Schris  // update the purgefile (timestamp of the last time anything within the wiki was changed)
79698407a7aSandi  io_saveFile($conf['cachedir'].'/purgefile',time());
797f3f0262cSandi}
798f3f0262cSandi
799f3f0262cSandi/**
800f3f0262cSandi * moves the current version to the attic and returns its
801f3f0262cSandi * revision date
80215fae107Sandi *
80315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
804f3f0262cSandi */
805f3f0262cSandifunction saveOldRevision($id){
806f3f0262cSandi  global $conf;
807f3f0262cSandi  $oldf = wikiFN($id);
808f3f0262cSandi  if(!@file_exists($oldf)) return '';
809f3f0262cSandi  $date = filemtime($oldf);
810f3f0262cSandi  $newf = wikiFN($id,$date);
811cc7d0c94SBen Coburn  io_writeWikiPage($newf, rawWiki($id), $id, $date);
812f3f0262cSandi  return $date;
813f3f0262cSandi}
814f3f0262cSandi
815f3f0262cSandi/**
81626a0801fSAndreas Gohr * Sends a notify mail on page change
81726a0801fSAndreas Gohr *
81826a0801fSAndreas Gohr * @param  string  $id       The changed page
81926a0801fSAndreas Gohr * @param  string  $who      Who to notify (admin|subscribers)
82026a0801fSAndreas Gohr * @param  int     $rev      Old page revision
82126a0801fSAndreas Gohr * @param  string  $summary  What changed
82290033e9dSAndreas Gohr * @param  boolean $minor    Is this a minor edit?
82302a498e7Schris * @param  array   $replace  Additional string substitutions, @KEY@ to be replaced by value
82415fae107Sandi *
82515fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
826f3f0262cSandi */
82702a498e7Schrisfunction notify($id,$who,$rev='',$summary='',$minor=false,$replace=array()){
828f3f0262cSandi  global $lang;
829f3f0262cSandi  global $conf;
83030d7d718SMike Frysinger  global $INFO;
831b158d625SSteven Danz
83226a0801fSAndreas Gohr  // decide if there is something to do
83326a0801fSAndreas Gohr  if($who == 'admin'){
83426a0801fSAndreas Gohr    if(empty($conf['notify'])) return; //notify enabled?
835f3f0262cSandi    $text = rawLocale('mailtext');
83626a0801fSAndreas Gohr    $to   = $conf['notify'];
83726a0801fSAndreas Gohr    $bcc  = '';
83826a0801fSAndreas Gohr  }elseif($who == 'subscribers'){
83926a0801fSAndreas Gohr    if(!$conf['subscribers']) return; //subscribers enabled?
84090033e9dSAndreas Gohr    if($conf['useacl'] && $_SERVER['REMOTE_USER'] && $minor) return; //skip minors
84126a0801fSAndreas Gohr    $bcc  = subscriber_addresslist($id);
84226a0801fSAndreas Gohr    if(empty($bcc)) return;
84326a0801fSAndreas Gohr    $to   = '';
84426a0801fSAndreas Gohr    $text = rawLocale('subscribermail');
845a06e4bdbSSebastian Harl  }elseif($who == 'register'){
846a06e4bdbSSebastian Harl    if(empty($conf['registernotify'])) return;
847a06e4bdbSSebastian Harl    $text = rawLocale('registermail');
848a06e4bdbSSebastian Harl    $to   = $conf['registernotify'];
849a06e4bdbSSebastian Harl    $bcc  = '';
85026a0801fSAndreas Gohr  }else{
85126a0801fSAndreas Gohr    return; //just to be safe
85226a0801fSAndreas Gohr  }
85326a0801fSAndreas Gohr
854f3f0262cSandi  $text = str_replace('@DATE@',date($conf['dformat']),$text);
855f3f0262cSandi  $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text);
856f3f0262cSandi  $text = str_replace('@IPADDRESS@',$_SERVER['REMOTE_ADDR'],$text);
857f3f0262cSandi  $text = str_replace('@HOSTNAME@',gethostbyaddr($_SERVER['REMOTE_ADDR']),$text);
858c9321d91SAndreas Gohr  $text = str_replace('@NEWPAGE@',wl($id,'',true,'&'),$text);
85926a0801fSAndreas Gohr  $text = str_replace('@PAGE@',$id,$text);
86026a0801fSAndreas Gohr  $text = str_replace('@TITLE@',$conf['title'],$text);
861ed7b5f09Sandi  $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text);
862f3f0262cSandi  $text = str_replace('@SUMMARY@',$summary,$text);
8637a82afdcSandi  $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text);
864f3f0262cSandi
86502a498e7Schris  foreach ($replace as $key => $substitution) {
86602a498e7Schris    $text = str_replace('@'.strtoupper($key).'@',$substitution, $text);
86702a498e7Schris  }
86802a498e7Schris
869a06e4bdbSSebastian Harl  if($who == 'register'){
870a06e4bdbSSebastian Harl    $subject = $lang['mail_new_user'].' '.$summary;
871a06e4bdbSSebastian Harl  }elseif($rev){
872f3f0262cSandi    $subject = $lang['mail_changed'].' '.$id;
873c9321d91SAndreas Gohr    $text = str_replace('@OLDPAGE@',wl($id,"rev=$rev",true,'&'),$text);
874ccdfa6c0SAndreas Gohr    require_once(DOKU_INC.'inc/DifferenceEngine.php');
875f3f0262cSandi    $df  = new Diff(split("\n",rawWiki($id,$rev)),
876f3f0262cSandi                    split("\n",rawWiki($id)));
877f3f0262cSandi    $dformat = new UnifiedDiffFormatter();
878f3f0262cSandi    $diff    = $dformat->format($df);
879f3f0262cSandi  }else{
880f3f0262cSandi    $subject=$lang['mail_newpage'].' '.$id;
881f3f0262cSandi    $text = str_replace('@OLDPAGE@','none',$text);
882f3f0262cSandi    $diff = rawWiki($id);
883f3f0262cSandi  }
884f3f0262cSandi  $text = str_replace('@DIFF@',$diff,$text);
885241f3a36Sandi  $subject = '['.$conf['title'].'] '.$subject;
886f3f0262cSandi
88730d7d718SMike Frysinger  $from = $conf['mailfrom'];
88830d7d718SMike Frysinger  $from = str_replace('@USER@',$_SERVER['REMOTE_USER'],$from);
88930d7d718SMike Frysinger  $from = str_replace('@NAME@',$INFO['userinfo']['name'],$from);
89030d7d718SMike Frysinger  $from = str_replace('@MAIL@',$INFO['userinfo']['mail'],$from);
89130d7d718SMike Frysinger
89230d7d718SMike Frysinger  mail_send($to,$subject,$text,$from,'',$bcc);
893f3f0262cSandi}
894f3f0262cSandi
89515fae107Sandi/**
896f3f0262cSandi * extracts the query from a google referer
89715fae107Sandi *
8986b13307fSandi * @todo   should be more generic and support yahoo et al
89915fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
900f3f0262cSandi */
901f3f0262cSandifunction getGoogleQuery(){
902f3f0262cSandi  $url = parse_url($_SERVER['HTTP_REFERER']);
9035c3f206fSandi  if(!$url) return '';
904f3f0262cSandi
905f3f0262cSandi  if(!preg_match("#google\.#i",$url['host'])) return '';
906f3f0262cSandi  $query = array();
907f3f0262cSandi  parse_str($url['query'],$query);
908f3f0262cSandi
909f3f0262cSandi  return $query['q'];
910f3f0262cSandi}
911f3f0262cSandi
912f3f0262cSandi/**
91315fae107Sandi * Try to set correct locale
91415fae107Sandi *
915095bfd5cSandi * @deprecated No longer used
91615fae107Sandi * @author     Andreas Gohr <andi@splitbrain.org>
917f3f0262cSandi */
918f3f0262cSandifunction setCorrectLocale(){
919f3f0262cSandi  global $conf;
920f3f0262cSandi  global $lang;
921f3f0262cSandi
922f3f0262cSandi  $enc = strtoupper($lang['encoding']);
923f3f0262cSandi  foreach ($lang['locales'] as $loc){
924f3f0262cSandi    //try locale
925f3f0262cSandi    if(@setlocale(LC_ALL,$loc)) return;
926f3f0262cSandi    //try loceale with encoding
927f3f0262cSandi    if(@setlocale(LC_ALL,"$loc.$enc")) return;
928f3f0262cSandi  }
929f3f0262cSandi  //still here? try to set from environment
930f3f0262cSandi  @setlocale(LC_ALL,"");
931f3f0262cSandi}
932f3f0262cSandi
933f3f0262cSandi/**
934f3f0262cSandi * Return the human readable size of a file
935f3f0262cSandi *
936f3f0262cSandi * @param       int    $size   A file size
937f3f0262cSandi * @param       int    $dec    A number of decimal places
938f3f0262cSandi * @author      Martin Benjamin <b.martin@cybernet.ch>
939f3f0262cSandi * @author      Aidan Lister <aidan@php.net>
940f3f0262cSandi * @version     1.0.0
941f3f0262cSandi */
942f31d5b73Sandifunction filesize_h($size, $dec = 1){
943f3f0262cSandi  $sizes = array('B', 'KB', 'MB', 'GB');
944f3f0262cSandi  $count = count($sizes);
945f3f0262cSandi  $i = 0;
946f3f0262cSandi
947f3f0262cSandi  while ($size >= 1024 && ($i < $count - 1)) {
948f3f0262cSandi    $size /= 1024;
949f3f0262cSandi    $i++;
950f3f0262cSandi  }
951f3f0262cSandi
952f3f0262cSandi  return round($size, $dec) . ' ' . $sizes[$i];
953f3f0262cSandi}
954f3f0262cSandi
95515fae107Sandi/**
95600a7b5adSEsther Brunner * return an obfuscated email address in line with $conf['mailguard'] setting
95700a7b5adSEsther Brunner *
95800a7b5adSEsther Brunner * @author Harry Fuecks <hfuecks@gmail.com>
95900a7b5adSEsther Brunner * @author Christopher Smith <chris@jalakai.co.uk>
96000a7b5adSEsther Brunner */
96100a7b5adSEsther Brunnerfunction obfuscate($email) {
96200a7b5adSEsther Brunner  global $conf;
96300a7b5adSEsther Brunner
96400a7b5adSEsther Brunner  switch ($conf['mailguard']) {
96500a7b5adSEsther Brunner    case 'visible' :
96600a7b5adSEsther Brunner      $obfuscate = array('@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] ');
96700a7b5adSEsther Brunner      return strtr($email, $obfuscate);
96800a7b5adSEsther Brunner
96900a7b5adSEsther Brunner    case 'hex' :
97000a7b5adSEsther Brunner      $encode = '';
97100a7b5adSEsther Brunner      for ($x=0; $x < strlen($email); $x++) $encode .= '&#x' . bin2hex($email{$x}).';';
97200a7b5adSEsther Brunner      return $encode;
97300a7b5adSEsther Brunner
97400a7b5adSEsther Brunner    case 'none' :
97500a7b5adSEsther Brunner    default :
97600a7b5adSEsther Brunner      return $email;
97700a7b5adSEsther Brunner  }
97800a7b5adSEsther Brunner}
97900a7b5adSEsther Brunner
98000a7b5adSEsther Brunner/**
981b158d625SSteven Danz * Let us know if a user is tracking a page
982b158d625SSteven Danz *
9831380fc45SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
984b158d625SSteven Danz */
9851380fc45SAndreas Gohrfunction is_subscribed($id,$uid){
9861380fc45SAndreas Gohr  $file=metaFN($id,'.mlist');
9871380fc45SAndreas Gohr  if (@file_exists($file)) {
988b158d625SSteven Danz    $mlist = file($file);
9891380fc45SAndreas Gohr    $pos = array_search($uid."\n",$mlist);
9901380fc45SAndreas Gohr    return is_int($pos);
991b158d625SSteven Danz  }
9921380fc45SAndreas Gohr
993b158d625SSteven Danz  return false;
994b158d625SSteven Danz}
995340756e4Sandi
996f9eb5648Ssteven-danz/**
997f9eb5648Ssteven-danz * Return a string with the email addresses of all the
998f9eb5648Ssteven-danz * users subscribed to a page
999f9eb5648Ssteven-danz *
100026a0801fSAndreas Gohr * @author Steven Danz <steven-danz@kc.rr.com>
1001f9eb5648Ssteven-danz */
1002f9eb5648Ssteven-danzfunction subscriber_addresslist($id){
1003f9eb5648Ssteven-danz  global $conf;
1004cd52f92dSchris  global $auth;
1005f9eb5648Ssteven-danz
1006f9eb5648Ssteven-danz  $emails = '';
1007f9eb5648Ssteven-danz
100826a0801fSAndreas Gohr  if (!$conf['subscribers']) return;
100926a0801fSAndreas Gohr
1010f9eb5648Ssteven-danz  $mlist = array();
1011f9eb5648Ssteven-danz  $file=metaFN($id,'.mlist');
1012d8186216SBen Coburn  if (@file_exists($file)) {
1013f9eb5648Ssteven-danz    $mlist = file($file);
1014f9eb5648Ssteven-danz  }
1015f9eb5648Ssteven-danz  if(count($mlist) > 0) {
1016f9eb5648Ssteven-danz    foreach ($mlist as $who) {
1017f9eb5648Ssteven-danz      $who = rtrim($who);
1018cd52f92dSchris      $info = $auth->getUserData($who);
1019f9eb5648Ssteven-danz      $level = auth_aclcheck($id,$who,$info['grps']);
1020f9eb5648Ssteven-danz      if ($level >= AUTH_READ) {
1021f9eb5648Ssteven-danz        if (strcasecmp($info['mail'],$conf['notify']) != 0) {
1022f9eb5648Ssteven-danz          if (empty($emails)) {
1023f9eb5648Ssteven-danz            $emails = $info['mail'];
1024f9eb5648Ssteven-danz          } else {
1025f9eb5648Ssteven-danz            $emails = "$emails,".$info['mail'];
1026f9eb5648Ssteven-danz          }
1027f9eb5648Ssteven-danz        }
1028f9eb5648Ssteven-danz      }
1029f9eb5648Ssteven-danz    }
1030f9eb5648Ssteven-danz  }
1031f9eb5648Ssteven-danz
1032f9eb5648Ssteven-danz  return $emails;
1033f9eb5648Ssteven-danz}
1034f9eb5648Ssteven-danz
103589541d4bSAndreas Gohr/**
103689541d4bSAndreas Gohr * Removes quoting backslashes
103789541d4bSAndreas Gohr *
103889541d4bSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
103989541d4bSAndreas Gohr */
104089541d4bSAndreas Gohrfunction unslash($string,$char="'"){
104189541d4bSAndreas Gohr  return str_replace('\\'.$char,$char,$string);
104289541d4bSAndreas Gohr}
104389541d4bSAndreas Gohr
1044340756e4Sandi//Setup VIM: ex: et ts=2 enc=utf-8 :
1045