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