xref: /dokuwiki/inc/io.php (revision b158d625b53833ef391800a991ad93d965d9425e)
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');
11f3f0262cSandi
12f3f0262cSandi/**
1353d6ccfeSandi * Removes empty directories
1453d6ccfeSandi *
1553d6ccfeSandi * @todo use safemode hack
1653d6ccfeSandi * @author  Andreas Gohr <andi@splitbrain.org>
1753d6ccfeSandi */
1853d6ccfeSandifunction io_sweepNS($id){
1953d6ccfeSandi  global $conf;
2053d6ccfeSandi
2153d6ccfeSandi  //scan all namespaces
2253d6ccfeSandi  while(($id = getNS($id)) !== false){
2353d6ccfeSandi		$dir = $conf['datadir'].'/'.str_replace(':','/',$id);
2453d6ccfeSandi    $dir = utf8_encodeFN($dir);
2553d6ccfeSandi
2653d6ccfeSandi    //try to delete dir else return
2753d6ccfeSandi    if(!@rmdir($dir)) return;
2853d6ccfeSandi  }
2953d6ccfeSandi}
3053d6ccfeSandi
3153d6ccfeSandi/**
3215fae107Sandi * Returns content of $file as cleaned string.
3315fae107Sandi *
3415fae107Sandi * Uses gzip if extension is .gz
3515fae107Sandi *
3615fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
37f3f0262cSandi */
38f3f0262cSandifunction io_readFile($file){
39f3f0262cSandi  $ret = '';
40f3f0262cSandi  if(@file_exists($file)){
41f3f0262cSandi    if(substr($file,-3) == '.gz'){
42f3f0262cSandi      $ret = join('',gzfile($file));
43f3f0262cSandi    }else{
44f3f0262cSandi      $ret = join('',file($file));
45f3f0262cSandi    }
46f3f0262cSandi  }
47f3f0262cSandi  return cleanText($ret);
48f3f0262cSandi}
49f3f0262cSandi
50f3f0262cSandi/**
5115fae107Sandi * Saves $content to $file.
52f3f0262cSandi *
5315fae107Sandi * Uses gzip if extension is .gz
5415fae107Sandi *
5515fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
5615fae107Sandi * @return bool true on success
57f3f0262cSandi */
58f3f0262cSandifunction io_saveFile($file,$content){
59f3f0262cSandi  io_makeFileDir($file);
6090eb8392Sandi  io_lock($file);
61f3f0262cSandi  if(substr($file,-3) == '.gz'){
62f3f0262cSandi    $fh = @gzopen($file,'wb9');
63f3f0262cSandi    if(!$fh){
64f3f0262cSandi      msg("Writing $file failed",-1);
65f3f0262cSandi      return false;
66f3f0262cSandi    }
67f3f0262cSandi    gzwrite($fh, $content);
68f3f0262cSandi    gzclose($fh);
69f3f0262cSandi  }else{
70f3f0262cSandi    $fh = @fopen($file,'wb');
71f3f0262cSandi    if(!$fh){
72f3f0262cSandi      msg("Writing $file failed",-1);
73f3f0262cSandi      return false;
74f3f0262cSandi    }
75f3f0262cSandi    fwrite($fh, $content);
76f3f0262cSandi    fclose($fh);
77f3f0262cSandi  }
7890eb8392Sandi  io_unlock($file);
79f3f0262cSandi  return true;
80f3f0262cSandi}
81f3f0262cSandi
82f3f0262cSandi/**
83*b158d625SSteven Danz * Appends $content to $file.
84*b158d625SSteven Danz *
85*b158d625SSteven Danz * Uses gzip if extension is .gz
86*b158d625SSteven Danz *
87*b158d625SSteven Danz * @author Steven Danz <steven-danz@kc.rr.com>
88*b158d625SSteven Danz * @return bool true on success
89*b158d625SSteven Danz */
90*b158d625SSteven Danzfunction io_appendFile($file,$content){
91*b158d625SSteven Danz  io_makeFileDir($file);
92*b158d625SSteven Danz  io_lock($file);
93*b158d625SSteven Danz  if(substr($file,-3) == '.gz'){
94*b158d625SSteven Danz    $fh = @gzopen($file,'ab9');
95*b158d625SSteven Danz    if(!$fh){
96*b158d625SSteven Danz      msg("Appending to $file failed",-1);
97*b158d625SSteven Danz      return false;
98*b158d625SSteven Danz    }
99*b158d625SSteven Danz    gzwrite($fh, $content);
100*b158d625SSteven Danz    gzclose($fh);
101*b158d625SSteven Danz  }else{
102*b158d625SSteven Danz    $fh = @fopen($file,'ab');
103*b158d625SSteven Danz    if(!$fh){
104*b158d625SSteven Danz      msg("Appending to $file failed",-1);
105*b158d625SSteven Danz      return false;
106*b158d625SSteven Danz    }
107*b158d625SSteven Danz    fwrite($fh, $content);
108*b158d625SSteven Danz    fclose($fh);
109*b158d625SSteven Danz  }
110*b158d625SSteven Danz  io_unlock($file);
111*b158d625SSteven Danz  return true;
112*b158d625SSteven Danz}
113*b158d625SSteven Danz
114*b158d625SSteven Danz/**
115*b158d625SSteven Danz * Delete exact match for $content from $file.
116*b158d625SSteven Danz *
117*b158d625SSteven Danz * Uses gzip if extension is .gz
118*b158d625SSteven Danz *
119*b158d625SSteven Danz * @author Steven Danz <steven-danz@kc.rr.com>
120*b158d625SSteven Danz * @return bool true on success
121*b158d625SSteven Danz */
122*b158d625SSteven Danzfunction io_deleteFromFile($file,$remove){
123*b158d625SSteven Danz  if (@file_exists($file)) {
124*b158d625SSteven Danz    io_lock($file);
125*b158d625SSteven Danz    $content = '';
126*b158d625SSteven Danz    if(substr($file,-3) == '.gz'){
127*b158d625SSteven Danz      $mlist = gzfile($file);
128*b158d625SSteven Danz    }else{
129*b158d625SSteven Danz      $mlist = file($file);
130*b158d625SSteven Danz    }
131*b158d625SSteven Danz    foreach ($mlist as $entry) {
132*b158d625SSteven Danz      if ($entry != $remove) {
133*b158d625SSteven Danz        $content = $content . $entry;
134*b158d625SSteven Danz      }
135*b158d625SSteven Danz    }
136*b158d625SSteven Danz
137*b158d625SSteven Danz    if (!empty($content)) {
138*b158d625SSteven Danz      if(substr($file,-3) == '.gz'){
139*b158d625SSteven Danz        $fh = @gzopen($file,'wb9');
140*b158d625SSteven Danz        if(!$fh){
141*b158d625SSteven Danz          msg("Removing content from $file failed",-1);
142*b158d625SSteven Danz          return false;
143*b158d625SSteven Danz        }
144*b158d625SSteven Danz        gzwrite($fh, $content);
145*b158d625SSteven Danz        gzclose($fh);
146*b158d625SSteven Danz      }else{
147*b158d625SSteven Danz        $fh = @fopen($file,'wb');
148*b158d625SSteven Danz        if(!$fh){
149*b158d625SSteven Danz          msg("Removing content from $file failed",-1);
150*b158d625SSteven Danz          return false;
151*b158d625SSteven Danz        }
152*b158d625SSteven Danz        fwrite($fh, $content);
153*b158d625SSteven Danz        fclose($fh);
154*b158d625SSteven Danz      }
155*b158d625SSteven Danz    } else {
156*b158d625SSteven Danz      @unlink($file);
157*b158d625SSteven Danz    }
158*b158d625SSteven Danz
159*b158d625SSteven Danz    io_unlock($file);
160*b158d625SSteven Danz  }
161*b158d625SSteven Danz  return true;
162*b158d625SSteven Danz}
163*b158d625SSteven Danz
164*b158d625SSteven Danz/**
16590eb8392Sandi * Tries to lock a file
16690eb8392Sandi *
16790eb8392Sandi * Locking is only done for io_savefile and uses directories
16890eb8392Sandi * inside $conf['lockdir']
16990eb8392Sandi *
17090eb8392Sandi * It waits maximal 3 seconds for the lock, after this time
17190eb8392Sandi * the lock is assumed to be stale and the function goes on
17290eb8392Sandi *
17390eb8392Sandi * @author Andreas Gohr <andi@splitbrain.org>
17490eb8392Sandi */
17590eb8392Sandifunction io_lock($file){
17690eb8392Sandi  global $conf;
17790eb8392Sandi  // no locking if safemode hack
17890eb8392Sandi  if($conf['safemodehack']) return;
17990eb8392Sandi
18090eb8392Sandi  $lockDir = $conf['lockdir'].'/'.md5($file);
18190eb8392Sandi  @ignore_user_abort(1);
18290eb8392Sandi
18390eb8392Sandi
18490eb8392Sandi  $timeStart = time();
18590eb8392Sandi  do {
18690eb8392Sandi    //waited longer than 3 seconds? -> stale lock
18790eb8392Sandi    if ((time() - $timeStart) > 3) break;
18890eb8392Sandi    $locked = @mkdir($lockDir);
18990eb8392Sandi  } while ($locked === false);
19090eb8392Sandi}
19190eb8392Sandi
19290eb8392Sandi/**
19390eb8392Sandi * Unlocks a file
19490eb8392Sandi *
19590eb8392Sandi * @author Andreas Gohr <andi@splitbrain.org>
19690eb8392Sandi */
19790eb8392Sandifunction io_unlock($file){
19890eb8392Sandi  global $conf;
19990eb8392Sandi  // no locking if safemode hack
20090eb8392Sandi  if($conf['safemodehack']) return;
20190eb8392Sandi
20290eb8392Sandi  $lockDir = $conf['lockdir'].'/'.md5($file);
20390eb8392Sandi  @rmdir($lockDir);
20490eb8392Sandi  @ignore_user_abort(0);
20590eb8392Sandi}
20690eb8392Sandi
20790eb8392Sandi/**
208f3f0262cSandi * Create the directory needed for the given file
20915fae107Sandi *
21015fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
211f3f0262cSandi */
212f3f0262cSandifunction io_makeFileDir($file){
213f3f0262cSandi  global $conf;
214f3f0262cSandi
215f3f0262cSandi  $dir = dirname($file);
216f3f0262cSandi  umask($conf['dmask']);
217f3f0262cSandi  if(!is_dir($dir)){
218f3f0262cSandi    io_mkdir_p($dir) || msg("Creating directory $dir failed",-1);
219f3f0262cSandi  }
220f3f0262cSandi  umask($conf['umask']);
221f3f0262cSandi}
222f3f0262cSandi
223f3f0262cSandi/**
224f3f0262cSandi * Creates a directory hierachy.
225f3f0262cSandi *
22615fae107Sandi * @link    http://www.php.net/manual/en/function.mkdir.php
227f3f0262cSandi * @author  <saint@corenova.com>
2283dc3a5f1Sandi * @author  Andreas Gohr <andi@splitbrain.org>
229f3f0262cSandi */
230f3f0262cSandifunction io_mkdir_p($target){
2313dc3a5f1Sandi  global $conf;
232f3f0262cSandi  if (is_dir($target)||empty($target)) return 1; // best case check first
233f3f0262cSandi  if (@file_exists($target) && !is_dir($target)) return 0;
2343dc3a5f1Sandi  //recursion
2353dc3a5f1Sandi  if (io_mkdir_p(substr($target,0,strrpos($target,'/')))){
2363dc3a5f1Sandi    if($conf['safemodehack']){
237034138e2SRainer Weinhold      $dir = preg_replace('/^'.preg_quote(realpath($conf['ftp']['root']),'/').'/','', $target);
238034138e2SRainer Weinhold      return io_mkdir_ftp($dir);
2393dc3a5f1Sandi    }else{
240f3f0262cSandi      return @mkdir($target,0777); // crawl back up & create dir tree
2413dc3a5f1Sandi    }
2423dc3a5f1Sandi  }
243f3f0262cSandi  return 0;
244f3f0262cSandi}
245f3f0262cSandi
246f3f0262cSandi/**
2473dc3a5f1Sandi * Creates a directory using FTP
2483dc3a5f1Sandi *
2493dc3a5f1Sandi * This is used when the safemode workaround is enabled
2503dc3a5f1Sandi *
2513dc3a5f1Sandi * @author <andi@splitbrain.org>
2523dc3a5f1Sandi */
2533dc3a5f1Sandifunction io_mkdir_ftp($dir){
2543dc3a5f1Sandi  global $conf;
2553dc3a5f1Sandi
2563dc3a5f1Sandi  if(!function_exists('ftp_connect')){
2573dc3a5f1Sandi    msg("FTP support not found - safemode workaround not usable",-1);
2583dc3a5f1Sandi    return false;
2593dc3a5f1Sandi  }
2603dc3a5f1Sandi
2613dc3a5f1Sandi  $conn = @ftp_connect($conf['ftp']['host'],$conf['ftp']['port'],10);
2623dc3a5f1Sandi  if(!$conn){
2633dc3a5f1Sandi    msg("FTP connection failed",-1);
2643dc3a5f1Sandi    return false;
2653dc3a5f1Sandi  }
2663dc3a5f1Sandi
2673dc3a5f1Sandi  if(!@ftp_login($conn, $conf['ftp']['user'], $conf['ftp']['pass'])){
2683dc3a5f1Sandi    msg("FTP login failed",-1);
2693dc3a5f1Sandi    return false;
2703dc3a5f1Sandi  }
2713dc3a5f1Sandi
2723dc3a5f1Sandi  //create directory
273034138e2SRainer Weinhold  $ok = @ftp_mkdir($conn, $dir);
2743dc3a5f1Sandi  //set permissions (using the directory umask)
275034138e2SRainer Weinhold  @ftp_site($conn,sprintf("CHMOD %04o %s",(0777 - $conf['dmask']),$dir));
2763dc3a5f1Sandi
277034138e2SRainer Weinhold  @ftp_close($conn);
2783dc3a5f1Sandi  return $ok;
2793dc3a5f1Sandi}
2803dc3a5f1Sandi
2813dc3a5f1Sandi/**
282b625487dSandi * downloads a file from the net and saves it to the given location
283b625487dSandi *
284b625487dSandi * @author Andreas Gohr <andi@splitbrain.org>
285b625487dSandi * @todo   Add size limit
286b625487dSandi */
287b625487dSandifunction io_download($url,$file){
288b625487dSandi  $fp = @fopen($url,"rb");
289b625487dSandi  if(!$fp) return false;
290b625487dSandi
2910e33fac4Sandi  $kb  = 0;
2920e33fac4Sandi  $now = time();
2930e33fac4Sandi
294b625487dSandi  while(!feof($fp)){
2950e33fac4Sandi    if($kb++ > 2048 || (time() - $now) > 45){
2960e33fac4Sandi      //abort on 2 MB and timeout on 45 sec
2970e33fac4Sandi      return false;
2980e33fac4Sandi    }
299b625487dSandi    $cont.= fread($fp,1024);
300b625487dSandi  }
301b625487dSandi  fclose($fp);
302b625487dSandi
303b625487dSandi  $fp2 = @fopen($file,"w");
304b625487dSandi  if(!$fp2) return false;
305b625487dSandi  fwrite($fp2,$cont);
306b625487dSandi  fclose($fp2);
307b625487dSandi  return true;
308b625487dSandi}
309b625487dSandi
310b625487dSandi/**
311f3f0262cSandi * Runs an external command and returns it's output as string
31215fae107Sandi *
31315fae107Sandi * @author Harry Brueckner <harry_b@eml.cc>
31415fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
3153dc3a5f1Sandi * @deprecated
316f3f0262cSandi */
317f3f0262cSandifunction io_runcmd($cmd){
318f3f0262cSandi  $fh = popen($cmd, "r");
319f3f0262cSandi  if(!$fh) return false;
320f3f0262cSandi  $ret = '';
321f3f0262cSandi  while (!feof($fh)) {
322f3f0262cSandi    $ret .= fread($fh, 8192);
323f3f0262cSandi  }
324f3f0262cSandi  pclose($fh);
325f3f0262cSandi  return $ret;
326f3f0262cSandi}
327f3f0262cSandi
328340756e4Sandi
329340756e4Sandi//Setup VIM: ex: et ts=2 enc=utf-8 :
330