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