xref: /dokuwiki/inc/io.php (revision 706882dcf32358de6c9300ced7b5fcfa9ba28771)
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 * If the third parameter is set to true the given content
54 * will be appended.
55 *
56 * Uses gzip if extension is .gz
57 *
58 * @author  Andreas Gohr <andi@splitbrain.org>
59 * @return bool true on success
60 */
61function io_saveFile($file,$content,$append=false){
62  $mode = ($append) ? 'ab' : 'wb';
63
64  io_makeFileDir($file);
65  io_lock($file);
66  if(substr($file,-3) == '.gz'){
67    $fh = @gzopen($file,$mode.'9');
68    if(!$fh){
69      msg("Writing $file failed",-1);
70      return false;
71    }
72    gzwrite($fh, $content);
73    gzclose($fh);
74  }else{
75    $fh = @fopen($file,$mode);
76    if(!$fh){
77      msg("Writing $file failed",-1);
78      return false;
79    }
80    fwrite($fh, $content);
81    fclose($fh);
82  }
83  io_unlock($file);
84  return true;
85}
86
87/**
88 * Delete exact linematch for $badline from $file.
89 *
90 * Be sure to include the trailing newline in $badline
91 *
92 * Uses gzip if extension is .gz
93 *
94 * @author Steven Danz <steven-danz@kc.rr.com>
95 * @return bool true on success
96 */
97function io_deleteFromFile($file,$badline){
98  if (!@file_exists($file)) return true;
99
100  io_lock($file);
101
102  // load into array
103  if(substr($file,-3) == '.gz'){
104    $lines = gzfile($file);
105  }else{
106    $lines = file($file);
107  }
108
109  // remove all matching lines
110  $pos = array_search($badline,$lines); //return null or false if not found
111  while(is_int($pos)){
112    unset($lines[$pos]);
113    $pos = array_search($badline,$lines);
114  }
115
116  if(count($lines)){
117    $content = join('',$lines);
118    if(substr($file,-3) == '.gz'){
119      $fh = @gzopen($file,'wb9');
120      if(!$fh){
121        msg("Removing content from $file failed",-1);
122        return false;
123      }
124      gzwrite($fh, $content);
125      gzclose($fh);
126    }else{
127      $fh = @fopen($file,'wb');
128      if(!$fh){
129        msg("Removing content from $file failed",-1);
130        return false;
131      }
132      fwrite($fh, $content);
133      fclose($fh);
134    }
135  }else{
136    @unlink($file);
137  }
138
139  io_unlock($file);
140  return true;
141}
142
143/**
144 * Tries to lock a file
145 *
146 * Locking is only done for io_savefile and uses directories
147 * inside $conf['lockdir']
148 *
149 * It waits maximal 3 seconds for the lock, after this time
150 * the lock is assumed to be stale and the function goes on
151 *
152 * @author Andreas Gohr <andi@splitbrain.org>
153 */
154function io_lock($file){
155  global $conf;
156  // no locking if safemode hack
157  if($conf['safemodehack']) return;
158
159  $lockDir = $conf['lockdir'].'/'.md5($file);
160  @ignore_user_abort(1);
161
162
163  $timeStart = time();
164  do {
165    //waited longer than 3 seconds? -> stale lock
166    if ((time() - $timeStart) > 3) break;
167    $locked = @mkdir($lockDir);
168  } while ($locked === false);
169}
170
171/**
172 * Unlocks a file
173 *
174 * @author Andreas Gohr <andi@splitbrain.org>
175 */
176function io_unlock($file){
177  global $conf;
178  // no locking if safemode hack
179  if($conf['safemodehack']) return;
180
181  $lockDir = $conf['lockdir'].'/'.md5($file);
182  @rmdir($lockDir);
183  @ignore_user_abort(0);
184}
185
186/**
187 * Create the directory needed for the given file
188 *
189 * @author  Andreas Gohr <andi@splitbrain.org>
190 */
191function io_makeFileDir($file){
192  global $conf;
193
194  $dir = dirname($file);
195  umask($conf['dmask']);
196  if(!is_dir($dir)){
197    io_mkdir_p($dir) || msg("Creating directory $dir failed",-1);
198  }
199  umask($conf['umask']);
200}
201
202/**
203 * Creates a directory hierachy.
204 *
205 * @link    http://www.php.net/manual/en/function.mkdir.php
206 * @author  <saint@corenova.com>
207 * @author  Andreas Gohr <andi@splitbrain.org>
208 */
209function io_mkdir_p($target){
210  global $conf;
211  if (is_dir($target)||empty($target)) return 1; // best case check first
212  if (@file_exists($target) && !is_dir($target)) return 0;
213  //recursion
214  if (io_mkdir_p(substr($target,0,strrpos($target,'/')))){
215    if($conf['safemodehack']){
216      $dir = preg_replace('/^'.preg_quote(realpath($conf['ftp']['root']),'/').'/','', $target);
217      return io_mkdir_ftp($dir);
218    }else{
219      return @mkdir($target,0777); // crawl back up & create dir tree
220    }
221  }
222  return 0;
223}
224
225/**
226 * Creates a directory using FTP
227 *
228 * This is used when the safemode workaround is enabled
229 *
230 * @author <andi@splitbrain.org>
231 */
232function io_mkdir_ftp($dir){
233  global $conf;
234
235  if(!function_exists('ftp_connect')){
236    msg("FTP support not found - safemode workaround not usable",-1);
237    return false;
238  }
239
240  $conn = @ftp_connect($conf['ftp']['host'],$conf['ftp']['port'],10);
241  if(!$conn){
242    msg("FTP connection failed",-1);
243    return false;
244  }
245
246  if(!@ftp_login($conn, $conf['ftp']['user'], $conf['ftp']['pass'])){
247    msg("FTP login failed",-1);
248    return false;
249  }
250
251  //create directory
252  $ok = @ftp_mkdir($conn, $dir);
253  //set permissions (using the directory umask)
254  @ftp_site($conn,sprintf("CHMOD %04o %s",(0777 - $conf['dmask']),$dir));
255
256  @ftp_close($conn);
257  return $ok;
258}
259
260/**
261 * downloads a file from the net and saves it to the given location
262 *
263 * @author Andreas Gohr <andi@splitbrain.org>
264 * @todo   Add size limit
265 */
266function io_download($url,$file){
267  $fp = @fopen($url,"rb");
268  if(!$fp) return false;
269
270  $kb  = 0;
271  $now = time();
272
273  while(!feof($fp)){
274    if($kb++ > 2048 || (time() - $now) > 45){
275      //abort on 2 MB and timeout on 45 sec
276      return false;
277    }
278    $cont.= fread($fp,1024);
279  }
280  fclose($fp);
281
282  $fp2 = @fopen($file,"w");
283  if(!$fp2) return false;
284  fwrite($fp2,$cont);
285  fclose($fp2);
286  return true;
287}
288
289/**
290 * Runs an external command and returns it's output as string
291 *
292 * @author Harry Brueckner <harry_b@eml.cc>
293 * @author Andreas Gohr <andi@splitbrain.org>
294 * @deprecated
295 */
296function io_runcmd($cmd){
297  $fh = popen($cmd, "r");
298  if(!$fh) return false;
299  $ret = '';
300  while (!feof($fh)) {
301    $ret .= fread($fh, 8192);
302  }
303  pclose($fh);
304  return $ret;
305}
306
307
308//Setup VIM: ex: et ts=2 enc=utf-8 :
309