| [ Index ] |
PHP Cross Reference of Limb3 |
[Summary view] [Print] [Text view]
1 <?php 2 /* 3 * Limb PHP Framework 4 * 5 * @link http://limb-project.com 6 * @copyright Copyright © 2004-2007 BIT(http://bit-creative.com) 7 * @license LGPL http://www.gnu.org/copyleft/lesser.html 8 */ 9 lmb_require('limb/core/src/lmbSys.class.php'); 10 lmb_require('limb/fs/src/exception/lmbFsException.class.php'); 11 12 /** 13 * class lmbFs. 14 * 15 * @package fs 16 * @version $Id$ 17 */ 18 class lmbFs 19 { 20 const LOCAL = 1; 21 const UNIX = 2; 22 const DOS = 3; 23 const WIN32_NET_PREFIX = '\\\\'; 24 25 static function safeWrite($file, $content, $perm=0664) 26 { 27 self :: mkdir(dirname($file)); 28 29 $tmp = self :: generateTmpFile('_'); 30 $fh = fopen($tmp, 'w'); 31 32 if($fh === false) 33 { 34 @unlink($tmp); 35 throw new lmbFsException('could not open file for writing', array('file' => $file)); 36 } 37 38 //just for safety 39 @flock($fh, LOCK_EX); 40 fwrite($fh, $content); 41 @flock($fh, LOCK_UN); 42 fclose($fh); 43 44 if(lmbSys :: isWin32() && file_exists($file)) 45 @unlink($file); 46 47 if(!@rename($tmp, $file)) 48 { 49 @unlink($tmp); 50 throw new lmbFsException('could not move file', array('src' => $tmp, 'file' => $file)); 51 } 52 53 @chmod($file, $perm); 54 if(file_exists($tmp)) 55 @unlink($tmp); 56 } 57 58 static function getTmpDir() 59 { 60 if(defined('LIMB_VAR_DIR')) 61 return LIMB_VAR_DIR; 62 63 if($path = session_save_path()) 64 { 65 if(($pos = strpos($path, ';')) !== false) 66 $path = substr($path, $pos+1); 67 return $path; 68 } 69 70 if($tmp = getenv('TMP') || $tmp = getenv('TEMP') || $tmp = getenv('TMPDIR')) 71 return $tmp; 72 73 //gracefull falback? 74 return '/tmp'; 75 } 76 77 static function generateTmpFile($prefix = 'p') 78 { 79 return tempnam(self :: getTmpDir(), $prefix); 80 } 81 82 /** 83 * @deprecated 84 */ 85 static function generateTempFile($prefix = 'p') 86 { 87 return self :: generateTmpFile($prefix); 88 } 89 90 static function dirpath($path) 91 { 92 $path = self :: normalizePath($path); 93 94 if(($dir_pos = strrpos($path, self :: separator())) !== false ) 95 return substr($path, 0, $dir_pos); 96 97 return $path; 98 } 99 100 /** 101 * Creates the directory $dir with permissions $perm. 102 * If $parents is true it will create any missing parent directories, 103 * just like 'mkdir -p'. 104 */ 105 static function mkdir($dir, $perm=0777, $parents=true) 106 { 107 if(is_dir($dir)) 108 return; 109 110 $dir = self :: normalizePath($dir); 111 112 if(!$parents) 113 { 114 self :: _doMkdir($dir, $perm); 115 return; 116 } 117 118 $separator = self :: separator(); 119 $path_elements = self :: explodePath($dir); 120 121 if(count($path_elements) == 0) 122 return; 123 124 $index = self :: _getFirstExistingPathIndex($path_elements, $separator); 125 126 if($index === false) 127 { 128 throw new lmbFsException('cant find first existent path', array('dir' => $dir)); 129 } 130 131 $offset_path = ''; 132 for($i=0; $i < $index; $i++) 133 { 134 $offset_path .= $path_elements[$i] . $separator; 135 } 136 137 for($i=$index; $i < count($path_elements); $i++) 138 { 139 $offset_path .= $path_elements[$i] . $separator; 140 self :: _doMkdir($offset_path, $perm); 141 } 142 } 143 144 protected static function _getFirstExistingPathIndex($path_elements, $separator) 145 { 146 for($i=count($path_elements); $i > 0; $i--) 147 { 148 $path = implode($separator, $path_elements); 149 150 if(is_dir($path)) 151 return $i; 152 153 array_pop($path_elements); 154 } 155 156 if(self :: isPathAbsolute($path)) 157 return false; 158 else 159 return 0; 160 } 161 162 /** 163 * Creates the directory $dir with permission $perm. 164 */ 165 protected static function _doMkdir($dir, $perm) 166 { 167 if(is_dir($dir)) 168 return; 169 170 if(self :: _hasWin32NetPrefix($dir)) 171 return; 172 173 $oldumask = umask(0); 174 if(!mkdir($dir, $perm)) 175 { 176 umask($oldumask); 177 throw new lmbFsException('failed to create directory', array('dir' => $dir)); 178 } 179 180 umask($oldumask); 181 } 182 183 static function explodePath($path, $fs_type = self :: UNIX) 184 { 185 $path = self :: normalizePath($path, $fs_type); 186 $separator = self :: separator($fs_type); 187 188 $dir_elements = explode($separator, $path); 189 190 if(sizeof($dir_elements) > 1 && $dir_elements[sizeof($dir_elements)-1] === '') 191 array_pop($dir_elements); 192 193 if(self :: _hasWin32NetPrefix($path)) 194 { 195 array_shift($dir_elements); 196 array_shift($dir_elements); 197 $dir_elements[0] = self :: WIN32_NET_PREFIX . $dir_elements[0]; 198 } 199 return $dir_elements; 200 } 201 202 static function joinPath($arr, $fs_type = self :: UNIX) 203 { 204 return implode(self :: separator($fs_type), $arr); 205 } 206 207 static function chop($path) 208 { 209 if(substr($path, -1) == '/' || substr($path, -1) == '\\') 210 $path = substr($path, 0, -1); 211 212 return $path; 213 } 214 215 static function rm($file) 216 { 217 if(!file_exists($file)) 218 return false; 219 220 self :: _doRm(self :: normalizePath($file), self :: separator()); 221 clearstatcache(); 222 223 return true; 224 } 225 226 protected static function _doRm($item, $separator) 227 { 228 if(!is_dir($item)) 229 { 230 if(!@unlink($item)) 231 throw new lmbFsException('failed to remove file', array('file' => $item)); 232 return; 233 } 234 235 if(!$handle = @opendir($item)) 236 throw new lmbFsException('failed to open directory', array('dir' => $item)); 237 238 while(($file = readdir($handle)) !== false) 239 { 240 if($file == '.' || $file == '..') 241 continue; 242 243 self :: _doRm($item . $separator . $file, $separator); 244 } 245 246 closedir($handle); 247 248 if(!@rmdir($item)) 249 throw new lmbFsException('failed to remove directory', array('dir' => $item)); 250 } 251 252 static function mv($src, $dest) 253 { 254 if(is_dir($src) || is_file($src)) 255 { 256 if(!@rename($src, $dest)) 257 throw new lmbFsException('failed to move item', array('src' => $src, 'dest' => $dest)); 258 259 clearstatcache(); 260 } 261 else 262 throw new lmbFsException('source file or directory does not exist', array('src' => $src)); 263 } 264 265 static function cp($src, $dest, $exclude_regex = '', $include_regex = '', $as_child = false, $include_hidden = true) 266 { 267 if(!is_dir($src)) 268 { 269 if(!is_dir($dest)) 270 self :: mkdir(dirname($dest)); 271 else 272 $dest = $dest . '/' . basename($src); 273 274 if(@copy($src, $dest) === false) 275 throw new lmbFsException('failed to copy file', array('src' => $src, 'dest' => $dest)); 276 return; 277 } 278 279 self :: mkdir($dest); 280 281 $src = self :: normalizePath($src); 282 $dest = self :: normalizePath($dest); 283 $separator = self :: separator(); 284 285 if($as_child) 286 { 287 $separator_regex = preg_quote($separator); 288 if(preg_match( "#^.+{$separator_regex}([^{$separator_regex}]+)$#", $src, $matches)) 289 { 290 self :: _doMkdir($dest . $separator . $matches[1], 0777); 291 $dest .= $separator . $matches[1]; 292 } 293 else 294 return false; 295 } 296 $items = self :: find($src, 'df', $include_regex, $exclude_regex, false, $include_hidden); 297 298 $total_items = $items; 299 while(count($items) > 0) 300 { 301 $current_items = $items; 302 $items = array(); 303 foreach($current_items as $item) 304 { 305 $full_path = $src . $separator . $item; 306 if(is_file( $full_path)) 307 copy($full_path, $dest . $separator . $item); 308 elseif(is_dir( $full_path)) 309 { 310 self :: _doMkdir($dest . $separator . $item, 0777); 311 312 $new_items = self :: find($full_path, 'df', $include_regex, $exclude_regex, $item, $include_hidden); 313 314 $items = array_merge($items, $new_items); 315 $total_items = array_merge($total_items, $new_items); 316 317 unset($new_items); 318 } 319 } 320 } 321 if($total_items) 322 clearstatcache(); 323 324 return $total_items; 325 } 326 327 static function ls($path) 328 { 329 if(!is_dir($path)) 330 return array(); 331 332 $files = array(); 333 $path = self :: normalizePath($path); 334 if($handle = opendir($path)) 335 { 336 while(($file = readdir($handle)) !== false) 337 { 338 if($file != '.' && $file != '..' ) 339 { 340 $files[] = $file; 341 } 342 } 343 closedir($handle); 344 } 345 return $files; 346 } 347 348 /** 349 * Return the separator used between directories and files according to $type. 350 */ 351 static function separator($type = lmbFs :: UNIX) 352 { 353 switch(self :: _concreteSeparatorType($type)) 354 { 355 case self :: UNIX: 356 return '/'; 357 case self :: DOS: 358 return "\\"; 359 } 360 } 361 362 protected static function _concreteSeparatorType($type) 363 { 364 if($type == self :: LOCAL) 365 { 366 if(lmbSys :: isWin32()) 367 $type = self :: DOS; 368 else 369 $type = lmbFs :: UNIX; 370 } 371 return $type; 372 } 373 374 /** 375 * Converts any directory separators found in $path, in both unix and dos style, into 376 * the separator type specified by $to_type and returns it. 377 */ 378 static function convertSeparators($path, $to_type = self :: UNIX) 379 { 380 $separator = self :: separator($to_type); 381 return preg_replace("#[/\\\\]#", $separator, $path); 382 } 383 384 /** 385 * Removes all unneeded directory separators and resolves any "."s and ".."s found in $path. 386 * 387 * For instance: "var/../lib/db" becomes "lib/db", while "../site/var" will not be changed. 388 * Will also convert separators 389 */ 390 static function normalizePath($path, $to_type = self :: UNIX) 391 { 392 $path = self :: convertSeparators($path, $to_type); 393 $separator = self :: separator($to_type); 394 395 $path = self :: _normalizeSeparators($path, $separator); 396 397 $path_elements= explode($separator, $path); 398 $newpath_elements= array(); 399 400 foreach($path_elements as $path_element) 401 { 402 if($path_element == '.') 403 continue; 404 if($path_element == '..' && 405 count($newpath_elements) > 0) 406 array_pop($newpath_elements); 407 else 408 $newpath_elements[] = $path_element; 409 } 410 if(count( $newpath_elements) == 0) 411 $newpath_elements[] = '.'; 412 413 $path = implode($separator, $newpath_elements); 414 return rtrim($path, '/\\'); 415 } 416 417 static function isPathRelative($path, $fs_type = self :: LOCAL) 418 { 419 return !self :: isPathAbsolute($path, $os_type); 420 } 421 422 static function isPathAbsolute($path, $fs_type = self :: LOCAL) 423 { 424 switch(self :: _concreteSeparatorType($fs_type)) 425 { 426 case self :: UNIX: 427 return $path{0} == '/'; 428 case self :: DOS: 429 return $path{0} == '/' || 430 $path{0} == "\\" || 431 preg_match('~^[a-zA-Z]+:~', $path); 432 } 433 } 434 435 protected static function _normalizeSeparators($path, $separator) 436 { 437 $quoted = preg_quote($separator); 438 $clean_path = preg_replace( "~$quoted$quoted+~", $separator, $path); 439 440 if(self :: _hasWin32NetPrefix($path)) 441 $clean_path = '\\' . $clean_path; 442 443 return $clean_path; 444 } 445 446 protected static function _hasWin32NetPrefix($path)//ugly!!! 447 { 448 if(lmbSys :: isWin32() && strlen($path) > 2) 449 { 450 return (substr($path, 0, 2) == self :: WIN32_NET_PREFIX); 451 } 452 return false; 453 } 454 455 static function path($names, $include_end_separator=false, $type = self :: UNIX) 456 { 457 $separator = self :: separator($type); 458 $path = implode($separator, $names); 459 $path = self :: normalizePath($path, $type); 460 461 $has_end_separator = (strlen($path) > 0 && $path[strlen($path) - 1] == $separator); 462 463 if($include_end_separator && !$has_end_separator) 464 $path .= $separator; 465 elseif (!$include_end_separator && $has_end_separator) 466 $path = substr($path, 0, strlen($path) - 1); 467 468 return $path; 469 } 470 471 static function find($dir, $types = 'dfl', $include_regex = '', $exclude_regex = '', $add_path = true, $include_hidden = false) 472 { 473 $dir = self :: normalizePath($dir); 474 $dir = self :: chop($dir); 475 476 $items = array(); 477 478 $separator = self :: separator(); 479 480 if($handle = @opendir($dir)) 481 { 482 while(($element = readdir($handle)) !== false) 483 { 484 if($element == '.' || $element == '..') 485 continue; 486 if(!$include_hidden && $element[0] == '.') 487 continue; 488 if($include_regex && !preg_match($include_regex, $element, $m)) 489 continue; 490 if($exclude_regex && preg_match(