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