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