|
eZ Publish
[4.0]
|
00001 <?php 00002 // 00003 // Definition of eZFSFileHandler class 00004 // 00005 // Created on: <09-Mar-2006 16:40:46 vs> 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 ezfsfilehandler.php 00032 */ 00033 00034 require_once( 'lib/ezutils/classes/ezdebugsetting.php' ); 00035 00036 class eZFSFileHandler 00037 { 00038 /** 00039 * Constructor. 00040 * 00041 * $filePath File path. If specified, file metadata is fetched in the constructor. 00042 */ 00043 function eZFSFileHandler( $filePath = false ) 00044 { 00045 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::ctor( '$filePath' )" ); 00046 // $this->metaData['name'] = $filePath; 00047 $this->Mutex = null; 00048 $this->filePath = $filePath; 00049 $this->lifetime = 60; // Lifetime of lock 00050 $this->loadMetaData(); 00051 } 00052 00053 /*! 00054 \private 00055 Acquires an exclusive lock to the current file by using eZMutex. 00056 00057 If a lock is already present it will sleep 0.5 seconds and try again until 00058 the lock lifetime is exceeded and the lock is stolen. 00059 00060 Note: Lock stealing might be removed. 00061 00062 \param $fname Name of the calling code (usually function name). 00063 */ 00064 function _exclusiveLock( $fname = false ) 00065 { 00066 //$pid = getmypid(); 00067 $mutex =& $this->_mutex(); 00068 while ( true ) 00069 { 00070 $timestamp = $mutex->lockTS(); // Note: This does not lock, only checks what the timestamp is. 00071 if ( $timestamp === false ) 00072 { 00073 if ( !$mutex->lock() ) 00074 { 00075 eZDebug::writeWarning( "Failed to acquire lock for file " . $this->filePath ); 00076 return false; 00077 } 00078 $mutex->setMeta( 'pid', getmypid() ); 00079 return true; 00080 } 00081 if ( $timestamp >= time() - $this->lifetime ) 00082 { 00083 usleep( 500000 ); // Sleep 0.5 second 00084 continue; 00085 } 00086 00087 $oldPid = $mutex->meta( 'pid' ); 00088 if ( is_numeric( $oldPid ) && 00089 $oldPid != 0 && 00090 function_exists( 'posix_kill' ) ) 00091 { 00092 posix_kill( $oldPid, 9 ); 00093 } 00094 if ( !$mutex->steal() ) 00095 { 00096 eZDebug::writeWarning( "Failed to steal lock for file " . $this->filePath . " from PID $oldPid" ); 00097 return false; 00098 } 00099 $mutex->setMeta( 'pid', getmypid() ); 00100 return true; 00101 } 00102 } 00103 00104 /*! 00105 \private 00106 Frees the current exclusive lock in use. 00107 00108 \param $fname Name of the calling code (usually function name). 00109 */ 00110 function _freeExclusiveLock( $fname = false ) 00111 { 00112 $mutex =& $this->_mutex(); 00113 $mutex->unlock(); 00114 } 00115 00116 /*! 00117 \private 00118 Returns the mutex object for the current file. 00119 */ 00120 function &_mutex() 00121 { 00122 if ( $this->Mutex !== null ) 00123 return $this->Mutex; 00124 //include_once( "lib/ezutils/classes/ezmutex.php" ); 00125 $mutex = new eZMutex( $this->filePath ); 00126 return $mutex; 00127 } 00128 00129 /*! 00130 \public 00131 Load file meta information. 00132 00133 \param $force If true, file stats will be refreshed 00134 */ 00135 function loadMetaData( $force = false ) 00136 { 00137 if ( $this->filePath !== false ) 00138 { 00139 if ( $force ) 00140 clearstatcache(); 00141 00142 // fill $this->metaData 00143 $filePath = $this->filePath; 00144 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00145 $this->metaData = @stat( $filePath ); 00146 eZDebug::accumulatorStop( 'dbfile' ); 00147 // $this->metaData['name'] = $filePath; 00148 } 00149 } 00150 00151 /** 00152 * Fetches file from db and saves it in FS under the same name. 00153 * 00154 * In case of fetching from filesystem does nothing. 00155 * 00156 * \public 00157 * \static 00158 */ 00159 function fileFetch( $filePath ) 00160 { 00161 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fileFetch( '$filePath' )" ); 00162 } 00163 00164 /** 00165 * Fetches file from db and saves it in FS under the same name. 00166 * 00167 * In case of fetching from filesystem does nothing. 00168 * 00169 * \public 00170 */ 00171 function fetch( $cacheLocally = false ) 00172 { 00173 $filePath = $this->filePath; 00174 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fetch( '$filePath' )" ); 00175 } 00176 00177 /** 00178 * Fetches file from db and saves it in FS under unique name. 00179 * 00180 * In case of fetching from filesystem does nothing. 00181 * \public 00182 */ 00183 function fetchUnique( ) 00184 { 00185 $filePath = $this->filePath; 00186 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fetchUnique( '$filePath' )" ); 00187 return $filePath; 00188 } 00189 00190 /** 00191 * Store file. 00192 * 00193 * In case of storing to filesystem does nothing. 00194 * 00195 * \public 00196 * \static 00197 * \param $filePath Path to the file being stored. 00198 * \param $scope Means something like "file category". May be used to clean caches of a certain type. 00199 * \param $delete true if the file should be deleted after storing. 00200 */ 00201 function fileStore( $filePath, $scope = false, $delete = false, $datatype = false ) 00202 { 00203 $delete = (int) $delete; 00204 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fileStore( '$filePath' )" ); 00205 } 00206 00207 /** 00208 * Store file contents. 00209 * 00210 * \public 00211 * \static 00212 */ 00213 function fileStoreContents( $filePath, $contents, $scope = false, $datatype = false ) 00214 { 00215 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fileStoreContents( '$filePath' )" ); 00216 00217 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00218 00219 eZFile::create( basename( $filePath ), dirname( $filePath ), $contents, true ); 00220 00221 $perm = eZINI::instance()->variable( 'FileSettings', 'StorageFilePermissions' ); 00222 chmod( $filePath, octdec( $perm ) ); 00223 00224 eZDebug::accumulatorStop( 'dbfile' ); 00225 } 00226 00227 /** 00228 * Store file contents. 00229 * 00230 * \public 00231 * \static 00232 * 00233 * \param $storeLocally This parameter is ignored since it makes no sense for the FS file handler. 00234 */ 00235 function storeContents( $contents, $scope = false, $datatype = false, $storeLocally = false ) 00236 { 00237 $filePath = $this->filePath; 00238 00239 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::storeContents( '$filePath' )" ); 00240 00241 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00242 00243 //include_once( 'lib/ezfile/classes/ezfile.php' ); 00244 eZFile::create( basename( $filePath ), dirname( $filePath ), $contents, true ); 00245 00246 $perm = eZINI::instance()->variable( 'FileSettings', 'StorageFilePermissions' ); 00247 chmod( $filePath, octdec( $perm ) ); 00248 00249 eZDebug::accumulatorStop( 'dbfile' ); 00250 } 00251 00252 /** 00253 * Returns file contents. 00254 * 00255 * \public 00256 * \static 00257 * \return contents string, or false in case of an error. 00258 */ 00259 function fileFetchContents( $filePath ) 00260 { 00261 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fileFetchContents( '$filePath' )" ); 00262 00263 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00264 $rslt = file_get_contents( $filePath ); 00265 eZDebug::accumulatorStop( 'dbfile' ); 00266 00267 return $rslt; 00268 } 00269 00270 /** 00271 * Returns file contents. 00272 * 00273 * \public 00274 * \return contents string, or false in case of an error. 00275 */ 00276 function fetchContents() 00277 { 00278 $filePath = $this->filePath; 00279 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fetchContents( '$filePath' )" ); 00280 00281 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00282 $rslt = file_get_contents( $filePath ); 00283 eZDebug::accumulatorStop( 'dbfile' ); 00284 00285 return $rslt; 00286 } 00287 00288 /*! 00289 Creates a single transaction out of the typical file operations for accessing caches. 00290 Caches are normally ready from the database or local file, if the entry does not exist 00291 or is expired then it generates the new cache data and stores it. 00292 This method takes care of these operations and handles the custom code by performing 00293 callbacks when needed. 00294 00295 The $retrieveCallback is used when the file contents can be used (ie. not re-generation) and 00296 is called when the file is ready locally. 00297 The function will be called with the file path as the first parameter, the mtime as the second 00298 and optionally $extraData as the third. 00299 The function must return the file contents or an instance of eZClusterFileFailure which can 00300 be used to tell the system that the retrieve data cannot be used after all. 00301 $retrieveCallback can be set to null which makes the system go directly to the generation. 00302 00303 The $generateCallback is used when the file content is expired or does not exist, in this 00304 case the content must be re-generated and stored. 00305 The function will be called with the file path as the first parameter and optionally $extraData 00306 as the second. 00307 The function must return an array with information on the contents, the array consists of: 00308 - scope - The current scope of the file, is optional. 00309 - datatype - The current datatype of the file, is optional. 00310 - content - The file content, this can be any type except null. 00311 - binarydata - The binary data which is written to the file. 00312 - store - Whether *content* or *binarydata* should be stored to the file, if false it will simply return the data. Optional, by default it is true. 00313 Note: Set $generateCallback to false to disable generation callback. 00314 Note: Set $generateCallback to null to tell the function to perform a write lock but not do any generation, the generation must done be done by the caller by calling storeCache(). 00315 00316 Either *content* or *binarydata* must be supplied, if not an error is issued and it returns null. 00317 If *content* is set it will be used as the return value of this function, if not it will return the binary data. 00318 If *binarydata* is set it will be used as the binary data for the file, if not it will perform a var_export on *content* and use that as the binary data. 00319 00320 For convenience the $generateCallback function can return a string which will be considered as the 00321 binary data for the file and returned as the content. 00322 00323 For controlling how long a cache entry can be used the parameters $expiry and $ttl is used. 00324 $expiry can be set to a timestamp which controls the absolute max time for the cache, after this 00325 time/date the cache will never be used. If the value is set to a negative value or null there the 00326 expiration check is disabled. 00327 00328 $ttl (time to live) tells how many seconds the cache can live from the time it was stored. If the 00329 value is set to negative or null there is no limit for the lifetime of the cache. A value of 0 means 00330 that the cache will always expire and practically disables caching. 00331 For the cache to be used both the $expiry and $ttl check must hold. 00332 */ 00333 function processCache( $retrieveCallback, $generateCallback = null, $ttl = null, $expiry = null, $extraData = null ) 00334 { 00335 //include_once( 'kernel/classes/ezclusterfilefailure.php' ); 00336 $forceDB = false; 00337 $fname = $this->filePath; 00338 $args = array( $fname ); 00339 if ( $extraData !== null ) 00340 $args[] = $extraData; 00341 $timestamp = null; 00342 $curtime = time(); 00343 $tries = 0; 00344 00345 if ( $expiry < 0 ) 00346 $expiry = null; 00347 if ( $ttl < 0 ) 00348 $ttl = null; 00349 00350 while ( true ) 00351 { 00352 $forceGeneration = false; 00353 $storeCache = true; 00354 $mtime = @filemtime( $fname ); 00355 // $mtime = $this->metaData['mtime']; 00356 if ( $retrieveCallback !== null && !eZFSFileHandler::isExpired( $fname, $mtime, $expiry, $curtime, $ttl ) ) 00357 { 00358 $args = array( $fname, $mtime ); 00359 if ( $extraData !== null ) 00360 $args[] = $extraData; 00361 $retval = call_user_func_array( $retrieveCallback, $args ); 00362 if ( !( $retval instanceof eZClusterFileFailure ) ) 00363 { 00364 return $retval; 00365 } 00366 $forceGeneration = true; 00367 } 00368 00369 if ( $tries >= 2 ) 00370 { 00371 eZDebugSetting::writeDebug( 'kernel-clustering', "Reading was retried $tries times and reached the maximum, returning null" ); 00372 $forceGeneration = true; // We will now generate the cache but not store it 00373 $storeCache = false; // This disables the cache storage 00374 } 00375 00376 // Generation part starts here 00377 if ( isset( $retval ) && 00378 $retval instanceof eZClusterFileFailure ) 00379 { 00380 if ( $retval->errno() != 1 ) // check for non-expiry error codes 00381 { 00382 eZDebug::writeError( "Failed to retrieve data from callback", 'eZFSFileHandler::processCache' ); 00383 return null; 00384 } 00385 $message = $retval->message(); 00386 if ( strlen( $message ) > 0 ) 00387 { 00388 eZDebugSetting::writeDebug( 'kernel-clustering', $retval->message(), "eZClusterFileFailure::processCache" ); 00389 } 00390 // the retrieved data was expired so we need to generate it, let's continue 00391 } 00392 00393 // We need to lock if we have a generate-callback or 00394 // the generation is deferred to the caller. 00395 // Note: false means no generation 00396 if ( $generateCallback !== false && 00397 $forceGeneration === false ) 00398 { 00399 // Lock the entry for exclusive access, if the entry does not exist 00400 // it will be inserted with mtime=-1 00401 if ( !$this->_exclusiveLock( $fname, 'processCache' ) ) 00402 { 00403 // Cannot get exclusive lock, so return null. 00404 return null; 00405 } 00406 00407 // This is where we perform a two-phase commit. If any other 00408 // process or machine has generated the file data and it is valid 00409 // we will retry the retrieval part and not do the generation. 00410 @clearstatcache(); 00411 $mtime = @filemtime( $fname ); 00412 // $expiry = max( $curtime, $expiry ); 00413 if ( $mtime > 0 && !eZFSFileHandler::isExpired( $fname, $mtime, $expiry, $curtime, $ttl ) ) 00414 { 00415 eZDebugSetting::writeDebug( 'kernel-clustering', "File was generated while we were locked, use that instead" ); 00416 $this->metaData = false; 00417 $this->_freeExclusiveLock( 'storeCache' ); 00418 ++$tries; 00419 continue; // retry reading file 00420 } 00421 } 00422 00423 // File in DB is outdated or non-existing, call write-callback to generate content 00424 if ( $generateCallback ) 00425 { 00426 $args = array( $fname ); 00427 if ( $extraData !== null ) 00428 $args[] = $extraData; 00429 $fileData = call_user_func_array( $generateCallback, $args ); 00430 return $this->storeCache( $fileData, $storeCache ); 00431 } 00432 00433 break; 00434 } 00435 00436 return new eZClusterFileFailure( 2, "Manual generation of file data is required, calling storeCache is required" ); 00437 } 00438 00439 /*! 00440 \static 00441 \private 00442 Calculates if the file data is expired or not. 00443 00444 \param $fname Name of file, available for easy debugging. 00445 \param $mtime Modification time of file, can be set to false if file does not exist. 00446 \param $expiry Time when file is to be expired, a value of -1 will disable this check. 00447 \param $curtime The current time to check against. 00448 \param $ttl Number of seconds the data can live, set to null to disable TTL. 00449 */ 00450 function isExpired( $fname, $mtime, $expiry, $curtime, $ttl ) 00451 { 00452 if ( $mtime == false ) 00453 { 00454 return true; 00455 } 00456 else if ( $ttl === null ) 00457 { 00458 $ret = $mtime < $expiry; 00459 return $ret; 00460 } 00461 else 00462 { 00463 $ret = $mtime < max( $expiry, $curtime - $ttl ); 00464 return $ret; 00465 } 00466 } 00467 00468 /*! 00469 \private 00470 Stores the data in $fileData to the remote and local file and commits the transaction. 00471 00472 The parameter $fileData must contain the same as information as the $generateCallback returns as explained in processCache(). 00473 00474 \note This method is just a continuation of the code in processCache() and is not meant to be called alone since it relies on specific state in the database. 00475 */ 00476 function storeCache( $fileData, $storeCache = true ) 00477 { 00478 $fname = $this->filePath; 00479 00480 $scope = false; 00481 $datatype = false; 00482 $binaryData = null; 00483 $fileContent = null; 00484 $store = true; 00485 if ( is_array( $fileData ) ) 00486 { 00487 if ( isset( $fileData['scope'] ) ) 00488 $scope = $fileData['scope']; 00489 if ( isset( $fileData['datatype'] ) ) 00490 $datatype = $fileData['datatype']; 00491 if ( isset( $fileData['content'] ) ) 00492 $fileContent = $fileData['content']; 00493 if ( isset( $fileData['binarydata'] ) ) 00494 $binaryData = $fileData['binarydata']; 00495 if ( isset( $fileData['store'] ) ) 00496 $store = $fileData['store']; 00497 } 00498 else 00499 $binaryData = $fileData; 00500 00501 // Disable storage if the caller of the function says so 00502 if ( !$storeCache ) 00503 $store = false; 00504 00505 $mtime = false; 00506 $result = null; 00507 if ( $binaryData === null && 00508 $fileContent === null ) 00509 { 00510 eZDebug::writeError( "Write callback need to set the 'content' or 'binarydata' entry" ); 00511 return null; 00512 } 00513 00514 if ( $binaryData === null ) 00515 $binaryData = "<" . "?php\n\treturn ". var_export( $fileContent, true ) . ";\n?" . ">\n"; 00516 00517 if ( $fileContent === null ) 00518 $result = $binaryData; 00519 else 00520 $result = $fileContent; 00521 00522 // Check if we are allowed to store the data, if not just return the result 00523 if ( !$store ) 00524 { 00525 return $result; 00526 } 00527 00528 // Store content locally 00529 $this->storeContents( $binaryData, $scope, $datatype, true ); 00530 00531 $this->_freeExclusiveLock( 'storeCache' ); 00532 00533 return $result; 00534 } 00535 00536 /*! 00537 Provides access to the file contents by downloading the file locally and 00538 calling $callback with the local filename. The callback can then process the 00539 contents and return the data in the same way as in processCache(). 00540 Downloading is only done once so the local copy is kept, while updates to the 00541 remote DB entry is synced with the local one. 00542 00543 The parameters $expiry and $extraData is the same as for processCache(). 00544 00545 \note Unlike processCache() this returns null if the file cannot be accessed. 00546 */ 00547 function processFile( $callback, $expiry = false, $extraData = null ) 00548 { 00549 $result = $this->processCache( $callback, false, null, $expiry, $extraData ); 00550 if ( $result instanceof eZClusterFileFailure ) 00551 { 00552 return null; 00553 } 00554 return $result; 00555 } 00556 00557 /** 00558 * Returns file metadata. 00559 * 00560 * \public 00561 */ 00562 function stat() 00563 { 00564 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::stat()" ); 00565 return $this->metaData; 00566 } 00567 00568 /** 00569 * Returns file size. 00570 * 00571 * \public 00572 */ 00573 function size() 00574 { 00575 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::size()" ); 00576 return isset( $this->metaData['size'] ) ? $this->metaData['size'] : null; 00577 } 00578 00579 /** 00580 * Returns file modification time. 00581 * 00582 * \public 00583 */ 00584 function mtime() 00585 { 00586 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::mtime()" ); 00587 return isset( $this->metaData['mtime'] ) ? $this->metaData['mtime'] : null; 00588 } 00589 00590 /** 00591 * Returns file name. 00592 * 00593 * \public 00594 */ 00595 function name() 00596 { 00597 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::name()" ); 00598 return $this->filePath; 00599 } 00600 00601 /** 00602 * Delete files matching regex $fileRegex under directory $dir. 00603 * 00604 * \public 00605 * \static 00606 * \sa fileDeleteByWildcard() 00607 */ 00608 function fileDeleteByRegex( $dir, $fileRegex ) 00609 { 00610 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fileDeleteByRegex( '$dir', '$fileRegex' )" ); 00611 00612 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00613 00614 if ( !file_exists( $dir ) ) 00615 { 00616 //eZDebugSetting::writeDebug( 'kernel-clustering', "Dir '$dir' does not exist", 'dir' ); 00617 eZDebug::accumulatorStop( 'dbfile' ); 00618 return; 00619 } 00620 00621 $dirHandle = opendir( $dir ); 00622 if ( !$dirHandle ) 00623 { 00624 eZDebug::writeError( "opendir( '$dir' ) failed." ); 00625 eZDebug::accumulatorStop( 'dbfile' ); 00626 return; 00627 } 00628 00629 while ( ( $file = readdir( $dirHandle ) ) !== false ) 00630 { 00631 if ( $file == '.' or 00632 $file == '..' ) 00633 continue; 00634 if ( preg_match( "/^$fileRegex/", $file ) ) 00635 { 00636 //eZDebugSetting::writeDebug( 'kernel-clustering', "\$file = eZDir::path( array( '$dir', '$file' ) );" ); 00637 $file = eZDir::path( array( $dir, $file ) ); 00638 eZDebugSetting::writeDebug( 'kernel-clustering', "Removing cache file '$file'", 'eZFSFileHandler::deleteRegex' ); 00639 unlink( $file ); 00640 00641 // Write log message to storage.log 00642 //include_once( 'lib/ezfile/classes/ezlog.php' ); 00643 eZLog::writeStorageLog( $file ); 00644 } 00645 } 00646 closedir( $dirHandle ); 00647 00648 eZDebug::accumulatorStop( 'dbfile' ); 00649 } 00650 00651 /** 00652 * Delete files matching given wildcard. 00653 * 00654 * Note that this method is faster than fileDeleteByRegex(). 00655 * 00656 * \public 00657 * \static 00658 * \sa fileDeleteByRegex() 00659 */ 00660 function fileDeleteByWildcard( $wildcard ) 00661 { 00662 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fileDeleteByWildcard( '$wildcard' )" ); 00663 00664 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00665 $unlinkArray = eZSys::globBrace( $wildcard ); 00666 if ( $unlinkArray !== false and ( count( $unlinkArray ) > 0 ) ) 00667 { 00668 array_map( 'unlink', $unlinkArray ); 00669 } 00670 eZDebug::accumulatorStop( 'dbfile' ); 00671 } 00672 00673 00674 /** 00675 * Delete files located in a directories from dirList, with common prefix specified by 00676 * commonPath, and common suffix with added wildcard at the end 00677 * 00678 * \public 00679 * \static 00680 * \sa fileDeleteByRegex() 00681 */ 00682 function fileDeleteByDirList( $dirList, $commonPath, $commonSuffix ) 00683 { 00684 $dirs = implode( ',', $dirList ); 00685 $wildcard = $commonPath .'/{' . $dirs . '}/' . $commonSuffix . '*'; 00686 00687 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fileDeleteByDirList( '$dirs', '$commonPath', '$commonSuffix' )" ); 00688 00689 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00690 $unlinkArray = eZSys::globBrace( $wildcard ); 00691 if ( $unlinkArray !== false and ( count( $unlinkArray ) > 0 ) ) 00692 { 00693 array_map( 'unlink', $unlinkArray ); 00694 } 00695 eZDebug::accumulatorStop( 'dbfile' ); 00696 } 00697 00698 /** 00699 * \public 00700 * \static 00701 */ 00702 function fileDelete( $path, $fnamePart = false ) 00703 { 00704 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fileDelete( '$path' )" ); 00705 00706 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00707 00708 $list = array(); 00709 if ( $fnamePart !== false ) 00710 { 00711 $globResult = glob( $path . "/" . $fnamePart . "*" ); 00712 if ( is_array( $globResult ) ) 00713 { 00714 $list = $globResult; 00715 } 00716 } 00717 else 00718 { 00719 $list = array( $path ); 00720 } 00721 00722 foreach ( $list as $path ) 00723 { 00724 if ( is_file( $path ) ) 00725 { 00726 //include_once( 'lib/ezfile/classes/ezfilehandler.php' ); 00727 $handler = eZFileHandler::instance( false ); 00728 $handler->unlink( $path ); 00729 if ( file_exists( $path ) ) 00730 eZDebug::writeError( "File still exists after removal: '$path'", 'fs::fileDelete' ); 00731 } 00732 else 00733 { 00734 //include_once( 'lib/ezfile/classes/ezdir.php' ); 00735 eZDir::recursiveDelete( $path ); 00736 } 00737 } 00738 00739 eZDebug::accumulatorStop( 'dbfile' ); 00740 } 00741 00742 /** 00743 * Deletes specified file/directory. 00744 * 00745 * If a directory specified it is deleted recursively. 00746 * 00747 * \public 00748 * \static 00749 */ 00750 function delete() 00751 { 00752 $path = $this->filePath; 00753 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::delete( '$path' )" ); 00754 00755 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00756 00757 if ( is_file( $path ) ) 00758 { 00759 //include_once( 'lib/ezfile/classes/ezfilehandler.php' ); 00760 $handler = eZFileHandler::instance( false ); 00761 $handler->unlink( $path ); 00762 if ( file_exists( $path ) ) 00763 eZDebug::writeError( "File still exists after removal: '$path'", 'fs::fileDelete' ); 00764 } 00765 elseif ( is_dir( $path ) ) 00766 { 00767 //include_once( 'lib/ezfile/classes/ezdir.php' ); 00768 eZDir::recursiveDelete( $path ); 00769 } 00770 00771 eZDebug::accumulatorStop( 'dbfile' ); 00772 } 00773 00774 /** 00775 * Deletes a file that has been fetched before. 00776 * 00777 * In case of fetching from filesystem does nothing. 00778 * 00779 * \public 00780 * \static 00781 */ 00782 function fileDeleteLocal( $path ) 00783 { 00784 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fileDeleteLocal( '$path' )" ); 00785 } 00786 00787 /** 00788 * Deletes a file that has been fetched before. 00789 * 00790 * In case of fetching from filesystem does nothing. 00791 * 00792 * \public 00793 */ 00794 function deleteLocal() 00795 { 00796 $path = $this->filePath; 00797 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::deleteLocal( '$path' )" ); 00798 } 00799 00800 /*! 00801 Purge local and remote file data for current file. 00802 */ 00803 function purge( $printCallback = false, $microsleep = false, $max = false, $expiry = false ) 00804 { 00805 $file = $this->filePath; 00806 if ( $max === false ) 00807 $max = 100; 00808 $count = 0; 00809 $list = array(); 00810 if ( is_file( $file ) ) 00811 { 00812 $list = array( $file ); 00813 } 00814 else 00815 { 00816 $globResult = glob( $file . "/*" ); 00817 if ( is_array( $globResult ) ) 00818 { 00819 $list = $globResult; 00820 } 00821 } 00822 do 00823 { 00824 if ( ( $count % $max ) == 0 && $microsleep ) 00825 usleep( $microsleep ); // Sleep a bit to make the filesystem happier 00826 00827 $count = 0; 00828 $file = array_shift( $list ); 00829 00830 if ( is_file( $file ) ) 00831 { 00832 $mtime = @filemtime( $file ); 00833 if ( $expiry === false || 00834 $mtime < $expiry ) // remove it if it is too old 00835 @unlink( $file ); 00836 ++$count; 00837 } 00838 else if ( is_dir( $file ) ) 00839 { 00840 $globResult = glob( $file . "/*" ); 00841 if ( is_array( $globResult ) ) 00842 { 00843 $list = array_merge( $list, $globResult ); 00844 } 00845 } 00846 00847 if ( $printCallback ) 00848 call_user_func_array( $printCallback, 00849 array( $file, 1 ) ); 00850 } while ( count( $list ) > 0 ); 00851 } 00852 00853 /** 00854 * Check if given file/dir exists. 00855 * 00856 * \public 00857 * \static 00858 */ 00859 function fileExists( $path ) 00860 { 00861 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fileExists( '$path' )" ); 00862 00863 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00864 $rc = file_exists( $path ); 00865 eZDebug::accumulatorStop( 'dbfile' ); 00866 00867 return $rc; 00868 } 00869 00870 /** 00871 * Check if given file/dir exists. 00872 * 00873 * NOTE: this function does not interact with filesystem. 00874 * Instead, it just returns existance status determined in the constructor. 00875 * 00876 * \public 00877 */ 00878 function exists() 00879 { 00880 $path = $this->filePath; 00881 $rc = isset( $this->metaData['mtime'] ); 00882 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::exists( '$path' ): " . ( $rc ? 'true' :'false' ) ); 00883 00884 return $rc; 00885 } 00886 00887 /** 00888 * Outputs file contents prepending them with appropriate HTTP headers. 00889 * 00890 * \public 00891 */ 00892 function passthrough() 00893 { 00894 $path = $this->filePath; 00895 00896 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::passthrough()" ); 00897 00898 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00899 00900 //include_once( 'lib/ezutils/classes/ezmimetype.php' ); 00901 $mimeData = eZMimeType::findByFileContents( $path ); 00902 // $mimeType = $mimeData['name']; 00903 $mimeType = 'application/octec-stream'; 00904 $contentLength = filesize( $path ); 00905 00906 header( "Content-Length: $contentLength" ); 00907 header( "Content-Type: $mimeType" ); 00908 header( "Expires: ". gmdate('D, d M Y H:i:s', time() + 6000) . 'GMT'); 00909 header( "Connection: close" ); 00910 00911 readfile( $path ); 00912 00913 eZDebug::accumulatorStop( 'dbfile' ); 00914 } 00915 00916 /** 00917 * Copy file. 00918 * 00919 * \public 00920 * \static 00921 */ 00922 function fileCopy( $srcPath, $dstPath ) 00923 { 00924 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fileCopy( '$srcPath', '$dstPath' )" ); 00925 00926 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00927 require_once( 'lib/ezfile/classes/ezfilehandler.php' ); 00928 eZFileHandler::copy( $srcPath, $dstPath ); 00929 eZDebug::accumulatorStop( 'dbfile', false, 'dbfile' ); 00930 } 00931 00932 /** 00933 * Create symbolic or hard link to file. 00934 * 00935 * \public 00936 * \static 00937 */ 00938 function fileLinkCopy( $srcPath, $dstPath, $symLink ) 00939 { 00940 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fileLinkCopy( '$srcPath', '$dstPath' )" ); 00941 00942 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00943 require_once( 'lib/ezfile/classes/ezfilehandler.php' ); 00944 eZFileHandler::linkCopy( $srcPath, $dstPath, $symLink ); 00945 eZDebug::accumulatorStop( 'dbfile', false, 'dbfile' ); 00946 } 00947 00948 /** 00949 * Move file. 00950 * 00951 * \public 00952 * \static 00953 */ 00954 function fileMove( $srcPath, $dstPath ) 00955 { 00956 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::fileMove( '$srcPath', '$dstPath' )" ); 00957 00958 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00959 require_once( 'lib/ezfile/classes/ezfilehandler.php' ); 00960 eZFileHandler::move( $srcPath, $dstPath ); 00961 eZDebug::accumulatorStop( 'dbfile' ); 00962 } 00963 00964 /** 00965 * Move file. 00966 * 00967 * \public 00968 */ 00969 function move( $dstPath ) 00970 { 00971 $srcPath = $this->filePath; 00972 00973 eZDebugSetting::writeDebug( 'kernel-clustering', "fs::move( '$srcPath', '$dstPath' )" ); 00974 00975 eZDebug::accumulatorStart( 'dbfile', false, 'dbfile' ); 00976 require_once( 'lib/ezfile/classes/ezfilehandler.php' ); 00977 eZFileHandler::move( $srcPath, $dstPath ); 00978 eZDebug::accumulatorStop( 'dbfile' ); 00979 } 00980 00981 public $metaData = null; 00982 } 00983 00984 ?>