|
eZ Publish
[4.0]
|
00001 <?php 00002 // 00003 // Definition of eZDir class 00004 // 00005 // Created on: <02-Jul-2002 15:33:41 sp> 00006 // 00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00008 // SOFTWARE NAME: eZ Publish 00009 // SOFTWARE RELEASE: 4.0.x 00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS 00011 // SOFTWARE LICENSE: GNU General Public License v2.0 00012 // NOTICE: > 00013 // This program is free software; you can redistribute it and/or 00014 // modify it under the terms of version 2.0 of the GNU General 00015 // Public License as published by the Free Software Foundation. 00016 // 00017 // This program is distributed in the hope that it will be useful, 00018 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 // GNU General Public License for more details. 00021 // 00022 // You should have received a copy of version 2.0 of the GNU General 00023 // Public License along with this program; if not, write to the Free 00024 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 00025 // MA 02110-1301, USA. 00026 // 00027 // 00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00029 // 00030 00031 /*! \file ezdir.php 00032 */ 00033 00034 /*! 00035 \class eZDir ezdir.php 00036 \brief The class eZDir does 00037 00038 */ 00039 //include_once( "lib/ezutils/classes/ezini.php" ); 00040 //include_once( "lib/ezutils/classes/ezsys.php" ); 00041 00042 class eZDir 00043 { 00044 const SEPARATOR_LOCAL = 1; 00045 const SEPARATOR_UNIX = 2; 00046 const SEPARATOR_DOS = 3; 00047 00048 /*! 00049 \return a multi-level path from a specific key. For example: 00050 \code 00051 echo createMultiLevelPath( "42abce", 3 ); 00052 \endcode 00053 returns "/4/2/abce" 00054 00055 Parameters: 00056 $key: the key to be used as path 00057 $maxDepth: the maximum number of path elements to be created (-1 is unlimited) 00058 \static 00059 */ 00060 static function createMultiLevelPath( $key, $maxDepth = -1 ) 00061 { 00062 $parts = preg_split("//", (string) $key, $maxDepth, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); 00063 $sep = eZDir::separator( self::SEPARATOR_LOCAL ); 00064 return $sep . join($sep, $parts); 00065 } 00066 00067 static function getPathFromFilename( $filename ) 00068 { 00069 $ini = eZINI::instance(); 00070 $dirDepth = $ini->variable( "FileSettings" , "DirDepth" ); 00071 $pathArray = array(); 00072 for ( $i = 0; $i < $dirDepth and $i < strlen( $filename ); $i++ ) 00073 { 00074 $pathArray[] = substr( $filename, $i, 1 ); 00075 } 00076 $path = implode( '/', $pathArray ); 00077 00078 return $path; 00079 } 00080 00081 static function filenamePath( $filename, $maxCharLen = 2 ) 00082 { 00083 $path = ''; 00084 for ( $i = 0; $i < strlen( $filename ) and ( strlen( $filename ) - $i ) > $maxCharLen; 00085 $i++ ) 00086 { 00087 $path = $path . substr( $filename, $i, 1 ) . '/'; 00088 } 00089 00090 return $path; 00091 } 00092 00093 /*! 00094 \static 00095 Creates the directory \a $dir with permissions \a $perm. 00096 If \a $parents is true it will create any missing parent directories, 00097 just like 'mkdir -p'. 00098 */ 00099 static function mkdir( $dir, $perm = false, $parents = false ) 00100 { 00101 if ( $perm === false ) 00102 { 00103 $perm = eZDir::directoryPermission(); 00104 } 00105 $dir = eZDir::cleanPath( $dir, self::SEPARATOR_UNIX ); 00106 if ( !$parents ) 00107 return eZDir::doMkdir( $dir, $perm ); 00108 else 00109 { 00110 $dirElements = explode( '/', $dir ); 00111 if ( count( $dirElements ) == 0 ) 00112 return true; 00113 $currentDir = $dirElements[0]; 00114 $result = true; 00115 if ( !file_exists( $currentDir ) and $currentDir != "" ) 00116 $result = eZDir::doMkdir( $currentDir, $perm ); 00117 if ( !$result ) 00118 return false; 00119 00120 for ( $i = 1; $i < count( $dirElements ); ++$i ) 00121 { 00122 $dirElement = $dirElements[$i]; 00123 if ( strlen( $dirElement ) == 0 ) 00124 continue; 00125 $currentDir .= '/' . $dirElement; 00126 $result = true; 00127 if ( !file_exists( $currentDir ) ) 00128 $result = eZDir::doMkdir( $currentDir, $perm ); 00129 if ( !$result ) 00130 return false; 00131 } 00132 return true; 00133 } 00134 } 00135 00136 /*! 00137 \static 00138 Goes trough the directory path \a $dir and removes empty directories. 00139 \note This is just the opposite of mkdir() with \a $parents set to \c true. 00140 */ 00141 static function cleanupEmptyDirectories( $dir ) 00142 { 00143 $dir = eZDir::cleanPath( $dir, self::SEPARATOR_UNIX ); 00144 $dirElements = explode( '/', $dir ); 00145 if ( count( $dirElements ) == 0 ) 00146 return true; 00147 $currentDir = $dirElements[0]; 00148 $result = true; 00149 if ( !file_exists( $currentDir ) and $currentDir != "" ) 00150 $result = eZDir::doMkdir( $currentDir, $perm ); 00151 if ( !$result ) 00152 return false; 00153 00154 for ( $i = count( $dirElements ); $i > 0; --$i ) 00155 { 00156 $dirpath = implode( '/', array_slice( $dirElements, 0, $i ) ); 00157 if ( file_exists( $dirpath ) and 00158 is_dir( $dirpath ) ) 00159 { 00160 $rmdirStatus = @rmdir( $dirpath ); 00161 if ( !$rmdirStatus ) 00162 return true; 00163 } 00164 } 00165 return true; 00166 } 00167 00168 /*! 00169 \return the dirpath portion of the filepath \a $filepath. 00170 \code 00171 $dirpath = eZDir::dirpath( "path/to/some/file.txt" ); 00172 print( $dirpath ); // prints out path/to/some 00173 \endcode 00174 */ 00175 static function dirpath( $filepath ) 00176 { 00177 $filepath = eZDir::cleanPath( $filepath, self::SEPARATOR_UNIX ); 00178 $dirPosition = strrpos( $filepath, '/' ); 00179 if ( $dirPosition !== false ) 00180 return substr( $filepath, 0, $dirPosition ); 00181 return $filepath; 00182 } 00183 00184 /*! 00185 \return the default permissions to use for directories. 00186 \note The permission is converted from octal text to decimal value. 00187 */ 00188 static function directoryPermission() 00189 { 00190 return octdec( eZINI::instance()->variable( 'FileSettings', 'StorageDirPermissions' ) ); 00191 } 00192 00193 /*! 00194 \static 00195 \private 00196 Creates the directory \a $dir with permission \a $perm. 00197 */ 00198 static function doMkdir( $dir, $perm ) 00199 { 00200 //include_once( "lib/ezutils/classes/ezdebugsetting.php" ); 00201 00202 $oldumask = umask( 0 ); 00203 if ( ! @mkdir( $dir, $perm ) ) 00204 { 00205 umask( $oldumask ); 00206 // eZDebug::writeError( "Couldn't create the directory \"$dir\".", "eZDir::doMkdir()" ); 00207 return false; 00208 } 00209 umask( $oldumask ); 00210 00211 return true; 00212 } 00213 00214 /*! 00215 \static 00216 \return the separator used between directories and files according to \a $type. 00217 00218 Type can be one of the following: 00219 - self::SEPARATOR_LOCAL - Returns whatever is applicable for the current machine. 00220 - self::SEPARATOR_UNIX - Returns a / 00221 - self::SEPARATOR_DOS - Returns a \ 00222 */ 00223 static function separator( $type ) 00224 { 00225 switch ( $type ) 00226 { 00227 case self::SEPARATOR_LOCAL: 00228 return eZSys::fileSeparator(); 00229 case self::SEPARATOR_UNIX: 00230 return '/'; 00231 case self::SEPARATOR_DOS: 00232 return "\\"; 00233 } 00234 return null; 00235 } 00236 00237 /*! 00238 \static 00239 Converts any directory separators found in \a $path, in both unix and dos style, into 00240 the separator type specified by \a $toType and returns it. 00241 */ 00242 static function convertSeparators( $path, $toType = self::SEPARATOR_UNIX ) 00243 { 00244 $separator = eZDir::separator( $toType ); 00245 return str_replace( array( '/', '\\' ), $separator, $path ); 00246 } 00247 00248 /*! 00249 \static 00250 Removes all unneeded directory separators and resolves any "."s and ".."s found in \a $path. 00251 00252 For instance: "var/../lib/ezdb" becomes "lib/ezdb", while "../site/var" will not be changed. 00253 \note Will also convert separators 00254 \sa convertSeparators. 00255 */ 00256 static function cleanPath( $path, $toType = self::SEPARATOR_UNIX ) 00257 { 00258 $path = eZDir::convertSeparators( $path, $toType ); 00259 $separator = eZDir::separator( $toType ); 00260 $path = preg_replace( "#$separator{2,}#", $separator, $path ); 00261 $pathElements = explode( $separator, $path ); 00262 $newPathElements = array(); 00263 foreach ( $pathElements as $pathElement ) 00264 { 00265 if ( $pathElement == '.' ) 00266 continue; 00267 if ( $pathElement == '..' and 00268 count( $newPathElements ) > 0 ) 00269 array_pop( $newPathElements ); 00270 else 00271 $newPathElements[] = $pathElement; 00272 } 00273 if ( count( $newPathElements ) == 0 ) 00274 $newPathElements[] = '.'; 00275 $path = implode( $separator, $newPathElements ); 00276 return $path; 00277 } 00278 00279 /*! 00280 \static 00281 Creates a path out of all the dir and file items in the array \a $names 00282 with correct separators in between them. 00283 It will also remove unneeded separators. 00284 \a $type is used to determine the separator type, see eZDir::separator. 00285 If \a $includeEndSeparator is true then it will make sure that the path ends with a 00286 separator if false it make sure there are no end separator. 00287 */ 00288 static function path( $names, $includeEndSeparator = false, $type = self::SEPARATOR_UNIX ) 00289 { 00290 $separator = eZDir::separator( $type ); 00291 $path = implode( $separator, $names ); 00292 $path = eZDir::cleanPath( $path, $type ); 00293 $pathLen = strlen( $path ); 00294 $hasEndSeparator = ( $pathLen > 0 and 00295 $path[$pathLen - 1] == $separator ); 00296 if ( $includeEndSeparator and 00297 !$hasEndSeparator ) 00298 $path .= $separator; 00299 else if ( !$includeEndSeparator and 00300 $hasEndSeparator ) 00301 $path = substr( $path, 0, $pathLen - 1 ); 00302 return $path; 00303 } 00304 00305 00306 /*! 00307 \static 00308 Removes the directory and all it's contents, recursive. 00309 */ 00310 static function recursiveDelete( $dir ) 00311 { 00312 if ( $handle = @opendir( $dir ) ) 00313 { 00314 while ( ( $file = readdir( $handle ) ) !== false ) 00315 { 00316 if ( ( $file == "." ) || ( $file == ".." ) ) 00317 { 00318 continue; 00319 } 00320 if ( is_dir( $dir . '/' . $file ) ) 00321 { 00322 eZDir::recursiveDelete( $dir . '/' . $file ); 00323 } 00324 else 00325 { 00326 unlink( $dir . '/' . $file ); 00327 } 00328 } 00329 @closedir( $handle ); 00330 rmdir( $dir ); 00331 } 00332 } 00333 00334 /*! 00335 \static 00336 Creates a list of all files and dirs in the directory. 00337 */ 00338 static function recursiveList( $dir, $path, &$fileList ) 00339 { 00340 if ( $handle = @opendir( $dir ) ) 00341 { 00342 while ( ( $file = readdir( $handle ) ) !== false ) 00343 { 00344 if ( ( $file == "." ) || ( $file == ".." ) ) 00345 { 00346 continue; 00347 } 00348 if ( is_dir( $dir . '/' . $file ) ) 00349 { 00350 $fileList[] = array( 'path' => $path, 'name' => $file, 'type' => 'dir' ); 00351 eZDir::recursiveList( $dir . '/' . $file, $path . '/' . $file, $fileList ); 00352 } 00353 else 00354 { 00355 $fileList[] = array( 'path' => $path, 'name' => $file, 'type' => 'file' ); 00356 } 00357 } 00358 @closedir( $handle ); 00359 } 00360 } 00361 00362 /*! 00363 \static 00364 Recurses through the directory and returns the files that matches the given suffix 00365 \note This function will not traverse . (hidden) folders 00366 */ 00367 static function recursiveFind( $dir, $suffix ) 00368 { 00369 $returnFiles = array(); 00370 if ( $handle = @opendir( $dir ) ) 00371 { 00372 while ( ( $file = readdir( $handle ) ) !== false ) 00373 { 00374 if ( ( $file == "." ) || ( $file == ".." ) ) 00375 { 00376 continue; 00377 } 00378 if ( is_dir( $dir . '/' . $file ) ) 00379 { 00380 if ( $file[0] != "." ) 00381 { 00382 $files = eZDir::recursiveFind( $dir . '/' . $file, $suffix ); 00383 $returnFiles = array_merge( $files, $returnFiles ); 00384 } 00385 } 00386 else 00387 { 00388 if ( preg_match( "/$suffix$/", $file ) ) 00389 $returnFiles[] = $dir . '/' . $file; 00390 } 00391 } 00392 @closedir( $handle ); 00393 } 00394 return $returnFiles; 00395 } 00396 00397 /*! 00398 \static 00399 Unlink files match the given pattern in the given directory. 00400 */ 00401 static function unlinkWildcard( $dir, $pattern ) 00402 { 00403 $availableFiles = array(); 00404 if ( $handle = @opendir( $dir ) ) 00405 { 00406 while ( ( $file = readdir( $handle ) ) !== false ) 00407 { 00408 if ( $file != "." && $file != ".." ) 00409 { 00410 $availableFiles[] = $file; 00411 } 00412 } 00413 @closedir( $handle ); 00414 00415 if( strpos( $pattern, "." ) ) 00416 { 00417 $baseexp = substr( $pattern, 0, strpos( $pattern, "." ) ); 00418 $typeexp = substr( $pattern, ( strpos( $pattern, "." ) + 1 ), strlen( $pattern ) ); 00419 } 00420 else 00421 { 00422 $baseexp = $pattern; 00423 $typeexp = ""; 00424 } 00425 00426 $baseexp=preg_quote( $baseexp ); 00427 $typeexp=preg_quote( $typeexp ); 00428 00429 $baseexp = str_replace( array( "\*", "\?" ), array( ".*", "." ), $baseexp ); 00430 $typeexp = str_replace(array( "\*", "\?" ), array( ".*", "." ), $typeexp ); 00431 00432 $i=0; 00433 $matchedFileArray = array(); 00434 foreach( $availableFiles as $file ) 00435 { 00436 $fileName = basename( $file ); 00437 00438 if( strpos( $fileName, "." ) ) 00439 { 00440 $base = substr( $fileName, 0, strpos( $fileName, ".")); 00441 $type = substr( $fileName, ( strpos( $fileName,"." ) + 1 ), strlen( $fileName ) ); 00442 } 00443 else 00444 { 00445 $base = $fileName; 00446 $type = ""; 00447 } 00448 00449 if( preg_match( "/^".$baseexp."$/i", $base ) && preg_match( "/^".$typeexp."$/i", $type ) ) 00450 { 00451 $matchedFileArray[$i] = $file; 00452 $i++; 00453 } 00454 } 00455 00456 foreach ( array_keys( $matchedFileArray ) as $key ) 00457 { 00458 $matchedFile =& $matchedFileArray[$key]; 00459 if ( substr( $dir,-1 ) == "/") 00460 { 00461 unlink( $dir.$matchedFile ); 00462 } 00463 else 00464 { 00465 unlink( $dir."/".$matchedFile ); 00466 } 00467 } 00468 } 00469 } 00470 00471 /*! 00472 \static 00473 Recurses through the directory and returns the files that matches the given suffix. 00474 This function will store the relative path from the given base only. 00475 Note: this function will not traverse . (hidden) folders 00476 */ 00477 static function recursiveFindRelative( $baseDir, $subDir, $suffix ) 00478 { 00479 $returnFiles = array(); 00480 $dir = $baseDir; 00481 if ( $subDir != "" ) 00482 { 00483 if ( $dir != '' ) 00484 $dir .= "/" . $subDir; 00485 else 00486 $dir .= $subDir; 00487 } 00488 if ( $handle = @opendir( $dir ) ) 00489 { 00490 while ( ( $file = readdir( $handle ) ) !== false ) 00491 { 00492 if ( ( $file == "." ) || ( $file == ".." ) ) 00493 { 00494 continue; 00495 } 00496 if ( is_dir( $dir . '/' . $file ) ) 00497 { 00498 if ( $file[0] != "." ) 00499 { 00500 $files = eZDir::recursiveFindRelative( $baseDir, $subDir . '/' . $file, $suffix ); 00501 $returnFiles = array_merge( $files, $returnFiles ); 00502 } 00503 } 00504 else 00505 { 00506 if ( preg_match( "/$suffix$/", $file ) ) 00507 $returnFiles[] = $subDir . '/' . $file; 00508 } 00509 } 00510 @closedir( $handle ); 00511 } 00512 return $returnFiles; 00513 } 00514 00515 /*! 00516 \static 00517 Returns all subdirectories in a folder 00518 */ 00519 static function findSubdirs( $dir, $includeHidden = false, $excludeItems = false ) 00520 { 00521 return eZDir::findSubitems( $dir, 'd', false, $includeHidden, $excludeItems ); 00522 } 00523 00524 /*! 00525 \static 00526 Returns all subdirectories in a folder 00527 */ 00528 static function findSubitems( $dir, $types = false, $fullPath = false, $includeHidden = false, $excludeItems = false ) 00529 { 00530 if ( !$types ) 00531 $types = 'dfl'; 00532 $dirArray = array(); 00533 if ( $handle = @opendir( $dir ) ) 00534 { 00535 while ( ( $element = readdir( $handle ) ) !== false ) 00536 { 00537 if ( $element == '.' or $element == '..' ) 00538 continue; 00539 if ( !$includeHidden and $element[0] == "." ) 00540 continue; 00541 if ( $excludeItems and preg_match( $excludeItems, $element ) ) 00542 continue; 00543 if ( @is_dir( $dir . '/' . $element ) and strpos( $types, 'd' ) === false ) 00544 continue; 00545 if ( @is_link( $dir . '/' . $element ) and strpos( $types, 'l' ) === false ) 00546 continue; 00547 if ( @is_file( $dir . '/' . $element ) and strpos( $types, 'f' ) === false ) 00548 continue; 00549 if ( $fullPath ) 00550 { 00551 if ( is_string( $fullPath ) ) 00552 $dirArray[] = $fullPath . '/' . $element; 00553 else 00554 $dirArray[] = $dir . '/' . $element; 00555 } 00556 else 00557 $dirArray[] = $element; 00558 } 00559 @closedir( $handle ); 00560 } 00561 return $dirArray; 00562 } 00563 00564 /*! 00565 Copies a directory (and optionally all it's subitems) to another directory. 00566 \param $sourceDirectory The source directory which should be copied, this location must exist. 00567 \param $destinationDirectory The location for the copied directory structure, this location must exist. 00568 This parameter will be modified if \a $asChild is \c true. 00569 \param If \c true then it will use last part of the \a $sourceDirectory as a sub-folder to \a $destinationDirectory. 00570 e.g. copying /etc/httpd to /var/ will create /var/httpd and place all folders/files under it. 00571 \param $recursive If \c true then it will copy folders/files recursively from folders found in \a $sourceDirectory. 00572 \param $includeHidden If \c true it will include files or folders beginning with a dot (.). 00573 \param $excludeItems A regular expression used to exclude files or folders in the subtree, use \c false for no exclusion. 00574 00575 \note The parameter \a $recursive is currently unused, it will always copy recursively. 00576 */ 00577 static function copy( $sourceDirectory, &$destinationDirectory, 00578 $asChild = true, $recursive = true, $includeHidden = false, $excludeItems = false ) 00579 { 00580 if ( !is_dir( $sourceDirectory ) ) 00581 { 00582 eZDebug::writeError( "Source $sourceDirectory is not a directory, cannot copy from it", 00583 'eZDir::copy' ); 00584 return false; 00585 } 00586 if ( !is_dir( $destinationDirectory ) ) 00587 { 00588 eZDebug::writeError( "Destination $destinationDirectory is not a directory, cannot copy to it", 00589 'eZDir::copy' ); 00590 return false; 00591 } 00592 if ( $asChild ) 00593 { 00594 if ( preg_match( "#^.+/([^/]+)$#", $sourceDirectory, $matches ) ) 00595 { 00596 eZDir::mkdir( $destinationDirectory . '/' . $matches[1], eZDir::directoryPermission(), false ); 00597 $destinationDirectory .= '/' . $matches[1]; 00598 } 00599 } 00600 $items = eZDir::findSubitems( $sourceDirectory, 'df', false, $includeHidden, $excludeItems ); 00601 $totalItems = $items; 00602 //include_once( 'lib/ezfile/classes/ezfilehandler.php' ); 00603 while ( count( $items ) > 0 ) 00604 { 00605 $currentItems = $items; 00606 $items = array(); 00607 foreach ( $currentItems as $item ) 00608 { 00609 $fullPath = $sourceDirectory . '/' . $item; 00610 if ( is_file( $fullPath ) ) 00611 eZFileHandler::copy( $fullPath, $destinationDirectory . '/' . $item ); 00612 else if ( is_dir( $fullPath ) ) 00613 { 00614 eZDir::mkdir( $destinationDirectory . '/' . $item, eZDir::directoryPermission(), false ); 00615 $newItems = eZDir::findSubitems( $fullPath, 'df', $item, $includeHidden, $excludeItems ); 00616 $items = array_merge( $items, $newItems ); 00617 $totalItems = array_merge( $totalItems, $newItems ); 00618 unset( $newItems ); 00619 } 00620 } 00621 } 00622 // eZDebugSetting::writeNotice( 'lib-ezfile-copy', 00623 // "Copied directory $sourceDirectory to destination $destinationDirectory", 00624 // 'eZDir::copy' ); 00625 return $totalItems; 00626 } 00627 00628 /*! 00629 \return a regexp which will match certain temporary files. 00630 */ 00631 static function temporaryFileRegexp( $standalone = true ) 00632 { 00633 $preg = ''; 00634 if ( $standalone ) 00635 $preg .= "/^"; 00636 $preg .= "(.*~|#.+#|.*\.bak|.svn|CVS|.revive.el|.cvsignore)"; 00637 if ( $standalone ) 00638 $preg .= "$/"; 00639 return $preg; 00640 } 00641 00642 /*! 00643 \static 00644 Check if a given directory is writeable 00645 00646 \return TRUE/FALSE 00647 */ 00648 static function isWriteable( $dirname ) 00649 { 00650 if ( eZSys::osType() != 'win32' ) 00651 return is_writable( $dirname ); 00652 00653 /* PHP function is_writable() doesn't work correctly on Windows NT descendants. 00654 * So we have to use the following hack on those OSes. 00655 * FIXME: maybe on Win9x we shouldn't do this? 00656 */ 00657 $tmpfname = $dirname . eZSys::fileSeparator() . "ezsetup_" . md5( microtime() ) . ".tmp"; 00658 00659 // try to create temporary file 00660 if ( !( $fp = @fopen( $tmpfname, "w" ) ) ) 00661 return FALSE; 00662 00663 fclose( $fp ); 00664 unlink( $tmpfname ); 00665 00666 return TRUE; 00667 } 00668 } 00669 00670 ?>