xref: /dokuwiki/inc/io.php (revision 1380fc452d56dd6f48ddbfa3a6b0e69edd043b04)
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 *
53*1380fc45SAndreas Gohr * If the third parameter is set to true the given content
54*1380fc45SAndreas Gohr * will be appended.
55*1380fc45SAndreas Gohr *
5615fae107Sandi * Uses gzip if extension is .gz
5715fae107Sandi *
5815fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
5915fae107Sandi * @return bool true on success
60f3f0262cSandi */
61*1380fc45SAndreas Gohrfunction io_saveFile($file,$content,$append=false){
62*1380fc45SAndreas Gohr  $mode = ($append) ? 'ab' : 'wb';
63*1380fc45SAndreas Gohr
64f3f0262cSandi  io_makeFileDir($file);
6590eb8392Sandi  io_lock($file);
66f3f0262cSandi  if(substr($file,-3) == '.gz'){
67*1380fc45SAndreas Gohr    $fh = @gzopen($file,$mode.'9');
68f3f0262cSandi    if(!$fh){
69f3f0262cSandi      msg("Writing $file failed",-1);
70f3f0262cSandi      return false;
71f3f0262cSandi    }
72f3f0262cSandi    gzwrite($fh, $content);
73f3f0262cSandi    gzclose($fh);
74f3f0262cSandi  }else{
75*1380fc45SAndreas Gohr    $fh = @fopen($file,$mode);
76f3f0262cSandi    if(!$fh){
77f3f0262cSandi      msg("Writing $file failed",-1);
78f3f0262cSandi      return false;
79f3f0262cSandi    }
80f3f0262cSandi    fwrite($fh, $content);
81f3f0262cSandi    fclose($fh);
82f3f0262cSandi  }
8390eb8392Sandi  io_unlock($file);
84f3f0262cSandi  return true;
85f3f0262cSandi}
86f3f0262cSandi
87f3f0262cSandi/**
88*1380fc45SAndreas Gohr * Delete exact linematch for $badline from $file.
89*1380fc45SAndreas Gohr *
90*1380fc45SAndreas Gohr * Be sure to include the trailing newline in $badline
91b158d625SSteven Danz *
92b158d625SSteven Danz * Uses gzip if extension is .gz
93b158d625SSteven Danz *
94b158d625SSteven Danz * @author Steven Danz <steven-danz@kc.rr.com>
95b158d625SSteven Danz * @return bool true on success
96b158d625SSteven Danz */
97*1380fc45SAndreas Gohrfunction io_deleteFromFile($file,$badline){
98*1380fc45SAndreas Gohr  if (!@file_exists($file)) return true;
99*1380fc45SAndreas Gohr
100b158d625SSteven Danz  io_lock($file);
101*1380fc45SAndreas Gohr
102*1380fc45SAndreas Gohr  // load into array
103b158d625SSteven Danz  if(substr($file,-3) == '.gz'){
104*1380fc45SAndreas Gohr    $lines = gzfile($file);
105b158d625SSteven Danz  }else{
106*1380fc45SAndreas Gohr    $lines = file($file);
107b158d625SSteven Danz  }
108b158d625SSteven Danz
109*1380fc45SAndreas Gohr  // remove all matching lines
110*1380fc45SAndreas Gohr  $pos = array_search($badline,$lines); //return null or false if not found
111*1380fc45SAndreas Gohr  while(is_int($pos)){
112*1380fc45SAndreas Gohr    unset($lines[$pos]);
113*1380fc45SAndreas Gohr    $pos = array_search($badline,$lines);
114b158d625SSteven Danz  }
115b158d625SSteven Danz
116*1380fc45SAndreas Gohr  if(count($lines)){
117*1380fc45SAndreas Gohr    $content = join('',$lines);
118b158d625SSteven Danz    if(substr($file,-3) == '.gz'){
119b158d625SSteven Danz      $fh = @gzopen($file,'wb9');
120b158d625SSteven Danz      if(!$fh){
121b158d625SSteven Danz        msg("Removing content from $file failed",-1);
122b158d625SSteven Danz        return false;
123b158d625SSteven Danz      }
124b158d625SSteven Danz      gzwrite($fh, $content);
125b158d625SSteven Danz      gzclose($fh);
126b158d625SSteven Danz    }else{
127b158d625SSteven Danz      $fh = @fopen($file,'wb');
128b158d625SSteven Danz      if(!$fh){
129b158d625SSteven Danz        msg("Removing content from $file failed",-1);
130b158d625SSteven Danz        return false;
131b158d625SSteven Danz      }
132b158d625SSteven Danz      fwrite($fh, $content);
133b158d625SSteven Danz      fclose($fh);
134b158d625SSteven Danz    }
135b158d625SSteven Danz  }else{
136b158d625SSteven Danz    @unlink($file);
137b158d625SSteven Danz  }
138b158d625SSteven Danz
139b158d625SSteven Danz  io_unlock($file);
140b158d625SSteven Danz  return true;
141b158d625SSteven Danz}
142b158d625SSteven Danz
143b158d625SSteven Danz/**
14490eb8392Sandi * Tries to lock a file
14590eb8392Sandi *
14690eb8392Sandi * Locking is only done for io_savefile and uses directories
14790eb8392Sandi * inside $conf['lockdir']
14890eb8392Sandi *
14990eb8392Sandi * It waits maximal 3 seconds for the lock, after this time
15090eb8392Sandi * the lock is assumed to be stale and the function goes on
15190eb8392Sandi *
15290eb8392Sandi * @author Andreas Gohr <andi@splitbrain.org>
15390eb8392Sandi */
15490eb8392Sandifunction io_lock($file){
15590eb8392Sandi  global $conf;
15690eb8392Sandi  // no locking if safemode hack
15790eb8392Sandi  if($conf['safemodehack']) return;
15890eb8392Sandi
15990eb8392Sandi  $lockDir = $conf['lockdir'].'/'.md5($file);
16090eb8392Sandi  @ignore_user_abort(1);
16190eb8392Sandi
16290eb8392Sandi
16390eb8392Sandi  $timeStart = time();
16490eb8392Sandi  do {
16590eb8392Sandi    //waited longer than 3 seconds? -> stale lock
16690eb8392Sandi    if ((time() - $timeStart) > 3) break;
16790eb8392Sandi    $locked = @mkdir($lockDir);
16890eb8392Sandi  } while ($locked === false);
16990eb8392Sandi}
17090eb8392Sandi
17190eb8392Sandi/**
17290eb8392Sandi * Unlocks a file
17390eb8392Sandi *
17490eb8392Sandi * @author Andreas Gohr <andi@splitbrain.org>
17590eb8392Sandi */
17690eb8392Sandifunction io_unlock($file){
17790eb8392Sandi  global $conf;
17890eb8392Sandi  // no locking if safemode hack
17990eb8392Sandi  if($conf['safemodehack']) return;
18090eb8392Sandi
18190eb8392Sandi  $lockDir = $conf['lockdir'].'/'.md5($file);
18290eb8392Sandi  @rmdir($lockDir);
18390eb8392Sandi  @ignore_user_abort(0);
18490eb8392Sandi}
18590eb8392Sandi
18690eb8392Sandi/**
187f3f0262cSandi * Create the directory needed for the given file
18815fae107Sandi *
18915fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
190f3f0262cSandi */
191f3f0262cSandifunction io_makeFileDir($file){
192f3f0262cSandi  global $conf;
193f3f0262cSandi
194f3f0262cSandi  $dir = dirname($file);
195f3f0262cSandi  umask($conf['dmask']);
196f3f0262cSandi  if(!is_dir($dir)){
197f3f0262cSandi    io_mkdir_p($dir) || msg("Creating directory $dir failed",-1);
198f3f0262cSandi  }
199f3f0262cSandi  umask($conf['umask']);
200f3f0262cSandi}
201f3f0262cSandi
202f3f0262cSandi/**
203f3f0262cSandi * Creates a directory hierachy.
204f3f0262cSandi *
20515fae107Sandi * @link    http://www.php.net/manual/en/function.mkdir.php
206f3f0262cSandi * @author  <saint@corenova.com>
2073dc3a5f1Sandi * @author  Andreas Gohr <andi@splitbrain.org>
208f3f0262cSandi */
209f3f0262cSandifunction io_mkdir_p($target){
2103dc3a5f1Sandi  global $conf;
211f3f0262cSandi  if (is_dir($target)||empty($target)) return 1; // best case check first
212f3f0262cSandi  if (@file_exists($target) && !is_dir($target)) return 0;
2133dc3a5f1Sandi  //recursion
2143dc3a5f1Sandi  if (io_mkdir_p(substr($target,0,strrpos($target,'/')))){
2153dc3a5f1Sandi    if($conf['safemodehack']){
216034138e2SRainer Weinhold      $dir = preg_replace('/^'.preg_quote(realpath($conf['ftp']['root']),'/').'/','', $target);
217034138e2SRainer Weinhold      return io_mkdir_ftp($dir);
2183dc3a5f1Sandi    }else{
219f3f0262cSandi      return @mkdir($target,0777); // crawl back up & create dir tree
2203dc3a5f1Sandi    }
2213dc3a5f1Sandi  }
222f3f0262cSandi  return 0;
223f3f0262cSandi}
224f3f0262cSandi
225f3f0262cSandi/**
2263dc3a5f1Sandi * Creates a directory using FTP
2273dc3a5f1Sandi *
2283dc3a5f1Sandi * This is used when the safemode workaround is enabled
2293dc3a5f1Sandi *
2303dc3a5f1Sandi * @author <andi@splitbrain.org>
2313dc3a5f1Sandi */
2323dc3a5f1Sandifunction io_mkdir_ftp($dir){
2333dc3a5f1Sandi  global $conf;
2343dc3a5f1Sandi
2353dc3a5f1Sandi  if(!function_exists('ftp_connect')){
2363dc3a5f1Sandi    msg("FTP support not found - safemode workaround not usable",-1);
2373dc3a5f1Sandi    return false;
2383dc3a5f1Sandi  }
2393dc3a5f1Sandi
2403dc3a5f1Sandi  $conn = @ftp_connect($conf['ftp']['host'],$conf['ftp']['port'],10);
2413dc3a5f1Sandi  if(!$conn){
2423dc3a5f1Sandi    msg("FTP connection failed",-1);
2433dc3a5f1Sandi    return false;
2443dc3a5f1Sandi  }
2453dc3a5f1Sandi
2463dc3a5f1Sandi  if(!@ftp_login($conn, $conf['ftp']['user'], $conf['ftp']['pass'])){
2473dc3a5f1Sandi    msg("FTP login failed",-1);
2483dc3a5f1Sandi    return false;
2493dc3a5f1Sandi  }
2503dc3a5f1Sandi
2513dc3a5f1Sandi  //create directory
252034138e2SRainer Weinhold  $ok = @ftp_mkdir($conn, $dir);
2533dc3a5f1Sandi  //set permissions (using the directory umask)
254034138e2SRainer Weinhold  @ftp_site($conn,sprintf("CHMOD %04o %s",(0777 - $conf['dmask']),$dir));
2553dc3a5f1Sandi
256034138e2SRainer Weinhold  @ftp_close($conn);
2573dc3a5f1Sandi  return $ok;
2583dc3a5f1Sandi}
2593dc3a5f1Sandi
2603dc3a5f1Sandi/**
261b625487dSandi * downloads a file from the net and saves it to the given location
262b625487dSandi *
263b625487dSandi * @author Andreas Gohr <andi@splitbrain.org>
264b625487dSandi * @todo   Add size limit
265b625487dSandi */
266b625487dSandifunction io_download($url,$file){
267b625487dSandi  $fp = @fopen($url,"rb");
268b625487dSandi  if(!$fp) return false;
269b625487dSandi
2700e33fac4Sandi  $kb  = 0;
2710e33fac4Sandi  $now = time();
2720e33fac4Sandi
273b625487dSandi  while(!feof($fp)){
2740e33fac4Sandi    if($kb++ > 2048 || (time() - $now) > 45){
2750e33fac4Sandi      //abort on 2 MB and timeout on 45 sec
2760e33fac4Sandi      return false;
2770e33fac4Sandi    }
278b625487dSandi    $cont.= fread($fp,1024);
279b625487dSandi  }
280b625487dSandi  fclose($fp);
281b625487dSandi
282b625487dSandi  $fp2 = @fopen($file,"w");
283b625487dSandi  if(!$fp2) return false;
284b625487dSandi  fwrite($fp2,$cont);
285b625487dSandi  fclose($fp2);
286b625487dSandi  return true;
287b625487dSandi}
288b625487dSandi
289b625487dSandi/**
290f3f0262cSandi * Runs an external command and returns it's output as string
29115fae107Sandi *
29215fae107Sandi * @author Harry Brueckner <harry_b@eml.cc>
29315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
2943dc3a5f1Sandi * @deprecated
295f3f0262cSandi */
296f3f0262cSandifunction io_runcmd($cmd){
297f3f0262cSandi  $fh = popen($cmd, "r");
298f3f0262cSandi  if(!$fh) return false;
299f3f0262cSandi  $ret = '';
300f3f0262cSandi  while (!feof($fh)) {
301f3f0262cSandi    $ret .= fread($fh, 8192);
302f3f0262cSandi  }
303f3f0262cSandi  pclose($fh);
304f3f0262cSandi  return $ret;
305f3f0262cSandi}
306f3f0262cSandi
307340756e4Sandi
308340756e4Sandi//Setup VIM: ex: et ts=2 enc=utf-8 :
309