xref: /dokuwiki/inc/io.php (revision cc7d0c94bfa9c4c59fad7c52eb7c9b0decffb885)
1ed7b5f09Sandi<?php
215fae107Sandi/**
315fae107Sandi * File IO functions
415fae107Sandi *
515fae107Sandi * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
615fae107Sandi * @author     Andreas Gohr <andi@splitbrain.org>
715fae107Sandi */
815fae107Sandi
9ed7b5f09Sandi  if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
10ed7b5f09Sandi  require_once(DOKU_INC.'inc/common.php');
119b307a83SAndreas Gohr  require_once(DOKU_INC.'inc/HTTPClient.php');
12*cc7d0c94SBen Coburn  require_once(DOKU_INC.'inc/events.php');
13*cc7d0c94SBen Coburn  require_once(DOKU_INC.'inc/utf8.php');
14f3f0262cSandi
15f3f0262cSandi/**
1653d6ccfeSandi * Removes empty directories
1753d6ccfeSandi *
18*cc7d0c94SBen Coburn * Sends IO_NAMESPACE_DELETED events for 'pages' and 'media' namespaces.
19*cc7d0c94SBen Coburn * Event data:
20*cc7d0c94SBen Coburn * $data[0]    ns: The colon separated namespace path minus the trailing page name.
21*cc7d0c94SBen Coburn * $data[1]    ns_type: 'pages' or 'media' namespace tree.
22*cc7d0c94SBen Coburn *
2353d6ccfeSandi * @todo use safemode hack
2453d6ccfeSandi * @author  Andreas Gohr <andi@splitbrain.org>
25*cc7d0c94SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
2653d6ccfeSandi */
27755f1e03SAndreas Gohrfunction io_sweepNS($id,$basedir='datadir'){
2853d6ccfeSandi  global $conf;
29*cc7d0c94SBen Coburn  $types = array ('datadir'=>'pages', 'mediadir'=>'media');
30*cc7d0c94SBen Coburn  $ns_type = (isset($types[$basedir])?$types[$basedir]:false);
3153d6ccfeSandi
3253d6ccfeSandi  //scan all namespaces
3353d6ccfeSandi  while(($id = getNS($id)) !== false){
34755f1e03SAndreas Gohr    $dir = $conf[$basedir].'/'.utf8_encodeFN(str_replace(':','/',$id));
3553d6ccfeSandi
3653d6ccfeSandi    //try to delete dir else return
37*cc7d0c94SBen Coburn    if(@rmdir($dir)) {
38*cc7d0c94SBen Coburn      if ($ns_type!==false) {
39*cc7d0c94SBen Coburn        $data = array($id, $ns_type);
40*cc7d0c94SBen Coburn        trigger_event('IO_NAMESPACE_DELETED', $data);
41*cc7d0c94SBen Coburn      }
42*cc7d0c94SBen Coburn    } else { return; }
43*cc7d0c94SBen Coburn  }
44*cc7d0c94SBen Coburn}
45*cc7d0c94SBen Coburn
46*cc7d0c94SBen Coburn/**
47*cc7d0c94SBen Coburn * Used to read in a DokuWiki page from file, and send IO_WIKIPAGE_READ events.
48*cc7d0c94SBen Coburn *
49*cc7d0c94SBen Coburn * Generates the action event which delegates to io_readFile().
50*cc7d0c94SBen Coburn * Action plugins are allowed to modify the page content in transit.
51*cc7d0c94SBen Coburn * The file path should not be changed.
52*cc7d0c94SBen Coburn *
53*cc7d0c94SBen Coburn * Event data:
54*cc7d0c94SBen Coburn * $data[0]    The raw arguments for io_readFile as an array.
55*cc7d0c94SBen Coburn * $data[1]    ns: The colon separated namespace path minus the trailing page name. (false if root ns)
56*cc7d0c94SBen Coburn * $data[2]    page_name: The wiki page name.
57*cc7d0c94SBen Coburn * $data[3]    rev: The page revision, false for current wiki pages.
58*cc7d0c94SBen Coburn *
59*cc7d0c94SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
60*cc7d0c94SBen Coburn */
61*cc7d0c94SBen Coburnfunction io_readWikiPage($file, $id, $rev=false) {
62*cc7d0c94SBen Coburn    if (empty($rev)) { $rev = false; }
63*cc7d0c94SBen Coburn    $data = array(array($file, false), getNS($id), noNS($id), $rev);
64*cc7d0c94SBen Coburn    return trigger_event('IO_WIKIPAGE_READ', $data, '_io_readWikiPage_action', false);
65*cc7d0c94SBen Coburn}
66*cc7d0c94SBen Coburn
67*cc7d0c94SBen Coburn/**
68*cc7d0c94SBen Coburn * Callback adapter for io_readFile().
69*cc7d0c94SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
70*cc7d0c94SBen Coburn */
71*cc7d0c94SBen Coburnfunction _io_readWikiPage_action($data) {
72*cc7d0c94SBen Coburn    if (is_array($data) && is_array($data[0]) && count($data[0])===2) {
73*cc7d0c94SBen Coburn        return call_user_func_array('io_readFile', $data[0]);
74*cc7d0c94SBen Coburn    } else {
75*cc7d0c94SBen Coburn        return ''; //callback error
7653d6ccfeSandi    }
7753d6ccfeSandi}
7853d6ccfeSandi
7953d6ccfeSandi/**
8015fae107Sandi * Returns content of $file as cleaned string.
8115fae107Sandi *
8215fae107Sandi * Uses gzip if extension is .gz
8315fae107Sandi *
84ee4c4a1bSAndreas Gohr * If you want to use the returned value in unserialize
85ee4c4a1bSAndreas Gohr * be sure to set $clean to false!
86ee4c4a1bSAndreas Gohr *
8715fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
88f3f0262cSandi */
89e34c0709SAndreas Gohrfunction io_readFile($file,$clean=true){
90f3f0262cSandi  $ret = '';
91f3f0262cSandi  if(@file_exists($file)){
92f3f0262cSandi    if(substr($file,-3) == '.gz'){
93f3f0262cSandi      $ret = join('',gzfile($file));
94f3f0262cSandi    }else{
95f3f0262cSandi      $ret = join('',file($file));
96f3f0262cSandi    }
97f3f0262cSandi  }
98e34c0709SAndreas Gohr  if($clean){
99f3f0262cSandi    return cleanText($ret);
100e34c0709SAndreas Gohr  }else{
101e34c0709SAndreas Gohr    return $ret;
102e34c0709SAndreas Gohr  }
103f3f0262cSandi}
104f3f0262cSandi
105f3f0262cSandi/**
106*cc7d0c94SBen Coburn * Used to write out a DokuWiki page to file, and send IO_WIKIPAGE_WRITE events.
107*cc7d0c94SBen Coburn *
108*cc7d0c94SBen Coburn * This generates an action event and delegates to io_saveFile().
109*cc7d0c94SBen Coburn * Action plugins are allowed to modify the page content in transit.
110*cc7d0c94SBen Coburn * The file path should not be changed.
111*cc7d0c94SBen Coburn * (The append parameter is set to false.)
112*cc7d0c94SBen Coburn *
113*cc7d0c94SBen Coburn * Event data:
114*cc7d0c94SBen Coburn * $data[0]    The raw arguments for io_saveFile as an array.
115*cc7d0c94SBen Coburn * $data[1]    ns: The colon separated namespace path minus the trailing page name. (false if root ns)
116*cc7d0c94SBen Coburn * $data[2]    page_name: The wiki page name.
117*cc7d0c94SBen Coburn * $data[3]    rev: The page revision, false for current wiki pages.
118*cc7d0c94SBen Coburn *
119*cc7d0c94SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
120*cc7d0c94SBen Coburn */
121*cc7d0c94SBen Coburnfunction io_writeWikiPage($file, $content, $id, $rev=false) {
122*cc7d0c94SBen Coburn    if (empty($rev)) { $rev = false; }
123*cc7d0c94SBen Coburn    if ($rev===false) { io_createNamespace($id); } // create namespaces as needed
124*cc7d0c94SBen Coburn    $data = array(array($file, $content, false), getNS($id), noNS($id), $rev);
125*cc7d0c94SBen Coburn    return trigger_event('IO_WIKIPAGE_WRITE', $data, '_io_writeWikiPage_action', false);
126*cc7d0c94SBen Coburn}
127*cc7d0c94SBen Coburn
128*cc7d0c94SBen Coburn/**
129*cc7d0c94SBen Coburn * Callback adapter for io_saveFile().
130*cc7d0c94SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
131*cc7d0c94SBen Coburn */
132*cc7d0c94SBen Coburnfunction _io_writeWikiPage_action($data) {
133*cc7d0c94SBen Coburn    if (is_array($data) && is_array($data[0]) && count($data[0])===3) {
134*cc7d0c94SBen Coburn        return call_user_func_array('io_saveFile', $data[0]);
135*cc7d0c94SBen Coburn    } else {
136*cc7d0c94SBen Coburn        return false; //callback error
137*cc7d0c94SBen Coburn    }
138*cc7d0c94SBen Coburn}
139*cc7d0c94SBen Coburn
140*cc7d0c94SBen Coburn/**
14115fae107Sandi * Saves $content to $file.
142f3f0262cSandi *
1431380fc45SAndreas Gohr * If the third parameter is set to true the given content
1441380fc45SAndreas Gohr * will be appended.
1451380fc45SAndreas Gohr *
14615fae107Sandi * Uses gzip if extension is .gz
14715fae107Sandi *
14815fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
14915fae107Sandi * @return bool true on success
150f3f0262cSandi */
1511380fc45SAndreas Gohrfunction io_saveFile($file,$content,$append=false){
152ac9115b0STroels Liebe Bentsen  global $conf;
1531380fc45SAndreas Gohr  $mode = ($append) ? 'ab' : 'wb';
1541380fc45SAndreas Gohr
155ac9115b0STroels Liebe Bentsen  $fileexists = file_exists($file);
156f3f0262cSandi  io_makeFileDir($file);
15790eb8392Sandi  io_lock($file);
158f3f0262cSandi  if(substr($file,-3) == '.gz'){
1591380fc45SAndreas Gohr    $fh = @gzopen($file,$mode.'9');
160f3f0262cSandi    if(!$fh){
161f3f0262cSandi      msg("Writing $file failed",-1);
162f3f0262cSandi      return false;
163f3f0262cSandi    }
164f3f0262cSandi    gzwrite($fh, $content);
165f3f0262cSandi    gzclose($fh);
166f3f0262cSandi  }else{
1671380fc45SAndreas Gohr    $fh = @fopen($file,$mode);
168f3f0262cSandi    if(!$fh){
169f3f0262cSandi      msg("Writing $file failed",-1);
170f3f0262cSandi      return false;
171f3f0262cSandi    }
172f3f0262cSandi    fwrite($fh, $content);
173f3f0262cSandi    fclose($fh);
174f3f0262cSandi  }
175ac9115b0STroels Liebe Bentsen
1761ca31cfeSAndreas Gohr  if(!$fileexists and $conf['fperm']) chmod($file, $conf['fperm']);
17790eb8392Sandi  io_unlock($file);
178f3f0262cSandi  return true;
179f3f0262cSandi}
180f3f0262cSandi
181f3f0262cSandi/**
1821380fc45SAndreas Gohr * Delete exact linematch for $badline from $file.
1831380fc45SAndreas Gohr *
1841380fc45SAndreas Gohr * Be sure to include the trailing newline in $badline
185b158d625SSteven Danz *
186b158d625SSteven Danz * Uses gzip if extension is .gz
187b158d625SSteven Danz *
1888b06d178Schris * 2005-10-14 : added regex option -- Christopher Smith <chris@jalakai.co.uk>
1898b06d178Schris *
190b158d625SSteven Danz * @author Steven Danz <steven-danz@kc.rr.com>
191b158d625SSteven Danz * @return bool true on success
192b158d625SSteven Danz */
1938b06d178Schrisfunction io_deleteFromFile($file,$badline,$regex=false){
1941380fc45SAndreas Gohr  if (!@file_exists($file)) return true;
1951380fc45SAndreas Gohr
196b158d625SSteven Danz  io_lock($file);
1971380fc45SAndreas Gohr
1981380fc45SAndreas Gohr  // load into array
199b158d625SSteven Danz  if(substr($file,-3) == '.gz'){
2001380fc45SAndreas Gohr    $lines = gzfile($file);
201b158d625SSteven Danz  }else{
2021380fc45SAndreas Gohr    $lines = file($file);
203b158d625SSteven Danz  }
204b158d625SSteven Danz
2051380fc45SAndreas Gohr  // remove all matching lines
2068b06d178Schris  if ($regex) {
2078b06d178Schris    $lines = preg_grep($badline,$lines,PREG_GREP_INVERT);
2088b06d178Schris  } else {
2091380fc45SAndreas Gohr    $pos = array_search($badline,$lines); //return null or false if not found
2101380fc45SAndreas Gohr    while(is_int($pos)){
2111380fc45SAndreas Gohr      unset($lines[$pos]);
2121380fc45SAndreas Gohr      $pos = array_search($badline,$lines);
213b158d625SSteven Danz    }
2148b06d178Schris  }
215b158d625SSteven Danz
2161380fc45SAndreas Gohr  if(count($lines)){
2171380fc45SAndreas Gohr    $content = join('',$lines);
218b158d625SSteven Danz    if(substr($file,-3) == '.gz'){
219b158d625SSteven Danz      $fh = @gzopen($file,'wb9');
220b158d625SSteven Danz      if(!$fh){
221b158d625SSteven Danz        msg("Removing content from $file failed",-1);
222b158d625SSteven Danz        return false;
223b158d625SSteven Danz      }
224b158d625SSteven Danz      gzwrite($fh, $content);
225b158d625SSteven Danz      gzclose($fh);
226b158d625SSteven Danz    }else{
227b158d625SSteven Danz      $fh = @fopen($file,'wb');
228b158d625SSteven Danz      if(!$fh){
229b158d625SSteven Danz        msg("Removing content from $file failed",-1);
230b158d625SSteven Danz        return false;
231b158d625SSteven Danz      }
232b158d625SSteven Danz      fwrite($fh, $content);
233b158d625SSteven Danz      fclose($fh);
234b158d625SSteven Danz    }
235b158d625SSteven Danz  }else{
236b158d625SSteven Danz    @unlink($file);
237b158d625SSteven Danz  }
238b158d625SSteven Danz
239b158d625SSteven Danz  io_unlock($file);
240b158d625SSteven Danz  return true;
241b158d625SSteven Danz}
242b158d625SSteven Danz
243b158d625SSteven Danz/**
24490eb8392Sandi * Tries to lock a file
24590eb8392Sandi *
24690eb8392Sandi * Locking is only done for io_savefile and uses directories
24790eb8392Sandi * inside $conf['lockdir']
24890eb8392Sandi *
24990eb8392Sandi * It waits maximal 3 seconds for the lock, after this time
25090eb8392Sandi * the lock is assumed to be stale and the function goes on
25190eb8392Sandi *
25290eb8392Sandi * @author Andreas Gohr <andi@splitbrain.org>
25390eb8392Sandi */
25490eb8392Sandifunction io_lock($file){
25590eb8392Sandi  global $conf;
25690eb8392Sandi  // no locking if safemode hack
25790eb8392Sandi  if($conf['safemodehack']) return;
25890eb8392Sandi
25990eb8392Sandi  $lockDir = $conf['lockdir'].'/'.md5($file);
26090eb8392Sandi  @ignore_user_abort(1);
26190eb8392Sandi
26290eb8392Sandi  $timeStart = time();
26390eb8392Sandi  do {
26490eb8392Sandi    //waited longer than 3 seconds? -> stale lock
26590eb8392Sandi    if ((time() - $timeStart) > 3) break;
26644881d27STroels Liebe Bentsen    $locked = @mkdir($lockDir, $conf['dmode']);
26777b98903SAndreas Gohr    if($locked){
26877b98903SAndreas Gohr      if($conf['dperm']) chmod($lockDir, $conf['dperm']);
26977b98903SAndreas Gohr      break;
27077b98903SAndreas Gohr    }
27177b98903SAndreas Gohr    usleep(50);
27290eb8392Sandi  } while ($locked === false);
27390eb8392Sandi}
27490eb8392Sandi
27590eb8392Sandi/**
27690eb8392Sandi * Unlocks a file
27790eb8392Sandi *
27890eb8392Sandi * @author Andreas Gohr <andi@splitbrain.org>
27990eb8392Sandi */
28090eb8392Sandifunction io_unlock($file){
28190eb8392Sandi  global $conf;
28290eb8392Sandi  // no locking if safemode hack
28390eb8392Sandi  if($conf['safemodehack']) return;
28490eb8392Sandi
28590eb8392Sandi  $lockDir = $conf['lockdir'].'/'.md5($file);
28690eb8392Sandi  @rmdir($lockDir);
28790eb8392Sandi  @ignore_user_abort(0);
28890eb8392Sandi}
28990eb8392Sandi
29090eb8392Sandi/**
291*cc7d0c94SBen Coburn * Create missing namespace directories and send the IO_NAMESPACE_CREATED events
292*cc7d0c94SBen Coburn * in the order of directory creation. (Parent directories first.)
293*cc7d0c94SBen Coburn *
294*cc7d0c94SBen Coburn * Event data:
295*cc7d0c94SBen Coburn * $data[0]    ns: The colon separated namespace path minus the trailing page name.
296*cc7d0c94SBen Coburn * $data[1]    ns_type: 'pages' or 'media' namespace tree.
297*cc7d0c94SBen Coburn *
298*cc7d0c94SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
299*cc7d0c94SBen Coburn */
300*cc7d0c94SBen Coburnfunction io_createNamespace($id, $ns_type='pages') {
301*cc7d0c94SBen Coburn    // verify ns_type
302*cc7d0c94SBen Coburn    $types = array('pages'=>'wikiFN', 'media'=>'mediaFN');
303*cc7d0c94SBen Coburn    if (!isset($types[$ns_type])) {
304*cc7d0c94SBen Coburn        trigger_error('Bad $ns_type parameter for io_createNamespace().');
305*cc7d0c94SBen Coburn        return;
306*cc7d0c94SBen Coburn    }
307*cc7d0c94SBen Coburn    // make event list
308*cc7d0c94SBen Coburn    $missing = array();
309*cc7d0c94SBen Coburn    $ns_stack = explode(':', $id);
310*cc7d0c94SBen Coburn    $ns = $id;
311*cc7d0c94SBen Coburn    $tmp = dirname( $file = call_user_func($types[$ns_type], $ns) );
312*cc7d0c94SBen Coburn    while (!@is_dir($tmp) && !(@file_exists($tmp) && !is_dir($tmp))) {
313*cc7d0c94SBen Coburn        array_pop($ns_stack);
314*cc7d0c94SBen Coburn        $ns = implode(':', $ns_stack);
315*cc7d0c94SBen Coburn        if (strlen($ns)==0) { break; }
316*cc7d0c94SBen Coburn        $missing[] = $ns;
317*cc7d0c94SBen Coburn        $tmp = dirname(call_user_func($types[$ns_type], $ns));
318*cc7d0c94SBen Coburn    }
319*cc7d0c94SBen Coburn    // make directories
320*cc7d0c94SBen Coburn    io_makeFileDir($file);
321*cc7d0c94SBen Coburn    // send the events
322*cc7d0c94SBen Coburn    $missing = array_reverse($missing); // inside out
323*cc7d0c94SBen Coburn    foreach ($missing as $ns) {
324*cc7d0c94SBen Coburn        $data = array($ns, $ns_type);
325*cc7d0c94SBen Coburn        trigger_event('IO_NAMESPACE_CREATED', $data);
326*cc7d0c94SBen Coburn    }
327*cc7d0c94SBen Coburn}
328*cc7d0c94SBen Coburn
329*cc7d0c94SBen Coburn/**
330f3f0262cSandi * Create the directory needed for the given file
33115fae107Sandi *
33215fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
333f3f0262cSandi */
334f3f0262cSandifunction io_makeFileDir($file){
335f3f0262cSandi  global $conf;
336f3f0262cSandi
337f3f0262cSandi  $dir = dirname($file);
3380d8850c4SAndreas Gohr  if(!@is_dir($dir)){
339f3f0262cSandi    io_mkdir_p($dir) || msg("Creating directory $dir failed",-1);
340f3f0262cSandi  }
341f3f0262cSandi}
342f3f0262cSandi
343f3f0262cSandi/**
344f3f0262cSandi * Creates a directory hierachy.
345f3f0262cSandi *
34615fae107Sandi * @link    http://www.php.net/manual/en/function.mkdir.php
347f3f0262cSandi * @author  <saint@corenova.com>
3483dc3a5f1Sandi * @author  Andreas Gohr <andi@splitbrain.org>
349f3f0262cSandi */
350f3f0262cSandifunction io_mkdir_p($target){
3513dc3a5f1Sandi  global $conf;
3520d8850c4SAndreas Gohr  if (@is_dir($target)||empty($target)) return 1; // best case check first
353f3f0262cSandi  if (@file_exists($target) && !is_dir($target)) return 0;
3543dc3a5f1Sandi  //recursion
3553dc3a5f1Sandi  if (io_mkdir_p(substr($target,0,strrpos($target,'/')))){
3563dc3a5f1Sandi    if($conf['safemodehack']){
357034138e2SRainer Weinhold      $dir = preg_replace('/^'.preg_quote(realpath($conf['ftp']['root']),'/').'/','', $target);
358034138e2SRainer Weinhold      return io_mkdir_ftp($dir);
3593dc3a5f1Sandi    }else{
36044881d27STroels Liebe Bentsen      $ret = @mkdir($target,$conf['dmode']); // crawl back up & create dir tree
3611ca31cfeSAndreas Gohr      if($ret && $conf['dperm']) chmod($target, $conf['dperm']);
36244881d27STroels Liebe Bentsen      return $ret;
3633dc3a5f1Sandi    }
3643dc3a5f1Sandi  }
365f3f0262cSandi  return 0;
366f3f0262cSandi}
367f3f0262cSandi
368f3f0262cSandi/**
3693dc3a5f1Sandi * Creates a directory using FTP
3703dc3a5f1Sandi *
3713dc3a5f1Sandi * This is used when the safemode workaround is enabled
3723dc3a5f1Sandi *
3733dc3a5f1Sandi * @author <andi@splitbrain.org>
3743dc3a5f1Sandi */
3753dc3a5f1Sandifunction io_mkdir_ftp($dir){
3763dc3a5f1Sandi  global $conf;
3773dc3a5f1Sandi
3783dc3a5f1Sandi  if(!function_exists('ftp_connect')){
3793dc3a5f1Sandi    msg("FTP support not found - safemode workaround not usable",-1);
3803dc3a5f1Sandi    return false;
3813dc3a5f1Sandi  }
3823dc3a5f1Sandi
3833dc3a5f1Sandi  $conn = @ftp_connect($conf['ftp']['host'],$conf['ftp']['port'],10);
3843dc3a5f1Sandi  if(!$conn){
3853dc3a5f1Sandi    msg("FTP connection failed",-1);
3863dc3a5f1Sandi    return false;
3873dc3a5f1Sandi  }
3883dc3a5f1Sandi
3893dc3a5f1Sandi  if(!@ftp_login($conn, $conf['ftp']['user'], $conf['ftp']['pass'])){
3903dc3a5f1Sandi    msg("FTP login failed",-1);
3913dc3a5f1Sandi    return false;
3923dc3a5f1Sandi  }
3933dc3a5f1Sandi
3943dc3a5f1Sandi  //create directory
395034138e2SRainer Weinhold  $ok = @ftp_mkdir($conn, $dir);
3961ca31cfeSAndreas Gohr  //set permissions
3971ca31cfeSAndreas Gohr  @ftp_site($conn,sprintf("CHMOD %04o %s",$conf['dmode'],$dir));
3983dc3a5f1Sandi
399034138e2SRainer Weinhold  @ftp_close($conn);
4003dc3a5f1Sandi  return $ok;
4013dc3a5f1Sandi}
4023dc3a5f1Sandi
4033dc3a5f1Sandi/**
40473ccfcb9Schris * downloads a file from the net and saves it
40573ccfcb9Schris *
40673ccfcb9Schris * if $useAttachment is false,
40773ccfcb9Schris * - $file is the full filename to save the file, incl. path
40873ccfcb9Schris * - if successful will return true, false otherwise
40973ccfcb9Schris
41073ccfcb9Schris * if $useAttachment is true,
41173ccfcb9Schris * - $file is the directory where the file should be saved
41273ccfcb9Schris * - if successful will return the name used for the saved file, false otherwise
413b625487dSandi *
414b625487dSandi * @author Andreas Gohr <andi@splitbrain.org>
41573ccfcb9Schris * @author Chris Smith <chris@jalakai.co.uk>
416b625487dSandi */
417847b8298SAndreas Gohrfunction io_download($url,$file,$useAttachment=false,$defaultName='',$maxSize=2097152){
418ac9115b0STroels Liebe Bentsen  global $conf;
4199b307a83SAndreas Gohr  $http = new DokuHTTPClient();
420847b8298SAndreas Gohr  $http->max_bodysize = $maxSize;
4219b307a83SAndreas Gohr  $http->timeout = 25; //max. 25 sec
4229b307a83SAndreas Gohr
4239b307a83SAndreas Gohr  $data = $http->get($url);
4249b307a83SAndreas Gohr  if(!$data) return false;
4259b307a83SAndreas Gohr
42673ccfcb9Schris  if ($useAttachment) {
42773ccfcb9Schris    $name = '';
42873ccfcb9Schris      if (isset($http->resp_headers['content-disposition'])) {
42973ccfcb9Schris      $content_disposition = $http->resp_headers['content-disposition'];
430ce070a9fSchris      $match=array();
43173ccfcb9Schris      if (is_string($content_disposition) &&
432ce070a9fSchris          preg_match('/attachment;\s*filename\s*=\s*"([^"]*)"/i', $content_disposition, $match)) {
43373ccfcb9Schris
43473ccfcb9Schris          $name = basename($match[1]);
43573ccfcb9Schris      }
43673ccfcb9Schris
43773ccfcb9Schris    }
43873ccfcb9Schris
43973ccfcb9Schris    if (!$name) {
44073ccfcb9Schris        if (!$defaultName) return false;
44173ccfcb9Schris        $name = $defaultName;
44273ccfcb9Schris    }
44373ccfcb9Schris
44473ccfcb9Schris    $file = $file.$name;
44573ccfcb9Schris  }
44673ccfcb9Schris
447ac9115b0STroels Liebe Bentsen  $fileexists = file_exists($file);
4489b307a83SAndreas Gohr  $fp = @fopen($file,"w");
449b625487dSandi  if(!$fp) return false;
4509b307a83SAndreas Gohr  fwrite($fp,$data);
451b625487dSandi  fclose($fp);
4521ca31cfeSAndreas Gohr  if(!$fileexists and $conf['fperm']) chmod($file, $conf['fperm']);
45373ccfcb9Schris  if ($useAttachment) return $name;
454b625487dSandi  return true;
455b625487dSandi}
456b625487dSandi
457b625487dSandi/**
458ac9115b0STroels Liebe Bentsen * Windows compatible rename
459bf5e5a5bSAndreas Gohr *
460bf5e5a5bSAndreas Gohr * rename() can not overwrite existing files on Windows
461bf5e5a5bSAndreas Gohr * this function will use copy/unlink instead
462bf5e5a5bSAndreas Gohr */
463bf5e5a5bSAndreas Gohrfunction io_rename($from,$to){
464ac9115b0STroels Liebe Bentsen  global $conf;
465bf5e5a5bSAndreas Gohr  if(!@rename($from,$to)){
466bf5e5a5bSAndreas Gohr    if(@copy($from,$to)){
4671ca31cfeSAndreas Gohr      if($conf['fperm']) chmod($file, $conf['fperm']);
468bf5e5a5bSAndreas Gohr      @unlink($from);
469bf5e5a5bSAndreas Gohr      return true;
470bf5e5a5bSAndreas Gohr    }
471bf5e5a5bSAndreas Gohr    return false;
472bf5e5a5bSAndreas Gohr  }
473bf5e5a5bSAndreas Gohr  return true;
474bf5e5a5bSAndreas Gohr}
475bf5e5a5bSAndreas Gohr
476bf5e5a5bSAndreas Gohr
477bf5e5a5bSAndreas Gohr/**
478f3f0262cSandi * Runs an external command and returns it's output as string
47915fae107Sandi *
48015fae107Sandi * @author Harry Brueckner <harry_b@eml.cc>
48115fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
4823dc3a5f1Sandi * @deprecated
483f3f0262cSandi */
484f3f0262cSandifunction io_runcmd($cmd){
485f3f0262cSandi  $fh = popen($cmd, "r");
486f3f0262cSandi  if(!$fh) return false;
487f3f0262cSandi  $ret = '';
488f3f0262cSandi  while (!feof($fh)) {
489f3f0262cSandi    $ret .= fread($fh, 8192);
490f3f0262cSandi  }
491f3f0262cSandi  pclose($fh);
492f3f0262cSandi  return $ret;
493f3f0262cSandi}
494f3f0262cSandi
4957421c3ccSAndreas Gohr/**
4967421c3ccSAndreas Gohr * Search a file for matching lines
4977421c3ccSAndreas Gohr *
4987421c3ccSAndreas Gohr * This is probably not faster than file()+preg_grep() but less
4997421c3ccSAndreas Gohr * memory intensive because not the whole file needs to be loaded
5007421c3ccSAndreas Gohr * at once.
5017421c3ccSAndreas Gohr *
5027421c3ccSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
5037421c3ccSAndreas Gohr * @param  string $file    The file to search
5047421c3ccSAndreas Gohr * @param  string $pattern PCRE pattern
5057421c3ccSAndreas Gohr * @param  int    $max     How many lines to return (0 for all)
5067421c3ccSAndreas Gohr * @param  bool   $baxkref When true returns array with backreferences instead of lines
5077421c3ccSAndreas Gohr * @return matching lines or backref, false on error
5087421c3ccSAndreas Gohr */
5097421c3ccSAndreas Gohrfunction io_grep($file,$pattern,$max=0,$backref=false){
5107421c3ccSAndreas Gohr  $fh = @fopen($file,'r');
5117421c3ccSAndreas Gohr  if(!$fh) return false;
5127421c3ccSAndreas Gohr  $matches = array();
5137421c3ccSAndreas Gohr
5147421c3ccSAndreas Gohr  $cnt  = 0;
5157421c3ccSAndreas Gohr  $line = '';
5167421c3ccSAndreas Gohr  while (!feof($fh)) {
5177421c3ccSAndreas Gohr    $line .= fgets($fh, 4096);  // read full line
5187421c3ccSAndreas Gohr    if(substr($line,-1) != "\n") continue;
5197421c3ccSAndreas Gohr
5207421c3ccSAndreas Gohr    // check if line matches
5217421c3ccSAndreas Gohr    if(preg_match($pattern,$line,$match)){
5227421c3ccSAndreas Gohr      if($backref){
5237421c3ccSAndreas Gohr        $matches[] = $match;
5247421c3ccSAndreas Gohr      }else{
5257421c3ccSAndreas Gohr        $matches[] = $line;
5267421c3ccSAndreas Gohr      }
5277421c3ccSAndreas Gohr      $cnt++;
5287421c3ccSAndreas Gohr    }
5297421c3ccSAndreas Gohr    if($max && $max == $cnt) break;
5307421c3ccSAndreas Gohr    $line = '';
5317421c3ccSAndreas Gohr  }
5327421c3ccSAndreas Gohr  fclose($fh);
5337421c3ccSAndreas Gohr  return $matches;
5347421c3ccSAndreas Gohr}
5357421c3ccSAndreas Gohr
536340756e4Sandi//Setup VIM: ex: et ts=2 enc=utf-8 :
537