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