xref: /dokuwiki/inc/io.php (revision bf5e5a5ba7408165918eb7d2398680ff245a48bb)
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');
12f3f0262cSandi
13f3f0262cSandi/**
1453d6ccfeSandi * Removes empty directories
1553d6ccfeSandi *
1653d6ccfeSandi * @todo use safemode hack
1753d6ccfeSandi * @author  Andreas Gohr <andi@splitbrain.org>
1853d6ccfeSandi */
1953d6ccfeSandifunction io_sweepNS($id){
2053d6ccfeSandi  global $conf;
2153d6ccfeSandi
2253d6ccfeSandi  //scan all namespaces
2353d6ccfeSandi  while(($id = getNS($id)) !== false){
2453d6ccfeSandi		$dir = $conf['datadir'].'/'.str_replace(':','/',$id);
2553d6ccfeSandi    $dir = utf8_encodeFN($dir);
2653d6ccfeSandi
2753d6ccfeSandi    //try to delete dir else return
2853d6ccfeSandi    if(!@rmdir($dir)) return;
2953d6ccfeSandi  }
3053d6ccfeSandi}
3153d6ccfeSandi
3253d6ccfeSandi/**
3315fae107Sandi * Returns content of $file as cleaned string.
3415fae107Sandi *
3515fae107Sandi * Uses gzip if extension is .gz
3615fae107Sandi *
3715fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
38f3f0262cSandi */
39e34c0709SAndreas Gohrfunction io_readFile($file,$clean=true){
40f3f0262cSandi  $ret = '';
41f3f0262cSandi  if(@file_exists($file)){
42f3f0262cSandi    if(substr($file,-3) == '.gz'){
43f3f0262cSandi      $ret = join('',gzfile($file));
44f3f0262cSandi    }else{
45f3f0262cSandi      $ret = join('',file($file));
46f3f0262cSandi    }
47f3f0262cSandi  }
48e34c0709SAndreas Gohr  if($clean){
49f3f0262cSandi    return cleanText($ret);
50e34c0709SAndreas Gohr  }else{
51e34c0709SAndreas Gohr    return $ret;
52e34c0709SAndreas Gohr  }
53f3f0262cSandi}
54f3f0262cSandi
55f3f0262cSandi/**
5615fae107Sandi * Saves $content to $file.
57f3f0262cSandi *
581380fc45SAndreas Gohr * If the third parameter is set to true the given content
591380fc45SAndreas Gohr * will be appended.
601380fc45SAndreas Gohr *
6115fae107Sandi * Uses gzip if extension is .gz
6215fae107Sandi *
6315fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
6415fae107Sandi * @return bool true on success
65f3f0262cSandi */
661380fc45SAndreas Gohrfunction io_saveFile($file,$content,$append=false){
671380fc45SAndreas Gohr  $mode = ($append) ? 'ab' : 'wb';
681380fc45SAndreas Gohr
69f3f0262cSandi  io_makeFileDir($file);
7090eb8392Sandi  io_lock($file);
71f3f0262cSandi  if(substr($file,-3) == '.gz'){
721380fc45SAndreas Gohr    $fh = @gzopen($file,$mode.'9');
73f3f0262cSandi    if(!$fh){
74f3f0262cSandi      msg("Writing $file failed",-1);
75f3f0262cSandi      return false;
76f3f0262cSandi    }
77f3f0262cSandi    gzwrite($fh, $content);
78f3f0262cSandi    gzclose($fh);
79f3f0262cSandi  }else{
801380fc45SAndreas Gohr    $fh = @fopen($file,$mode);
81f3f0262cSandi    if(!$fh){
82f3f0262cSandi      msg("Writing $file failed",-1);
83f3f0262cSandi      return false;
84f3f0262cSandi    }
85f3f0262cSandi    fwrite($fh, $content);
86f3f0262cSandi    fclose($fh);
87f3f0262cSandi  }
8890eb8392Sandi  io_unlock($file);
89f3f0262cSandi  return true;
90f3f0262cSandi}
91f3f0262cSandi
92f3f0262cSandi/**
931380fc45SAndreas Gohr * Delete exact linematch for $badline from $file.
941380fc45SAndreas Gohr *
951380fc45SAndreas Gohr * Be sure to include the trailing newline in $badline
96b158d625SSteven Danz *
97b158d625SSteven Danz * Uses gzip if extension is .gz
98b158d625SSteven Danz *
998b06d178Schris * 2005-10-14 : added regex option -- Christopher Smith <chris@jalakai.co.uk>
1008b06d178Schris *
101b158d625SSteven Danz * @author Steven Danz <steven-danz@kc.rr.com>
102b158d625SSteven Danz * @return bool true on success
103b158d625SSteven Danz */
1048b06d178Schrisfunction io_deleteFromFile($file,$badline,$regex=false){
1051380fc45SAndreas Gohr  if (!@file_exists($file)) return true;
1061380fc45SAndreas Gohr
107b158d625SSteven Danz  io_lock($file);
1081380fc45SAndreas Gohr
1091380fc45SAndreas Gohr  // load into array
110b158d625SSteven Danz  if(substr($file,-3) == '.gz'){
1111380fc45SAndreas Gohr    $lines = gzfile($file);
112b158d625SSteven Danz  }else{
1131380fc45SAndreas Gohr    $lines = file($file);
114b158d625SSteven Danz  }
115b158d625SSteven Danz
1161380fc45SAndreas Gohr  // remove all matching lines
1178b06d178Schris  if ($regex) {
1188b06d178Schris  	$lines = preg_grep($badline,$lines,PREG_GREP_INVERT);
1198b06d178Schris  } else {
1201380fc45SAndreas Gohr    $pos = array_search($badline,$lines); //return null or false if not found
1211380fc45SAndreas Gohr    while(is_int($pos)){
1221380fc45SAndreas Gohr      unset($lines[$pos]);
1231380fc45SAndreas Gohr      $pos = array_search($badline,$lines);
124b158d625SSteven Danz    }
1258b06d178Schris  }
126b158d625SSteven Danz
1271380fc45SAndreas Gohr  if(count($lines)){
1281380fc45SAndreas Gohr    $content = join('',$lines);
129b158d625SSteven Danz    if(substr($file,-3) == '.gz'){
130b158d625SSteven Danz      $fh = @gzopen($file,'wb9');
131b158d625SSteven Danz      if(!$fh){
132b158d625SSteven Danz        msg("Removing content from $file failed",-1);
133b158d625SSteven Danz        return false;
134b158d625SSteven Danz      }
135b158d625SSteven Danz      gzwrite($fh, $content);
136b158d625SSteven Danz      gzclose($fh);
137b158d625SSteven Danz    }else{
138b158d625SSteven Danz      $fh = @fopen($file,'wb');
139b158d625SSteven Danz      if(!$fh){
140b158d625SSteven Danz        msg("Removing content from $file failed",-1);
141b158d625SSteven Danz        return false;
142b158d625SSteven Danz      }
143b158d625SSteven Danz      fwrite($fh, $content);
144b158d625SSteven Danz      fclose($fh);
145b158d625SSteven Danz    }
146b158d625SSteven Danz  }else{
147b158d625SSteven Danz    @unlink($file);
148b158d625SSteven Danz  }
149b158d625SSteven Danz
150b158d625SSteven Danz  io_unlock($file);
151b158d625SSteven Danz  return true;
152b158d625SSteven Danz}
153b158d625SSteven Danz
154b158d625SSteven Danz/**
15590eb8392Sandi * Tries to lock a file
15690eb8392Sandi *
15790eb8392Sandi * Locking is only done for io_savefile and uses directories
15890eb8392Sandi * inside $conf['lockdir']
15990eb8392Sandi *
16090eb8392Sandi * It waits maximal 3 seconds for the lock, after this time
16190eb8392Sandi * the lock is assumed to be stale and the function goes on
16290eb8392Sandi *
16390eb8392Sandi * @author Andreas Gohr <andi@splitbrain.org>
16490eb8392Sandi */
16590eb8392Sandifunction io_lock($file){
16690eb8392Sandi  global $conf;
16790eb8392Sandi  // no locking if safemode hack
16890eb8392Sandi  if($conf['safemodehack']) return;
16990eb8392Sandi
17090eb8392Sandi  $lockDir = $conf['lockdir'].'/'.md5($file);
17190eb8392Sandi  @ignore_user_abort(1);
17290eb8392Sandi
17390eb8392Sandi
17490eb8392Sandi  $timeStart = time();
17590eb8392Sandi  do {
17690eb8392Sandi    //waited longer than 3 seconds? -> stale lock
17790eb8392Sandi    if ((time() - $timeStart) > 3) break;
17890eb8392Sandi    $locked = @mkdir($lockDir);
17990eb8392Sandi  } while ($locked === false);
18090eb8392Sandi}
18190eb8392Sandi
18290eb8392Sandi/**
18390eb8392Sandi * Unlocks a file
18490eb8392Sandi *
18590eb8392Sandi * @author Andreas Gohr <andi@splitbrain.org>
18690eb8392Sandi */
18790eb8392Sandifunction io_unlock($file){
18890eb8392Sandi  global $conf;
18990eb8392Sandi  // no locking if safemode hack
19090eb8392Sandi  if($conf['safemodehack']) return;
19190eb8392Sandi
19290eb8392Sandi  $lockDir = $conf['lockdir'].'/'.md5($file);
19390eb8392Sandi  @rmdir($lockDir);
19490eb8392Sandi  @ignore_user_abort(0);
19590eb8392Sandi}
19690eb8392Sandi
19790eb8392Sandi/**
198f3f0262cSandi * Create the directory needed for the given file
19915fae107Sandi *
20015fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
201f3f0262cSandi */
202f3f0262cSandifunction io_makeFileDir($file){
203f3f0262cSandi  global $conf;
204f3f0262cSandi
205f3f0262cSandi  $dir = dirname($file);
206f3f0262cSandi  umask($conf['dmask']);
207f3f0262cSandi  if(!is_dir($dir)){
208f3f0262cSandi    io_mkdir_p($dir) || msg("Creating directory $dir failed",-1);
209f3f0262cSandi  }
210f3f0262cSandi  umask($conf['umask']);
211f3f0262cSandi}
212f3f0262cSandi
213f3f0262cSandi/**
214f3f0262cSandi * Creates a directory hierachy.
215f3f0262cSandi *
21615fae107Sandi * @link    http://www.php.net/manual/en/function.mkdir.php
217f3f0262cSandi * @author  <saint@corenova.com>
2183dc3a5f1Sandi * @author  Andreas Gohr <andi@splitbrain.org>
219f3f0262cSandi */
220f3f0262cSandifunction io_mkdir_p($target){
2213dc3a5f1Sandi  global $conf;
222f3f0262cSandi  if (is_dir($target)||empty($target)) return 1; // best case check first
223f3f0262cSandi  if (@file_exists($target) && !is_dir($target)) return 0;
2243dc3a5f1Sandi  //recursion
2253dc3a5f1Sandi  if (io_mkdir_p(substr($target,0,strrpos($target,'/')))){
2263dc3a5f1Sandi    if($conf['safemodehack']){
227034138e2SRainer Weinhold      $dir = preg_replace('/^'.preg_quote(realpath($conf['ftp']['root']),'/').'/','', $target);
228034138e2SRainer Weinhold      return io_mkdir_ftp($dir);
2293dc3a5f1Sandi    }else{
230f3f0262cSandi      return @mkdir($target,0777); // crawl back up & create dir tree
2313dc3a5f1Sandi    }
2323dc3a5f1Sandi  }
233f3f0262cSandi  return 0;
234f3f0262cSandi}
235f3f0262cSandi
236f3f0262cSandi/**
2373dc3a5f1Sandi * Creates a directory using FTP
2383dc3a5f1Sandi *
2393dc3a5f1Sandi * This is used when the safemode workaround is enabled
2403dc3a5f1Sandi *
2413dc3a5f1Sandi * @author <andi@splitbrain.org>
2423dc3a5f1Sandi */
2433dc3a5f1Sandifunction io_mkdir_ftp($dir){
2443dc3a5f1Sandi  global $conf;
2453dc3a5f1Sandi
2463dc3a5f1Sandi  if(!function_exists('ftp_connect')){
2473dc3a5f1Sandi    msg("FTP support not found - safemode workaround not usable",-1);
2483dc3a5f1Sandi    return false;
2493dc3a5f1Sandi  }
2503dc3a5f1Sandi
2513dc3a5f1Sandi  $conn = @ftp_connect($conf['ftp']['host'],$conf['ftp']['port'],10);
2523dc3a5f1Sandi  if(!$conn){
2533dc3a5f1Sandi    msg("FTP connection failed",-1);
2543dc3a5f1Sandi    return false;
2553dc3a5f1Sandi  }
2563dc3a5f1Sandi
2573dc3a5f1Sandi  if(!@ftp_login($conn, $conf['ftp']['user'], $conf['ftp']['pass'])){
2583dc3a5f1Sandi    msg("FTP login failed",-1);
2593dc3a5f1Sandi    return false;
2603dc3a5f1Sandi  }
2613dc3a5f1Sandi
2623dc3a5f1Sandi  //create directory
263034138e2SRainer Weinhold  $ok = @ftp_mkdir($conn, $dir);
2643dc3a5f1Sandi  //set permissions (using the directory umask)
265034138e2SRainer Weinhold  @ftp_site($conn,sprintf("CHMOD %04o %s",(0777 - $conf['dmask']),$dir));
2663dc3a5f1Sandi
267034138e2SRainer Weinhold  @ftp_close($conn);
2683dc3a5f1Sandi  return $ok;
2693dc3a5f1Sandi}
2703dc3a5f1Sandi
2713dc3a5f1Sandi/**
27273ccfcb9Schris * downloads a file from the net and saves it
27373ccfcb9Schris *
27473ccfcb9Schris * if $useAttachment is false,
27573ccfcb9Schris * - $file is the full filename to save the file, incl. path
27673ccfcb9Schris * - if successful will return true, false otherwise
27773ccfcb9Schris
27873ccfcb9Schris * if $useAttachment is true,
27973ccfcb9Schris * - $file is the directory where the file should be saved
28073ccfcb9Schris * - if successful will return the name used for the saved file, false otherwise
281b625487dSandi *
282b625487dSandi * @author Andreas Gohr <andi@splitbrain.org>
28373ccfcb9Schris * @author Chris Smith <chris@jalakai.co.uk>
284b625487dSandi */
28573ccfcb9Schrisfunction io_download($url,$file,$useAttachment=false,$defaultName=''){
2869b307a83SAndreas Gohr  $http = new DokuHTTPClient();
2879b307a83SAndreas Gohr  $http->max_bodysize = 2*1024*1024; //max. 2MB
2889b307a83SAndreas Gohr  $http->timeout = 25; //max. 25 sec
2899b307a83SAndreas Gohr
2909b307a83SAndreas Gohr  $data = $http->get($url);
2919b307a83SAndreas Gohr  if(!$data) return false;
2929b307a83SAndreas Gohr
29373ccfcb9Schris  if ($useAttachment) {
29473ccfcb9Schris    $name = '';
29573ccfcb9Schris      if (isset($http->resp_headers['content-disposition'])) {
29673ccfcb9Schris      $content_disposition = $http->resp_headers['content-disposition'];
29773ccfcb9Schris      if (is_string($content_disposition) &&
29873ccfcb9Schris          preg_match('/attachment;\s*filename\s*=\s*"([^"]*)"/i', $content_disposition, $match=array())) {
29973ccfcb9Schris
30073ccfcb9Schris          $name = basename($match[1]);
30173ccfcb9Schris      }
30273ccfcb9Schris
30373ccfcb9Schris    }
30473ccfcb9Schris
30573ccfcb9Schris    if (!$name) {
30673ccfcb9Schris        if (!$defaultName) return false;
30773ccfcb9Schris        $name = $defaultName;
30873ccfcb9Schris    }
30973ccfcb9Schris
31073ccfcb9Schris    $file = $file.$name;
31173ccfcb9Schris  }
31273ccfcb9Schris
3139b307a83SAndreas Gohr  $fp = @fopen($file,"w");
314b625487dSandi  if(!$fp) return false;
3159b307a83SAndreas Gohr  fwrite($fp,$data);
316b625487dSandi  fclose($fp);
31773ccfcb9Schris  if ($useAttachment) return $name;
318b625487dSandi  return true;
319b625487dSandi}
320b625487dSandi
321b625487dSandi/**
322*bf5e5a5bSAndreas Gohr * Windows copatible rename
323*bf5e5a5bSAndreas Gohr *
324*bf5e5a5bSAndreas Gohr * rename() can not overwrite existing files on Windows
325*bf5e5a5bSAndreas Gohr * this function will use copy/unlink instead
326*bf5e5a5bSAndreas Gohr */
327*bf5e5a5bSAndreas Gohrfunction io_rename($from,$to){
328*bf5e5a5bSAndreas Gohr  if(!@rename($from,$to)){
329*bf5e5a5bSAndreas Gohr    if(@copy($from,$to)){
330*bf5e5a5bSAndreas Gohr      @unlink($from);
331*bf5e5a5bSAndreas Gohr      return true;
332*bf5e5a5bSAndreas Gohr    }
333*bf5e5a5bSAndreas Gohr    return false;
334*bf5e5a5bSAndreas Gohr  }
335*bf5e5a5bSAndreas Gohr  return true;
336*bf5e5a5bSAndreas Gohr}
337*bf5e5a5bSAndreas Gohr
338*bf5e5a5bSAndreas Gohr
339*bf5e5a5bSAndreas Gohr/**
340f3f0262cSandi * Runs an external command and returns it's output as string
34115fae107Sandi *
34215fae107Sandi * @author Harry Brueckner <harry_b@eml.cc>
34315fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
3443dc3a5f1Sandi * @deprecated
345f3f0262cSandi */
346f3f0262cSandifunction io_runcmd($cmd){
347f3f0262cSandi  $fh = popen($cmd, "r");
348f3f0262cSandi  if(!$fh) return false;
349f3f0262cSandi  $ret = '';
350f3f0262cSandi  while (!feof($fh)) {
351f3f0262cSandi    $ret .= fread($fh, 8192);
352f3f0262cSandi  }
353f3f0262cSandi  pclose($fh);
354f3f0262cSandi  return $ret;
355f3f0262cSandi}
356f3f0262cSandi
357340756e4Sandi
358340756e4Sandi//Setup VIM: ex: et ts=2 enc=utf-8 :
359