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