xref: /dokuwiki/inc/io.php (revision 8e0b019f895b3e742a353ac11ff1fe38d121de18)
1ed7b5f09Sandi<?php
215fae107Sandi/**
315fae107Sandi * File IO functions
415fae107Sandi *
515fae107Sandi * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
615fae107Sandi * @author     Andreas Gohr <andi@splitbrain.org>
715fae107Sandi */
815fae107Sandi
9ed7b5f09Sandi  if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
10ed7b5f09Sandi  require_once(DOKU_INC.'inc/common.php');
119b307a83SAndreas Gohr  require_once(DOKU_INC.'inc/HTTPClient.php');
12cc7d0c94SBen Coburn  require_once(DOKU_INC.'inc/events.php');
13cc7d0c94SBen Coburn  require_once(DOKU_INC.'inc/utf8.php');
14f3f0262cSandi
15f3f0262cSandi/**
1653d6ccfeSandi * Removes empty directories
1753d6ccfeSandi *
18cc7d0c94SBen Coburn * Sends IO_NAMESPACE_DELETED events for 'pages' and 'media' namespaces.
19cc7d0c94SBen Coburn * Event data:
20cc7d0c94SBen Coburn * $data[0]    ns: The colon separated namespace path minus the trailing page name.
21cc7d0c94SBen Coburn * $data[1]    ns_type: 'pages' or 'media' namespace tree.
22cc7d0c94SBen Coburn *
2353d6ccfeSandi * @todo use safemode hack
2453d6ccfeSandi * @author  Andreas Gohr <andi@splitbrain.org>
25cc7d0c94SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
2653d6ccfeSandi */
27755f1e03SAndreas Gohrfunction io_sweepNS($id,$basedir='datadir'){
2853d6ccfeSandi  global $conf;
29cc7d0c94SBen Coburn  $types = array ('datadir'=>'pages', 'mediadir'=>'media');
30cc7d0c94SBen Coburn  $ns_type = (isset($types[$basedir])?$types[$basedir]:false);
3153d6ccfeSandi
3253d6ccfeSandi  //scan all namespaces
3353d6ccfeSandi  while(($id = getNS($id)) !== false){
34755f1e03SAndreas Gohr    $dir = $conf[$basedir].'/'.utf8_encodeFN(str_replace(':','/',$id));
3553d6ccfeSandi
3653d6ccfeSandi    //try to delete dir else return
37cc7d0c94SBen Coburn    if(@rmdir($dir)) {
38cc7d0c94SBen Coburn      if ($ns_type!==false) {
39cc7d0c94SBen Coburn        $data = array($id, $ns_type);
40cc7d0c94SBen Coburn        trigger_event('IO_NAMESPACE_DELETED', $data);
41cc7d0c94SBen Coburn      }
42cc7d0c94SBen Coburn    } else { return; }
43cc7d0c94SBen Coburn  }
44cc7d0c94SBen Coburn}
45cc7d0c94SBen Coburn
46cc7d0c94SBen Coburn/**
47cc7d0c94SBen Coburn * Used to read in a DokuWiki page from file, and send IO_WIKIPAGE_READ events.
48cc7d0c94SBen Coburn *
49cc7d0c94SBen Coburn * Generates the action event which delegates to io_readFile().
50cc7d0c94SBen Coburn * Action plugins are allowed to modify the page content in transit.
51cc7d0c94SBen Coburn * The file path should not be changed.
52cc7d0c94SBen Coburn *
53cc7d0c94SBen Coburn * Event data:
54cc7d0c94SBen Coburn * $data[0]    The raw arguments for io_readFile as an array.
55cc7d0c94SBen Coburn * $data[1]    ns: The colon separated namespace path minus the trailing page name. (false if root ns)
56cc7d0c94SBen Coburn * $data[2]    page_name: The wiki page name.
57cc7d0c94SBen Coburn * $data[3]    rev: The page revision, false for current wiki pages.
58cc7d0c94SBen Coburn *
59cc7d0c94SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
60cc7d0c94SBen Coburn */
61cc7d0c94SBen Coburnfunction io_readWikiPage($file, $id, $rev=false) {
62cc7d0c94SBen Coburn    if (empty($rev)) { $rev = false; }
63cc7d0c94SBen Coburn    $data = array(array($file, false), getNS($id), noNS($id), $rev);
64cc7d0c94SBen Coburn    return trigger_event('IO_WIKIPAGE_READ', $data, '_io_readWikiPage_action', false);
65cc7d0c94SBen Coburn}
66cc7d0c94SBen Coburn
67cc7d0c94SBen Coburn/**
68cc7d0c94SBen Coburn * Callback adapter for io_readFile().
69cc7d0c94SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
70cc7d0c94SBen Coburn */
71cc7d0c94SBen Coburnfunction _io_readWikiPage_action($data) {
72cc7d0c94SBen Coburn    if (is_array($data) && is_array($data[0]) && count($data[0])===2) {
73cc7d0c94SBen Coburn        return call_user_func_array('io_readFile', $data[0]);
74cc7d0c94SBen Coburn    } else {
75cc7d0c94SBen Coburn        return ''; //callback error
7653d6ccfeSandi    }
7753d6ccfeSandi}
7853d6ccfeSandi
7953d6ccfeSandi/**
8015fae107Sandi * Returns content of $file as cleaned string.
8115fae107Sandi *
8215fae107Sandi * Uses gzip if extension is .gz
8315fae107Sandi *
84ee4c4a1bSAndreas Gohr * If you want to use the returned value in unserialize
85ee4c4a1bSAndreas Gohr * be sure to set $clean to false!
86ee4c4a1bSAndreas Gohr *
8715fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
88f3f0262cSandi */
89e34c0709SAndreas Gohrfunction io_readFile($file,$clean=true){
90f3f0262cSandi  $ret = '';
91f3f0262cSandi  if(@file_exists($file)){
92f3f0262cSandi    if(substr($file,-3) == '.gz'){
93f3f0262cSandi      $ret = join('',gzfile($file));
94ff3ed99fSmarcel    }else if(substr($file,-4) == '.bz2'){
95ff3ed99fSmarcel      $ret = bzfile($file);
96f3f0262cSandi    }else{
97f3f0262cSandi      $ret = join('',file($file));
98f3f0262cSandi    }
99f3f0262cSandi  }
100e34c0709SAndreas Gohr  if($clean){
101f3f0262cSandi    return cleanText($ret);
102e34c0709SAndreas Gohr  }else{
103e34c0709SAndreas Gohr    return $ret;
104e34c0709SAndreas Gohr  }
105f3f0262cSandi}
106ff3ed99fSmarcel/**
107ff3ed99fSmarcel* Returns the content of a .bz2 compressed file as string
108ff3ed99fSmarcel* @author marcel senf <marcel@rucksackreinigung.de>
109ff3ed99fSmarcel*/
110ff3ed99fSmarcel
111ff3ed99fSmarcelfunction bzfile($file){
112ff3ed99fSmarcel  $bz = bzopen($file,"r");
113ff3ed99fSmarcel  while (!feof($bz)){
114ff3ed99fSmarcel    //8192 seems to be the maximum buffersize?
115ff3ed99fSmarcel	  $str = $str . bzread($bz,8192);
116ff3ed99fSmarcel  }
117ff3ed99fSmarcel  bzclose($bz);
118ff3ed99fSmarcel  return $str;
119ff3ed99fSmarcel}
120ff3ed99fSmarcel
121f3f0262cSandi
122f3f0262cSandi/**
123cc7d0c94SBen Coburn * Used to write out a DokuWiki page to file, and send IO_WIKIPAGE_WRITE events.
124cc7d0c94SBen Coburn *
125cc7d0c94SBen Coburn * This generates an action event and delegates to io_saveFile().
126cc7d0c94SBen Coburn * Action plugins are allowed to modify the page content in transit.
127cc7d0c94SBen Coburn * The file path should not be changed.
128cc7d0c94SBen Coburn * (The append parameter is set to false.)
129cc7d0c94SBen Coburn *
130cc7d0c94SBen Coburn * Event data:
131cc7d0c94SBen Coburn * $data[0]    The raw arguments for io_saveFile as an array.
132cc7d0c94SBen Coburn * $data[1]    ns: The colon separated namespace path minus the trailing page name. (false if root ns)
133cc7d0c94SBen Coburn * $data[2]    page_name: The wiki page name.
134cc7d0c94SBen Coburn * $data[3]    rev: The page revision, false for current wiki pages.
135cc7d0c94SBen Coburn *
136cc7d0c94SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
137cc7d0c94SBen Coburn */
138cc7d0c94SBen Coburnfunction io_writeWikiPage($file, $content, $id, $rev=false) {
139cc7d0c94SBen Coburn    if (empty($rev)) { $rev = false; }
140cc7d0c94SBen Coburn    if ($rev===false) { io_createNamespace($id); } // create namespaces as needed
141cc7d0c94SBen Coburn    $data = array(array($file, $content, false), getNS($id), noNS($id), $rev);
142cc7d0c94SBen Coburn    return trigger_event('IO_WIKIPAGE_WRITE', $data, '_io_writeWikiPage_action', false);
143cc7d0c94SBen Coburn}
144cc7d0c94SBen Coburn
145cc7d0c94SBen Coburn/**
146cc7d0c94SBen Coburn * Callback adapter for io_saveFile().
147cc7d0c94SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
148cc7d0c94SBen Coburn */
149cc7d0c94SBen Coburnfunction _io_writeWikiPage_action($data) {
150cc7d0c94SBen Coburn    if (is_array($data) && is_array($data[0]) && count($data[0])===3) {
151cc7d0c94SBen Coburn        return call_user_func_array('io_saveFile', $data[0]);
152cc7d0c94SBen Coburn    } else {
153cc7d0c94SBen Coburn        return false; //callback error
154cc7d0c94SBen Coburn    }
155cc7d0c94SBen Coburn}
156cc7d0c94SBen Coburn
157cc7d0c94SBen Coburn/**
15815fae107Sandi * Saves $content to $file.
159f3f0262cSandi *
1601380fc45SAndreas Gohr * If the third parameter is set to true the given content
1611380fc45SAndreas Gohr * will be appended.
1621380fc45SAndreas Gohr *
16315fae107Sandi * Uses gzip if extension is .gz
164ff3ed99fSmarcel * and bz2 if extension is .bz2
16515fae107Sandi *
16615fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
16715fae107Sandi * @return bool true on success
168f3f0262cSandi */
1691380fc45SAndreas Gohrfunction io_saveFile($file,$content,$append=false){
170ac9115b0STroels Liebe Bentsen  global $conf;
1711380fc45SAndreas Gohr  $mode = ($append) ? 'ab' : 'wb';
1721380fc45SAndreas Gohr
173d8186216SBen Coburn  $fileexists = @file_exists($file);
174f3f0262cSandi  io_makeFileDir($file);
17590eb8392Sandi  io_lock($file);
176f3f0262cSandi  if(substr($file,-3) == '.gz'){
1771380fc45SAndreas Gohr    $fh = @gzopen($file,$mode.'9');
178f3f0262cSandi    if(!$fh){
179f3f0262cSandi      msg("Writing $file failed",-1);
180f3f0262cSandi      return false;
181f3f0262cSandi    }
182f3f0262cSandi    gzwrite($fh, $content);
183f3f0262cSandi    gzclose($fh);
184ff3ed99fSmarcel  }else if(substr($file,-4) == '.bz2'){
185ff3ed99fSmarcel    $fh = @bzopen($file,$mode);
186ff3ed99fSmarcel    if(!$fh){
187ff3ed99fSmarcel      msg("Writing $file failed", -1);
188ff3ed99fSmarcel      return false;
189ff3ed99fSmarcel    }
190ff3ed99fSmarcel    bzwrite($fh, $content);
191ff3ed99fSmarcel    bzclose($fh);
192f3f0262cSandi  }else{
1931380fc45SAndreas Gohr    $fh = @fopen($file,$mode);
194f3f0262cSandi    if(!$fh){
195f3f0262cSandi      msg("Writing $file failed",-1);
196f3f0262cSandi      return false;
197f3f0262cSandi    }
198f3f0262cSandi    fwrite($fh, $content);
199f3f0262cSandi    fclose($fh);
200f3f0262cSandi  }
201ac9115b0STroels Liebe Bentsen
2021ca31cfeSAndreas Gohr  if(!$fileexists and $conf['fperm']) chmod($file, $conf['fperm']);
20390eb8392Sandi  io_unlock($file);
204f3f0262cSandi  return true;
205f3f0262cSandi}
206f3f0262cSandi
207f3f0262cSandi/**
2081380fc45SAndreas Gohr * Delete exact linematch for $badline from $file.
2091380fc45SAndreas Gohr *
2101380fc45SAndreas Gohr * Be sure to include the trailing newline in $badline
211b158d625SSteven Danz *
212b158d625SSteven Danz * Uses gzip if extension is .gz
213b158d625SSteven Danz *
2148b06d178Schris * 2005-10-14 : added regex option -- Christopher Smith <chris@jalakai.co.uk>
2158b06d178Schris *
216b158d625SSteven Danz * @author Steven Danz <steven-danz@kc.rr.com>
217b158d625SSteven Danz * @return bool true on success
218b158d625SSteven Danz */
2198b06d178Schrisfunction io_deleteFromFile($file,$badline,$regex=false){
2201380fc45SAndreas Gohr  if (!@file_exists($file)) return true;
2211380fc45SAndreas Gohr
222b158d625SSteven Danz  io_lock($file);
2231380fc45SAndreas Gohr
2241380fc45SAndreas Gohr  // load into array
225b158d625SSteven Danz  if(substr($file,-3) == '.gz'){
2261380fc45SAndreas Gohr    $lines = gzfile($file);
227b158d625SSteven Danz  }else{
2281380fc45SAndreas Gohr    $lines = file($file);
229b158d625SSteven Danz  }
230b158d625SSteven Danz
2311380fc45SAndreas Gohr  // remove all matching lines
2328b06d178Schris  if ($regex) {
2338b06d178Schris    $lines = preg_grep($badline,$lines,PREG_GREP_INVERT);
2348b06d178Schris  } else {
2351380fc45SAndreas Gohr    $pos = array_search($badline,$lines); //return null or false if not found
2361380fc45SAndreas Gohr    while(is_int($pos)){
2371380fc45SAndreas Gohr      unset($lines[$pos]);
2381380fc45SAndreas Gohr      $pos = array_search($badline,$lines);
239b158d625SSteven Danz    }
2408b06d178Schris  }
241b158d625SSteven Danz
2421380fc45SAndreas Gohr  if(count($lines)){
2431380fc45SAndreas Gohr    $content = join('',$lines);
244b158d625SSteven Danz    if(substr($file,-3) == '.gz'){
245b158d625SSteven Danz      $fh = @gzopen($file,'wb9');
246b158d625SSteven Danz      if(!$fh){
247b158d625SSteven Danz        msg("Removing content from $file failed",-1);
248b158d625SSteven Danz        return false;
249b158d625SSteven Danz      }
250b158d625SSteven Danz      gzwrite($fh, $content);
251b158d625SSteven Danz      gzclose($fh);
252b158d625SSteven Danz    }else{
253b158d625SSteven Danz      $fh = @fopen($file,'wb');
254b158d625SSteven Danz      if(!$fh){
255b158d625SSteven Danz        msg("Removing content from $file failed",-1);
256b158d625SSteven Danz        return false;
257b158d625SSteven Danz      }
258b158d625SSteven Danz      fwrite($fh, $content);
259b158d625SSteven Danz      fclose($fh);
260b158d625SSteven Danz    }
261b158d625SSteven Danz  }else{
262b158d625SSteven Danz    @unlink($file);
263b158d625SSteven Danz  }
264b158d625SSteven Danz
265b158d625SSteven Danz  io_unlock($file);
266b158d625SSteven Danz  return true;
267b158d625SSteven Danz}
268b158d625SSteven Danz
269b158d625SSteven Danz/**
27090eb8392Sandi * Tries to lock a file
27190eb8392Sandi *
27290eb8392Sandi * Locking is only done for io_savefile and uses directories
27390eb8392Sandi * inside $conf['lockdir']
27490eb8392Sandi *
27590eb8392Sandi * It waits maximal 3 seconds for the lock, after this time
27690eb8392Sandi * the lock is assumed to be stale and the function goes on
27790eb8392Sandi *
27890eb8392Sandi * @author Andreas Gohr <andi@splitbrain.org>
27990eb8392Sandi */
28090eb8392Sandifunction io_lock($file){
28190eb8392Sandi  global $conf;
28290eb8392Sandi  // no locking if safemode hack
28390eb8392Sandi  if($conf['safemodehack']) return;
28490eb8392Sandi
28590eb8392Sandi  $lockDir = $conf['lockdir'].'/'.md5($file);
28690eb8392Sandi  @ignore_user_abort(1);
28790eb8392Sandi
28890eb8392Sandi  $timeStart = time();
28990eb8392Sandi  do {
29090eb8392Sandi    //waited longer than 3 seconds? -> stale lock
29190eb8392Sandi    if ((time() - $timeStart) > 3) break;
29244881d27STroels Liebe Bentsen    $locked = @mkdir($lockDir, $conf['dmode']);
29377b98903SAndreas Gohr    if($locked){
29477b98903SAndreas Gohr      if($conf['dperm']) chmod($lockDir, $conf['dperm']);
29577b98903SAndreas Gohr      break;
29677b98903SAndreas Gohr    }
29777b98903SAndreas Gohr    usleep(50);
29890eb8392Sandi  } while ($locked === false);
29990eb8392Sandi}
30090eb8392Sandi
30190eb8392Sandi/**
30290eb8392Sandi * Unlocks a file
30390eb8392Sandi *
30490eb8392Sandi * @author Andreas Gohr <andi@splitbrain.org>
30590eb8392Sandi */
30690eb8392Sandifunction io_unlock($file){
30790eb8392Sandi  global $conf;
30890eb8392Sandi  // no locking if safemode hack
30990eb8392Sandi  if($conf['safemodehack']) return;
31090eb8392Sandi
31190eb8392Sandi  $lockDir = $conf['lockdir'].'/'.md5($file);
31290eb8392Sandi  @rmdir($lockDir);
31390eb8392Sandi  @ignore_user_abort(0);
31490eb8392Sandi}
31590eb8392Sandi
31690eb8392Sandi/**
317cc7d0c94SBen Coburn * Create missing namespace directories and send the IO_NAMESPACE_CREATED events
318cc7d0c94SBen Coburn * in the order of directory creation. (Parent directories first.)
319cc7d0c94SBen Coburn *
320cc7d0c94SBen Coburn * Event data:
321cc7d0c94SBen Coburn * $data[0]    ns: The colon separated namespace path minus the trailing page name.
322cc7d0c94SBen Coburn * $data[1]    ns_type: 'pages' or 'media' namespace tree.
323cc7d0c94SBen Coburn *
324cc7d0c94SBen Coburn * @author Ben Coburn <btcoburn@silicodon.net>
325cc7d0c94SBen Coburn */
326cc7d0c94SBen Coburnfunction io_createNamespace($id, $ns_type='pages') {
327cc7d0c94SBen Coburn    // verify ns_type
328cc7d0c94SBen Coburn    $types = array('pages'=>'wikiFN', 'media'=>'mediaFN');
329cc7d0c94SBen Coburn    if (!isset($types[$ns_type])) {
330cc7d0c94SBen Coburn        trigger_error('Bad $ns_type parameter for io_createNamespace().');
331cc7d0c94SBen Coburn        return;
332cc7d0c94SBen Coburn    }
333cc7d0c94SBen Coburn    // make event list
334cc7d0c94SBen Coburn    $missing = array();
335cc7d0c94SBen Coburn    $ns_stack = explode(':', $id);
336cc7d0c94SBen Coburn    $ns = $id;
337cc7d0c94SBen Coburn    $tmp = dirname( $file = call_user_func($types[$ns_type], $ns) );
338cc7d0c94SBen Coburn    while (!@is_dir($tmp) && !(@file_exists($tmp) && !is_dir($tmp))) {
339cc7d0c94SBen Coburn        array_pop($ns_stack);
340cc7d0c94SBen Coburn        $ns = implode(':', $ns_stack);
341cc7d0c94SBen Coburn        if (strlen($ns)==0) { break; }
342cc7d0c94SBen Coburn        $missing[] = $ns;
343cc7d0c94SBen Coburn        $tmp = dirname(call_user_func($types[$ns_type], $ns));
344cc7d0c94SBen Coburn    }
345cc7d0c94SBen Coburn    // make directories
346cc7d0c94SBen Coburn    io_makeFileDir($file);
347cc7d0c94SBen Coburn    // send the events
348cc7d0c94SBen Coburn    $missing = array_reverse($missing); // inside out
349cc7d0c94SBen Coburn    foreach ($missing as $ns) {
350cc7d0c94SBen Coburn        $data = array($ns, $ns_type);
351cc7d0c94SBen Coburn        trigger_event('IO_NAMESPACE_CREATED', $data);
352cc7d0c94SBen Coburn    }
353cc7d0c94SBen Coburn}
354cc7d0c94SBen Coburn
355cc7d0c94SBen Coburn/**
356f3f0262cSandi * Create the directory needed for the given file
35715fae107Sandi *
35815fae107Sandi * @author  Andreas Gohr <andi@splitbrain.org>
359f3f0262cSandi */
360f3f0262cSandifunction io_makeFileDir($file){
361f3f0262cSandi  global $conf;
362f3f0262cSandi
363f3f0262cSandi  $dir = dirname($file);
3640d8850c4SAndreas Gohr  if(!@is_dir($dir)){
365f3f0262cSandi    io_mkdir_p($dir) || msg("Creating directory $dir failed",-1);
366f3f0262cSandi  }
367f3f0262cSandi}
368f3f0262cSandi
369f3f0262cSandi/**
370f3f0262cSandi * Creates a directory hierachy.
371f3f0262cSandi *
37215fae107Sandi * @link    http://www.php.net/manual/en/function.mkdir.php
373f3f0262cSandi * @author  <saint@corenova.com>
3743dc3a5f1Sandi * @author  Andreas Gohr <andi@splitbrain.org>
375f3f0262cSandi */
376f3f0262cSandifunction io_mkdir_p($target){
3773dc3a5f1Sandi  global $conf;
3780d8850c4SAndreas Gohr  if (@is_dir($target)||empty($target)) return 1; // best case check first
379f3f0262cSandi  if (@file_exists($target) && !is_dir($target)) return 0;
3803dc3a5f1Sandi  //recursion
3813dc3a5f1Sandi  if (io_mkdir_p(substr($target,0,strrpos($target,'/')))){
3823dc3a5f1Sandi    if($conf['safemodehack']){
383034138e2SRainer Weinhold      $dir = preg_replace('/^'.preg_quote(realpath($conf['ftp']['root']),'/').'/','', $target);
384034138e2SRainer Weinhold      return io_mkdir_ftp($dir);
3853dc3a5f1Sandi    }else{
38644881d27STroels Liebe Bentsen      $ret = @mkdir($target,$conf['dmode']); // crawl back up & create dir tree
3871ca31cfeSAndreas Gohr      if($ret && $conf['dperm']) chmod($target, $conf['dperm']);
38844881d27STroels Liebe Bentsen      return $ret;
3893dc3a5f1Sandi    }
3903dc3a5f1Sandi  }
391f3f0262cSandi  return 0;
392f3f0262cSandi}
393f3f0262cSandi
394f3f0262cSandi/**
3953dc3a5f1Sandi * Creates a directory using FTP
3963dc3a5f1Sandi *
3973dc3a5f1Sandi * This is used when the safemode workaround is enabled
3983dc3a5f1Sandi *
3993dc3a5f1Sandi * @author <andi@splitbrain.org>
4003dc3a5f1Sandi */
4013dc3a5f1Sandifunction io_mkdir_ftp($dir){
4023dc3a5f1Sandi  global $conf;
4033dc3a5f1Sandi
4043dc3a5f1Sandi  if(!function_exists('ftp_connect')){
4053dc3a5f1Sandi    msg("FTP support not found - safemode workaround not usable",-1);
4063dc3a5f1Sandi    return false;
4073dc3a5f1Sandi  }
4083dc3a5f1Sandi
4093dc3a5f1Sandi  $conn = @ftp_connect($conf['ftp']['host'],$conf['ftp']['port'],10);
4103dc3a5f1Sandi  if(!$conn){
4113dc3a5f1Sandi    msg("FTP connection failed",-1);
4123dc3a5f1Sandi    return false;
4133dc3a5f1Sandi  }
4143dc3a5f1Sandi
4153dc3a5f1Sandi  if(!@ftp_login($conn, $conf['ftp']['user'], $conf['ftp']['pass'])){
4163dc3a5f1Sandi    msg("FTP login failed",-1);
4173dc3a5f1Sandi    return false;
4183dc3a5f1Sandi  }
4193dc3a5f1Sandi
4203dc3a5f1Sandi  //create directory
421034138e2SRainer Weinhold  $ok = @ftp_mkdir($conn, $dir);
4221ca31cfeSAndreas Gohr  //set permissions
4231ca31cfeSAndreas Gohr  @ftp_site($conn,sprintf("CHMOD %04o %s",$conf['dmode'],$dir));
4243dc3a5f1Sandi
425034138e2SRainer Weinhold  @ftp_close($conn);
4263dc3a5f1Sandi  return $ok;
4273dc3a5f1Sandi}
4283dc3a5f1Sandi
4293dc3a5f1Sandi/**
43073ccfcb9Schris * downloads a file from the net and saves it
43173ccfcb9Schris *
43273ccfcb9Schris * if $useAttachment is false,
43373ccfcb9Schris * - $file is the full filename to save the file, incl. path
43473ccfcb9Schris * - if successful will return true, false otherwise
43573ccfcb9Schris
43673ccfcb9Schris * if $useAttachment is true,
43773ccfcb9Schris * - $file is the directory where the file should be saved
43873ccfcb9Schris * - if successful will return the name used for the saved file, false otherwise
439b625487dSandi *
440b625487dSandi * @author Andreas Gohr <andi@splitbrain.org>
44173ccfcb9Schris * @author Chris Smith <chris@jalakai.co.uk>
442b625487dSandi */
443847b8298SAndreas Gohrfunction io_download($url,$file,$useAttachment=false,$defaultName='',$maxSize=2097152){
444ac9115b0STroels Liebe Bentsen  global $conf;
4459b307a83SAndreas Gohr  $http = new DokuHTTPClient();
446847b8298SAndreas Gohr  $http->max_bodysize = $maxSize;
4479b307a83SAndreas Gohr  $http->timeout = 25; //max. 25 sec
4489b307a83SAndreas Gohr
4499b307a83SAndreas Gohr  $data = $http->get($url);
4509b307a83SAndreas Gohr  if(!$data) return false;
4519b307a83SAndreas Gohr
45273ccfcb9Schris  if ($useAttachment) {
45373ccfcb9Schris    $name = '';
45473ccfcb9Schris      if (isset($http->resp_headers['content-disposition'])) {
45573ccfcb9Schris      $content_disposition = $http->resp_headers['content-disposition'];
456ce070a9fSchris      $match=array();
45773ccfcb9Schris      if (is_string($content_disposition) &&
458ce070a9fSchris          preg_match('/attachment;\s*filename\s*=\s*"([^"]*)"/i', $content_disposition, $match)) {
45973ccfcb9Schris
46073ccfcb9Schris          $name = basename($match[1]);
46173ccfcb9Schris      }
46273ccfcb9Schris
46373ccfcb9Schris    }
46473ccfcb9Schris
46573ccfcb9Schris    if (!$name) {
46673ccfcb9Schris        if (!$defaultName) return false;
46773ccfcb9Schris        $name = $defaultName;
46873ccfcb9Schris    }
46973ccfcb9Schris
47073ccfcb9Schris    $file = $file.$name;
47173ccfcb9Schris  }
47273ccfcb9Schris
473d8186216SBen Coburn  $fileexists = @file_exists($file);
4749b307a83SAndreas Gohr  $fp = @fopen($file,"w");
475b625487dSandi  if(!$fp) return false;
4769b307a83SAndreas Gohr  fwrite($fp,$data);
477b625487dSandi  fclose($fp);
4781ca31cfeSAndreas Gohr  if(!$fileexists and $conf['fperm']) chmod($file, $conf['fperm']);
47973ccfcb9Schris  if ($useAttachment) return $name;
480b625487dSandi  return true;
481b625487dSandi}
482b625487dSandi
483b625487dSandi/**
484ac9115b0STroels Liebe Bentsen * Windows compatible rename
485bf5e5a5bSAndreas Gohr *
486bf5e5a5bSAndreas Gohr * rename() can not overwrite existing files on Windows
487bf5e5a5bSAndreas Gohr * this function will use copy/unlink instead
488bf5e5a5bSAndreas Gohr */
489bf5e5a5bSAndreas Gohrfunction io_rename($from,$to){
490ac9115b0STroels Liebe Bentsen  global $conf;
491bf5e5a5bSAndreas Gohr  if(!@rename($from,$to)){
492bf5e5a5bSAndreas Gohr    if(@copy($from,$to)){
493*8e0b019fSAndreas Gohr      if($conf['fperm']) chmod($to, $conf['fperm']);
494bf5e5a5bSAndreas Gohr      @unlink($from);
495bf5e5a5bSAndreas Gohr      return true;
496bf5e5a5bSAndreas Gohr    }
497bf5e5a5bSAndreas Gohr    return false;
498bf5e5a5bSAndreas Gohr  }
499bf5e5a5bSAndreas Gohr  return true;
500bf5e5a5bSAndreas Gohr}
501bf5e5a5bSAndreas Gohr
502bf5e5a5bSAndreas Gohr
503bf5e5a5bSAndreas Gohr/**
504f3f0262cSandi * Runs an external command and returns it's output as string
50515fae107Sandi *
50615fae107Sandi * @author Harry Brueckner <harry_b@eml.cc>
50715fae107Sandi * @author Andreas Gohr <andi@splitbrain.org>
5083dc3a5f1Sandi * @deprecated
509f3f0262cSandi */
510f3f0262cSandifunction io_runcmd($cmd){
511f3f0262cSandi  $fh = popen($cmd, "r");
512f3f0262cSandi  if(!$fh) return false;
513f3f0262cSandi  $ret = '';
514f3f0262cSandi  while (!feof($fh)) {
515f3f0262cSandi    $ret .= fread($fh, 8192);
516f3f0262cSandi  }
517f3f0262cSandi  pclose($fh);
518f3f0262cSandi  return $ret;
519f3f0262cSandi}
520f3f0262cSandi
5217421c3ccSAndreas Gohr/**
5227421c3ccSAndreas Gohr * Search a file for matching lines
5237421c3ccSAndreas Gohr *
5247421c3ccSAndreas Gohr * This is probably not faster than file()+preg_grep() but less
5257421c3ccSAndreas Gohr * memory intensive because not the whole file needs to be loaded
5267421c3ccSAndreas Gohr * at once.
5277421c3ccSAndreas Gohr *
5287421c3ccSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org>
5297421c3ccSAndreas Gohr * @param  string $file    The file to search
5307421c3ccSAndreas Gohr * @param  string $pattern PCRE pattern
5317421c3ccSAndreas Gohr * @param  int    $max     How many lines to return (0 for all)
5327421c3ccSAndreas Gohr * @param  bool   $baxkref When true returns array with backreferences instead of lines
5337421c3ccSAndreas Gohr * @return matching lines or backref, false on error
5347421c3ccSAndreas Gohr */
5357421c3ccSAndreas Gohrfunction io_grep($file,$pattern,$max=0,$backref=false){
5367421c3ccSAndreas Gohr  $fh = @fopen($file,'r');
5377421c3ccSAndreas Gohr  if(!$fh) return false;
5387421c3ccSAndreas Gohr  $matches = array();
5397421c3ccSAndreas Gohr
5407421c3ccSAndreas Gohr  $cnt  = 0;
5417421c3ccSAndreas Gohr  $line = '';
5427421c3ccSAndreas Gohr  while (!feof($fh)) {
5437421c3ccSAndreas Gohr    $line .= fgets($fh, 4096);  // read full line
5447421c3ccSAndreas Gohr    if(substr($line,-1) != "\n") continue;
5457421c3ccSAndreas Gohr
5467421c3ccSAndreas Gohr    // check if line matches
5477421c3ccSAndreas Gohr    if(preg_match($pattern,$line,$match)){
5487421c3ccSAndreas Gohr      if($backref){
5497421c3ccSAndreas Gohr        $matches[] = $match;
5507421c3ccSAndreas Gohr      }else{
5517421c3ccSAndreas Gohr        $matches[] = $line;
5527421c3ccSAndreas Gohr      }
5537421c3ccSAndreas Gohr      $cnt++;
5547421c3ccSAndreas Gohr    }
5557421c3ccSAndreas Gohr    if($max && $max == $cnt) break;
5567421c3ccSAndreas Gohr    $line = '';
5577421c3ccSAndreas Gohr  }
5587421c3ccSAndreas Gohr  fclose($fh);
5597421c3ccSAndreas Gohr  return $matches;
5607421c3ccSAndreas Gohr}
5617421c3ccSAndreas Gohr
562340756e4Sandi//Setup VIM: ex: et ts=2 enc=utf-8 :
563