xref: /dokuwiki/inc/io.php (revision b158d625b53833ef391800a991ad93d965d9425e)
1<?php
2/**
3 * File IO functions
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Andreas Gohr <andi@splitbrain.org>
7 */
8
9  if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
10  require_once(DOKU_INC.'inc/common.php');
11
12/**
13 * Removes empty directories
14 *
15 * @todo use safemode hack
16 * @author  Andreas Gohr <andi@splitbrain.org>
17 */
18function io_sweepNS($id){
19  global $conf;
20
21  //scan all namespaces
22  while(($id = getNS($id)) !== false){
23		$dir = $conf['datadir'].'/'.str_replace(':','/',$id);
24    $dir = utf8_encodeFN($dir);
25
26    //try to delete dir else return
27    if(!@rmdir($dir)) return;
28  }
29}
30
31/**
32 * Returns content of $file as cleaned string.
33 *
34 * Uses gzip if extension is .gz
35 *
36 * @author  Andreas Gohr <andi@splitbrain.org>
37 */
38function io_readFile($file){
39  $ret = '';
40  if(@file_exists($file)){
41    if(substr($file,-3) == '.gz'){
42      $ret = join('',gzfile($file));
43    }else{
44      $ret = join('',file($file));
45    }
46  }
47  return cleanText($ret);
48}
49
50/**
51 * Saves $content to $file.
52 *
53 * Uses gzip if extension is .gz
54 *
55 * @author  Andreas Gohr <andi@splitbrain.org>
56 * @return bool true on success
57 */
58function io_saveFile($file,$content){
59  io_makeFileDir($file);
60  io_lock($file);
61  if(substr($file,-3) == '.gz'){
62    $fh = @gzopen($file,'wb9');
63    if(!$fh){
64      msg("Writing $file failed",-1);
65      return false;
66    }
67    gzwrite($fh, $content);
68    gzclose($fh);
69  }else{
70    $fh = @fopen($file,'wb');
71    if(!$fh){
72      msg("Writing $file failed",-1);
73      return false;
74    }
75    fwrite($fh, $content);
76    fclose($fh);
77  }
78  io_unlock($file);
79  return true;
80}
81
82/**
83 * Appends $content to $file.
84 *
85 * Uses gzip if extension is .gz
86 *
87 * @author Steven Danz <steven-danz@kc.rr.com>
88 * @return bool true on success
89 */
90function io_appendFile($file,$content){
91  io_makeFileDir($file);
92  io_lock($file);
93  if(substr($file,-3) == '.gz'){
94    $fh = @gzopen($file,'ab9');
95    if(!$fh){
96      msg("Appending to $file failed",-1);
97      return false;
98    }
99    gzwrite($fh, $content);
100    gzclose($fh);
101  }else{
102    $fh = @fopen($file,'ab');
103    if(!$fh){
104      msg("Appending to $file failed",-1);
105      return false;
106    }
107    fwrite($fh, $content);
108    fclose($fh);
109  }
110  io_unlock($file);
111  return true;
112}
113
114/**
115 * Delete exact match for $content from $file.
116 *
117 * Uses gzip if extension is .gz
118 *
119 * @author Steven Danz <steven-danz@kc.rr.com>
120 * @return bool true on success
121 */
122function io_deleteFromFile($file,$remove){
123  if (@file_exists($file)) {
124    io_lock($file);
125    $content = '';
126    if(substr($file,-3) == '.gz'){
127      $mlist = gzfile($file);
128    }else{
129      $mlist = file($file);
130    }
131    foreach ($mlist as $entry) {
132      if ($entry != $remove) {
133        $content = $content . $entry;
134      }
135    }
136
137    if (!empty($content)) {
138      if(substr($file,-3) == '.gz'){
139        $fh = @gzopen($file,'wb9');
140        if(!$fh){
141          msg("Removing content from $file failed",-1);
142          return false;
143        }
144        gzwrite($fh, $content);
145        gzclose($fh);
146      }else{
147        $fh = @fopen($file,'wb');
148        if(!$fh){
149          msg("Removing content from $file failed",-1);
150          return false;
151        }
152        fwrite($fh, $content);
153        fclose($fh);
154      }
155    } else {
156      @unlink($file);
157    }
158
159    io_unlock($file);
160  }
161  return true;
162}
163
164/**
165 * Tries to lock a file
166 *
167 * Locking is only done for io_savefile and uses directories
168 * inside $conf['lockdir']
169 *
170 * It waits maximal 3 seconds for the lock, after this time
171 * the lock is assumed to be stale and the function goes on
172 *
173 * @author Andreas Gohr <andi@splitbrain.org>
174 */
175function io_lock($file){
176  global $conf;
177  // no locking if safemode hack
178  if($conf['safemodehack']) return;
179
180  $lockDir = $conf['lockdir'].'/'.md5($file);
181  @ignore_user_abort(1);
182
183
184  $timeStart = time();
185  do {
186    //waited longer than 3 seconds? -> stale lock
187    if ((time() - $timeStart) > 3) break;
188    $locked = @mkdir($lockDir);
189  } while ($locked === false);
190}
191
192/**
193 * Unlocks a file
194 *
195 * @author Andreas Gohr <andi@splitbrain.org>
196 */
197function io_unlock($file){
198  global $conf;
199  // no locking if safemode hack
200  if($conf['safemodehack']) return;
201
202  $lockDir = $conf['lockdir'].'/'.md5($file);
203  @rmdir($lockDir);
204  @ignore_user_abort(0);
205}
206
207/**
208 * Create the directory needed for the given file
209 *
210 * @author  Andreas Gohr <andi@splitbrain.org>
211 */
212function io_makeFileDir($file){
213  global $conf;
214
215  $dir = dirname($file);
216  umask($conf['dmask']);
217  if(!is_dir($dir)){
218    io_mkdir_p($dir) || msg("Creating directory $dir failed",-1);
219  }
220  umask($conf['umask']);
221}
222
223/**
224 * Creates a directory hierachy.
225 *
226 * @link    http://www.php.net/manual/en/function.mkdir.php
227 * @author  <saint@corenova.com>
228 * @author  Andreas Gohr <andi@splitbrain.org>
229 */
230function io_mkdir_p($target){
231  global $conf;
232  if (is_dir($target)||empty($target)) return 1; // best case check first
233  if (@file_exists($target) && !is_dir($target)) return 0;
234  //recursion
235  if (io_mkdir_p(substr($target,0,strrpos($target,'/')))){
236    if($conf['safemodehack']){
237      $dir = preg_replace('/^'.preg_quote(realpath($conf['ftp']['root']),'/').'/','', $target);
238      return io_mkdir_ftp($dir);
239    }else{
240      return @mkdir($target,0777); // crawl back up & create dir tree
241    }
242  }
243  return 0;
244}
245
246/**
247 * Creates a directory using FTP
248 *
249 * This is used when the safemode workaround is enabled
250 *
251 * @author <andi@splitbrain.org>
252 */
253function io_mkdir_ftp($dir){
254  global $conf;
255
256  if(!function_exists('ftp_connect')){
257    msg("FTP support not found - safemode workaround not usable",-1);
258    return false;
259  }
260
261  $conn = @ftp_connect($conf['ftp']['host'],$conf['ftp']['port'],10);
262  if(!$conn){
263    msg("FTP connection failed",-1);
264    return false;
265  }
266
267  if(!@ftp_login($conn, $conf['ftp']['user'], $conf['ftp']['pass'])){
268    msg("FTP login failed",-1);
269    return false;
270  }
271
272  //create directory
273  $ok = @ftp_mkdir($conn, $dir);
274  //set permissions (using the directory umask)
275  @ftp_site($conn,sprintf("CHMOD %04o %s",(0777 - $conf['dmask']),$dir));
276
277  @ftp_close($conn);
278  return $ok;
279}
280
281/**
282 * downloads a file from the net and saves it to the given location
283 *
284 * @author Andreas Gohr <andi@splitbrain.org>
285 * @todo   Add size limit
286 */
287function io_download($url,$file){
288  $fp = @fopen($url,"rb");
289  if(!$fp) return false;
290
291  $kb  = 0;
292  $now = time();
293
294  while(!feof($fp)){
295    if($kb++ > 2048 || (time() - $now) > 45){
296      //abort on 2 MB and timeout on 45 sec
297      return false;
298    }
299    $cont.= fread($fp,1024);
300  }
301  fclose($fp);
302
303  $fp2 = @fopen($file,"w");
304  if(!$fp2) return false;
305  fwrite($fp2,$cont);
306  fclose($fp2);
307  return true;
308}
309
310/**
311 * Runs an external command and returns it's output as string
312 *
313 * @author Harry Brueckner <harry_b@eml.cc>
314 * @author Andreas Gohr <andi@splitbrain.org>
315 * @deprecated
316 */
317function io_runcmd($cmd){
318  $fh = popen($cmd, "r");
319  if(!$fh) return false;
320  $ret = '';
321  while (!feof($fh)) {
322    $ret .= fread($fh, 8192);
323  }
324  pclose($fh);
325  return $ret;
326}
327
328
329//Setup VIM: ex: et ts=2 enc=utf-8 :
330