mirror of
https://github.com/processwire/processwire.git
synced 2025-08-12 09:44:38 +02:00
Improvements and clarifications with the WireTempDir class
This commit is contained in:
@@ -16,30 +16,46 @@ class WireTempDir extends Wire {
|
|||||||
*/
|
*/
|
||||||
const hiddenFileName = '.wtd';
|
const hiddenFileName = '.wtd';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True when remove method has been called at least once
|
||||||
|
*
|
||||||
|
* This is to ensure later instances don’t perform redundant cleanup tasks.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static protected $maintenanceCompleted = false;
|
||||||
|
|
||||||
protected $classRoot = null; // example: /site/assets/WireTempDir/
|
protected $classRoot = null; // example: /site/assets/WireTempDir/
|
||||||
protected $tempDirRoot = null; // example: /site/assets/WireTempDir/.SomeName/
|
protected $tempDirRoot = null; // example: /site/assets/WireTempDir/.SomeName/
|
||||||
protected $tempDir = null; // example: /site/assets/WireTempDir/.SomeName/1/
|
protected $tempDir = null; // example: /site/assets/WireTempDir/.SomeName/1/
|
||||||
protected $tempDirMaxAge = 120; // maximum age in seconds
|
protected $tempDirMaxAge = 120; // maximum age in seconds for files in a user-specified name
|
||||||
protected $autoRemove = true; // automatially remove temp dir when this class is destructed?
|
protected $cleanMaxAge = 86400; // age after which files an be assumed to be abandoned and need cleanup
|
||||||
|
protected $autoRemove = true; // automatically remove temp dir when this class is destructed?
|
||||||
protected $createdName = ''; // name of runtime created random tempDirRoot, when applicable
|
protected $createdName = ''; // name of runtime created random tempDirRoot, when applicable
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct new temp dir
|
* Construct
|
||||||
*
|
*
|
||||||
* While this constructor accepts arguments, if you are in a multi-instance environment you should instead construct
|
* @param string|object $name DEPRECATED (Call 'init' method instead)
|
||||||
* with no arguments, inject the ProcessWire instance, and then call the create() method with those arguments.
|
* @param string $basePath DEPRECATED (Call 'init' method instead)
|
||||||
*
|
|
||||||
* @param string|object $name Recommend providing the object that is using the temp dir, but can also be any string
|
|
||||||
* @param string $basePath Base path where temp dirs should be created. Omit to use default (recommended).
|
|
||||||
* @throws WireException if given a $root that doesn't exist
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function __construct($name = '', $basePath = '') {
|
public function __construct($name = '', $basePath = '') {
|
||||||
if($name) $this->create($name, $basePath);
|
if($name) $this->init($name, $basePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the temporary directory
|
* Destruct
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __destruct() {
|
||||||
|
if($this->autoRemove) $this->remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize temporary directory
|
||||||
*
|
*
|
||||||
* This method should only be called once per instance of this class. If you specified a $name argument
|
* This method should only be called once per instance of this class. If you specified a $name argument
|
||||||
* in the constructor, then you should not call this method because it will have already been called.
|
* in the constructor, then you should not call this method because it will have already been called.
|
||||||
@@ -50,31 +66,43 @@ class WireTempDir extends Wire {
|
|||||||
* @return string Returns the root of the temporary directory. Use the get() method to get a dir for use.
|
* @return string Returns the root of the temporary directory. Use the get() method to get a dir for use.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function create($name = '', $basePath = '') {
|
public function init($name = '', $basePath = '') {
|
||||||
|
|
||||||
if(!is_null($this->tempDirRoot)) throw new WireException("Temp dir has already been created");
|
if(!is_null($this->tempDirRoot)) throw new WireException("Temp dir has already been created");
|
||||||
if(empty($name)) $name = $this->createName();
|
if(empty($name)) $name = $this->createName();
|
||||||
if(is_object($name)) $name = wireClassName($name, false);
|
if(is_object($name)) $name = wireClassName($name, false);
|
||||||
|
|
||||||
|
$basePath = $this->classRootPath(true, $basePath);
|
||||||
|
$this->classRoot = $basePath;
|
||||||
|
$this->tempDirRoot = $basePath . ".$name/";
|
||||||
|
|
||||||
|
return $this->tempDirRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the class root path for cache files (i.e. /path/to/site/assets/cache/WireTempDir/)
|
||||||
|
*
|
||||||
|
* @param bool $createIfNotExists Create the directory if it does not exist? (default=false)
|
||||||
|
* @param string $basePath Path to start from (default=/path/to/site/assets/cache/)
|
||||||
|
* @return string
|
||||||
|
* @throws WireException
|
||||||
|
* @since 3.0.175
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function classRootPath($createIfNotExists = false, $basePath = '') {
|
||||||
if($basePath) {
|
if($basePath) {
|
||||||
// they provide base path
|
// they provide base path
|
||||||
$basePath = rtrim($basePath, '/') . '/'; // ensure it ends with trailing slash
|
$basePath = rtrim($basePath, '/') . '/'; // ensure it ends with trailing slash
|
||||||
if(!is_dir($basePath)) throw new WireException("Provided base path doesn't exist: $basePath");
|
if(!is_dir($basePath)) throw new WireException("Provided base path doesn't exist: $basePath");
|
||||||
if(!is_writable($basePath)) throw new WireException("Provided base path is not writiable: $basePath");
|
if(!is_writable($basePath)) throw new WireException("Provided base path is not writiable: $basePath");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// we provide base path (root)
|
// we provide base path (root)
|
||||||
$basePath = $this->wire('config')->paths->cache;
|
$basePath = $this->wire()->config->paths->cache;
|
||||||
if(!is_dir($basePath)) $this->mkdir($basePath);
|
if($createIfNotExists && !is_dir($basePath)) $this->mkdir($basePath);
|
||||||
}
|
}
|
||||||
|
$basePath .= wireClassName($this, false) . '/'; // i.e. /path/to/site/assets/cache/WireTempDir/
|
||||||
$basePath .= wireClassName($this, false) . '/';
|
if($createIfNotExists && !is_dir($basePath)) $this->mkdir($basePath);
|
||||||
$this->classRoot = $basePath;
|
return $basePath;
|
||||||
if(!is_dir($basePath)) $this->mkdir($basePath);
|
|
||||||
|
|
||||||
$this->tempDirRoot = $basePath . ".$name/";
|
|
||||||
|
|
||||||
return $this->tempDirRoot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,20 +121,27 @@ class WireTempDir extends Wire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the max age of temp files (default=120 seconds)
|
* Set the max age of temp files and/or maintenance cleanup max age
|
||||||
*
|
*
|
||||||
* @param $seconds
|
* #pw-internal
|
||||||
|
*
|
||||||
|
* @param int|null $tempDirMaxAge Temp dir max age in seconds (default=120)
|
||||||
|
* @param int|null $cleanMaxAge Maintenance cleanup max age in seconds (default=86400) 3.0.175+
|
||||||
* @return $this
|
* @return $this
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setMaxAge($seconds) {
|
public function setMaxAge($tempDirMaxAge = null, $cleanMaxAge = null) {
|
||||||
$this->tempDirMaxAge = (int) $seconds;
|
if(is_int($tempDirMaxAge)) $this->tempDirMaxAge = $tempDirMaxAge;
|
||||||
|
if(is_int($cleanMaxAge)) $this->cleanMaxAge = $cleanMaxAge;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this with 'false' to prevent temp dir from being removed automatically when object is destructed
|
* Call this with 'false' to prevent temp dir from being removed automatically when object is destructed
|
||||||
*
|
*
|
||||||
|
* If you do this, then you accept responsibility for removing the directory by calling $tempDir->remove();
|
||||||
|
* If you do not remove it yourself, WireTempDir will remove as part of the daily maintenance.
|
||||||
|
*
|
||||||
* @param bool $remove
|
* @param bool $remove
|
||||||
* @return $this
|
* @return $this
|
||||||
*
|
*
|
||||||
@@ -116,10 +151,6 @@ class WireTempDir extends Wire {
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __destruct() {
|
|
||||||
if($this->autoRemove) $this->remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a temporary directory (path)
|
* Returns a temporary directory (path)
|
||||||
*
|
*
|
||||||
@@ -132,7 +163,7 @@ class WireTempDir extends Wire {
|
|||||||
|
|
||||||
static $level = 0;
|
static $level = 0;
|
||||||
|
|
||||||
if(is_null($this->tempDirRoot)) throw new WireException("Please call the create() method before the get() method");
|
if(is_null($this->tempDirRoot)) $this->init();
|
||||||
|
|
||||||
// first check if cached result from previous call
|
// first check if cached result from previous call
|
||||||
if(!is_null($this->tempDir) && file_exists($this->tempDir)) return $this->tempDir;
|
if(!is_null($this->tempDir) && file_exists($this->tempDir)) return $this->tempDir;
|
||||||
@@ -192,8 +223,6 @@ class WireTempDir extends Wire {
|
|||||||
*/
|
*/
|
||||||
public function remove() {
|
public function remove() {
|
||||||
|
|
||||||
static $classRuns = 0;
|
|
||||||
|
|
||||||
$errorMessage = 'Unable to remove temp dir';
|
$errorMessage = 'Unable to remove temp dir';
|
||||||
$success = true;
|
$success = true;
|
||||||
|
|
||||||
@@ -216,15 +245,15 @@ class WireTempDir extends Wire {
|
|||||||
$this->rmdir($this->tempDirRoot, true);
|
$this->rmdir($this->tempDirRoot, true);
|
||||||
} else {
|
} else {
|
||||||
// if it is potentially used by multiple instances, then remove only expired files
|
// if it is potentially used by multiple instances, then remove only expired files
|
||||||
$this->removeExpiredDirs($this->tempDirRoot);
|
$this->removeExpiredDirs($this->tempDirRoot, $this->tempDirMaxAge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$classRuns && $this->classRoot && is_dir($this->classRoot)) {
|
if(!self::$maintenanceCompleted && $this->classRoot && is_dir($this->classRoot)) {
|
||||||
$this->removeExpiredDirs($this->classRoot, 86400);
|
$this->removeExpiredDirs($this->classRoot, $this->cleanMaxAge);
|
||||||
}
|
}
|
||||||
|
|
||||||
$classRuns++;
|
self::$maintenanceCompleted = true;
|
||||||
|
|
||||||
return $success;
|
return $success;
|
||||||
}
|
}
|
||||||
@@ -235,11 +264,11 @@ class WireTempDir extends Wire {
|
|||||||
* Also removes $path if it's found that everything in it is expired.
|
* Also removes $path if it's found that everything in it is expired.
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* @param int|null Optionally specify a max age to override default setting.
|
* @param int Max age in seconds
|
||||||
* @return bool
|
* @return bool
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected function removeExpiredDirs($path, $maxAge = null) {
|
protected function removeExpiredDirs($path, $maxAge) {
|
||||||
|
|
||||||
if(!is_dir($path)) return false;
|
if(!is_dir($path)) return false;
|
||||||
if(!is_int($maxAge)) $maxAge = $this->tempDirMaxAge;
|
if(!is_int($maxAge)) $maxAge = $this->tempDirMaxAge;
|
||||||
@@ -259,7 +288,7 @@ class WireTempDir extends Wire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// old dir found: check times on files/dirs within that dir
|
// old dir found: check times on files/dirs within that dir
|
||||||
$pathname = $this->wire('files')->unixDirName($dir->getPathname());
|
$pathname = $this->wire()->files->unixDirName($dir->getPathname());
|
||||||
if(!$this->isTempDir($pathname)) continue;
|
if(!$this->isTempDir($pathname)) continue;
|
||||||
|
|
||||||
$removeDir = true;
|
$removeDir = true;
|
||||||
@@ -320,9 +349,11 @@ class WireTempDir extends Wire {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function removeAll() {
|
public function removeAll() {
|
||||||
if($this->classRoot && is_dir($this->classRoot)) {
|
$classRoot = $this->classRoot;
|
||||||
|
if(empty($classRoot)) $classRoot = $this->classRootPath(false);
|
||||||
|
if($classRoot && is_dir($classRoot)) {
|
||||||
// note: use of $files->rmdir rather than $this->rmdir is intentional
|
// note: use of $files->rmdir rather than $this->rmdir is intentional
|
||||||
return $this->wire('files')->rmdir($this->classRoot, true);
|
return $this->wire()->files->rmdir($classRoot, true);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -366,11 +397,12 @@ class WireTempDir extends Wire {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected function rmdir($dir, $recursive = false) {
|
protected function rmdir($dir, $recursive = false) {
|
||||||
$dir = $this->wire('files')->unixDirName($dir);
|
$files = $this->wire()->files;
|
||||||
|
$dir = $files->unixDirName($dir);
|
||||||
if(!strlen($dir) || !is_dir($dir)) return true;
|
if(!strlen($dir) || !is_dir($dir)) return true;
|
||||||
if(!$this->isTempDir($dir)) return false;
|
if(!$this->isTempDir($dir)) return false;
|
||||||
if(is_file($dir . self::hiddenFileName)) $this->wire('files')->unlink($dir . self::hiddenFileName, true);
|
if(is_file($dir . self::hiddenFileName)) $this->wire('files')->unlink($dir . self::hiddenFileName, true);
|
||||||
return $this->wire('files')->rmdir($dir, $recursive, true);
|
return $files->rmdir($dir, $recursive, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -381,7 +413,7 @@ class WireTempDir extends Wire {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected function isTempDir($dir) {
|
protected function isTempDir($dir) {
|
||||||
$files = $this->wire('files');
|
$files = $this->wire()->files;
|
||||||
if(!strlen($dir) || !is_dir($dir)) {
|
if(!strlen($dir) || !is_dir($dir)) {
|
||||||
// if given a non-directory return false
|
// if given a non-directory return false
|
||||||
return false;
|
return false;
|
||||||
@@ -393,4 +425,35 @@ class WireTempDir extends Wire {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform maintenance by cleaning up old temporary directories
|
||||||
|
*
|
||||||
|
* Note: This is done automatically if any temporary directories are created during the request.
|
||||||
|
*
|
||||||
|
* @throws WireException
|
||||||
|
* @return bool
|
||||||
|
* @since 3.0.175
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function maintenance() {
|
||||||
|
if(self::$maintenanceCompleted) return true;
|
||||||
|
$classRoot = $this->classRoot ? $this->classRoot : $this->classRootPath(false);
|
||||||
|
$result = $this->removeExpiredDirs($classRoot, $this->cleanMaxAge);
|
||||||
|
self::$maintenanceCompleted = true;
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use init() method instead
|
||||||
|
* @param string $name
|
||||||
|
* @param string $basePath
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function create($name = '', $basePath = '') {
|
||||||
|
return $this->init($name, $basePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user