mirror of
https://github.com/processwire/processwire.git
synced 2025-08-10 16:54:44 +02:00
Add new $files->unlink() and $files->rename() methods to files API var, plus enhance many file methods with additional security for path verification, and update PW's various usages of unlink/rename to use the new versions provided by the files API var.
This commit is contained in:
@@ -210,7 +210,7 @@ class CacheFile extends Wire {
|
||||
foreach($dir as $file) {
|
||||
if($file->isDir() || $file->isDot()) continue;
|
||||
//if(strpos($file->getFilename(), self::cacheFileExtension)) @unlink($file->getPathname());
|
||||
if(self::isCacheFile($file->getPathname())) @unlink($file->getPathname());
|
||||
if(self::isCacheFile($file->getPathname())) $this->wire('files')->unlink($file->getPathname());
|
||||
}
|
||||
|
||||
return @rmdir($this->path);
|
||||
@@ -223,7 +223,7 @@ class CacheFile extends Wire {
|
||||
*
|
||||
*/
|
||||
protected function removeFilename($filename) {
|
||||
@unlink($filename);
|
||||
$this->wire('files')->unlink($filename);
|
||||
}
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ class CacheFile extends Wire {
|
||||
$numRemoved += self::removeAll($pathname, true);
|
||||
|
||||
} else if($file->isFile() && (self::isCacheFile($pathname) || ($file->getFilename() == self::globalExpireFilename))) {
|
||||
if(unlink($pathname)) $numRemoved++;
|
||||
if(wire('files')->unlink($pathname)) $numRemoved++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1110,7 +1110,7 @@ class FileCompiler extends Wire {
|
||||
|
||||
if(!file_exists($sourceFile)) {
|
||||
// source file has been deleted
|
||||
unlink($targetFile);
|
||||
$this->wire('files')->unlink($targetFile, true);
|
||||
if($useLog) $this->log("Maintenance/Remove target file: $targetURL$basename");
|
||||
|
||||
} else if(filemtime($sourceFile) > filemtime($targetFile)) {
|
||||
|
@@ -451,11 +451,11 @@ class FileLog extends Wire {
|
||||
fclose($fpr);
|
||||
|
||||
if($cnt) {
|
||||
unlink($filename);
|
||||
rename("$filename.new", $filename);
|
||||
$this->wire('files')->unlink($filename, true);
|
||||
$this->wire('files')->rename("$filename.new", $filename, true);
|
||||
$this->wire('files')->chmod($filename);
|
||||
} else {
|
||||
@unlink("$filename.new");
|
||||
$this->wire('files')->unlink("$filename.new", true);
|
||||
}
|
||||
|
||||
return $cnt;
|
||||
@@ -477,8 +477,8 @@ class FileLog extends Wire {
|
||||
'dateTo' => time(),
|
||||
));
|
||||
if(file_exists($toFile)) {
|
||||
unlink($this->logFilename);
|
||||
rename($toFile, $this->logFilename);
|
||||
$this->wire('files')->unlink($this->logFilename, true);
|
||||
$this->wire('files')->rename($toFile, $this->logFilename, true);
|
||||
return $qty;
|
||||
}
|
||||
return 0;
|
||||
@@ -491,7 +491,7 @@ class FileLog extends Wire {
|
||||
*
|
||||
*/
|
||||
public function delete() {
|
||||
return @unlink($this->logFilename);
|
||||
return $this->wire('files')->unlink($this->logFilename, true);
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
|
@@ -552,9 +552,9 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
||||
$dest = preg_replace('/\.' . $extension . '$/', '_tmp.' . $extension, $filename);
|
||||
if(strlen($content) == @file_put_contents($dest, $content, \LOCK_EX)) {
|
||||
// on success we replace the file
|
||||
unlink($filename);
|
||||
rename($dest, $filename);
|
||||
wireChmod($filename);
|
||||
$this->wire('files')->unlink($filename);
|
||||
$this->wire('files')->rename($dest, $filename);
|
||||
$this->wire('files')->chmod($filename);
|
||||
return true;
|
||||
} else {
|
||||
// it was created a temp diskfile but not with all data in it
|
||||
@@ -1540,8 +1540,8 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
||||
|
||||
// all went well, copy back the temp file, remove the temp file
|
||||
if(!@copy($this->tmpFile, $this->filename)) return false; // fallback or failed
|
||||
wireChmod($this->filename);
|
||||
@unlink($this->tmpFile);
|
||||
$this->wire('files')->chmod($this->filename);
|
||||
$this->wire('files')->unlink($this->tmpFile);
|
||||
|
||||
// post processing: IPTC, setModified and reload ImageInfo
|
||||
$this->writeBackIPTC($this->filename, false);
|
||||
@@ -1590,13 +1590,13 @@ abstract class ImageSizerEngine extends WireData implements Module, Configurable
|
||||
if($result) {
|
||||
// success
|
||||
if($tmpFilename != $dstFilename) {
|
||||
if(is_file($dstFilename)) unlink($dstFilename);
|
||||
rename($tmpFilename, $dstFilename);
|
||||
if(is_file($dstFilename)) $this->wire('files')->unlink($dstFilename);
|
||||
$this->wire('files')->rename($tmpFilename, $dstFilename);
|
||||
}
|
||||
wireChmod($dstFilename);
|
||||
$this->wire('files')->chmod($dstFilename);
|
||||
} else {
|
||||
// fail
|
||||
if(is_file($tmpFilename)) unlink($tmpFilename);
|
||||
if(is_file($tmpFilename)) $this->wire('files')->unlink($tmpFilename);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@@ -2068,6 +2068,7 @@ class Modules extends WireArray {
|
||||
$success = false;
|
||||
$reason = $this->isDeleteable($class, true);
|
||||
if($reason !== true) throw new WireException($reason);
|
||||
$siteModulesPath = $this->wire('config')->paths->siteModules;
|
||||
|
||||
$filename = $this->installable[$class];
|
||||
$basename = basename($filename);
|
||||
@@ -2161,7 +2162,7 @@ class Modules extends WireArray {
|
||||
foreach($files as $file) {
|
||||
$file = "$path/$file";
|
||||
if(!file_exists($file)) continue;
|
||||
if(unlink($file)) {
|
||||
if($this->wire('files')->unlink($file, $siteModulesPath)) {
|
||||
$this->message("Removed file: $file", Notice::debug);
|
||||
} else {
|
||||
$this->error("Unable to remove file: $file", Notice::debug);
|
||||
|
@@ -952,7 +952,7 @@ class Pagefile extends WireData {
|
||||
*/
|
||||
public function unlink() {
|
||||
if(!strlen($this->basename) || !is_file($this->filename)) return true;
|
||||
return unlink($this->filename);
|
||||
return $this->wire('files')->unlink($this->filename, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -968,7 +968,7 @@ class Pagefile extends WireData {
|
||||
*/
|
||||
public function rename($basename) {
|
||||
$basename = $this->pagefiles->cleanBasename($basename, true);
|
||||
if(rename($this->filename, $this->pagefiles->path . $basename)) {
|
||||
if($this->wire('files')->rename($this->filename, $this->pagefiles->path . $basename, true)) {
|
||||
$this->set('basename', $basename);
|
||||
return $this->basename();
|
||||
}
|
||||
|
@@ -318,16 +318,16 @@ class PagefilesManager extends Wire {
|
||||
$errors = 0;
|
||||
if($recursive) {
|
||||
// clear out path and everything below it
|
||||
if(!wireRmdir($path, true)) $errors++;
|
||||
if(!$this->wire('files')->rmdir($path, true, true)) $errors++;
|
||||
if(!$rmdir) $this->_createPath($path);
|
||||
} else {
|
||||
// only clear out files in path
|
||||
foreach(new \DirectoryIterator($path) as $file) {
|
||||
if($file->isDot() || $file->isDir()) continue;
|
||||
if(!unlink($file->getPathname())) $errors++;
|
||||
if(!$this->wire('files')->unlink($file->getPathname(), true)) $errors++;
|
||||
}
|
||||
if($rmdir) {
|
||||
@rmdir($path); // will not be successful if other dirs within it
|
||||
$this->wire('files')->rmdir($path, false, true); // will not be successful if other dirs within it
|
||||
}
|
||||
}
|
||||
return $errors === 0;
|
||||
|
@@ -701,8 +701,8 @@ class Pageimage extends Pagefile {
|
||||
if(!$exists || $options['forceNew']) {
|
||||
// filenameUnvalidated is temporary filename used for resize
|
||||
$filenameUnvalidated = $this->pagefiles->page->filesManager()->getTempPath() . $basename;
|
||||
if($exists && $options['forceNew']) @unlink($filenameFinal);
|
||||
if(file_exists($filenameUnvalidated)) @unlink($filenameUnvalidated);
|
||||
if($exists && $options['forceNew']) $this->wire('files')->unlink($filenameFinal, true);
|
||||
if(file_exists($filenameUnvalidated)) $this->wire('files')->unlink($filenameUnvalidated, true);
|
||||
if(@copy($this->filename(), $filenameUnvalidated)) {
|
||||
try {
|
||||
|
||||
@@ -760,8 +760,8 @@ class Pageimage extends Pagefile {
|
||||
// if an error occurred, that error property will be populated with details
|
||||
if($this->error) {
|
||||
// error condition: unlink copied file
|
||||
if(is_file($filenameFinal)) @unlink($filenameFinal);
|
||||
if($filenameUnvalidated && is_file($filenameUnvalidated)) @unlink($filenameUnvalidated);
|
||||
if(is_file($filenameFinal)) $this->wire('files')->unlink($filenameFinal, true);
|
||||
if($filenameUnvalidated && is_file($filenameUnvalidated)) $this->wire('files')->unlink($filenameUnvalidated);
|
||||
|
||||
// write an invalid image so it's clear something failed
|
||||
// todo: maybe return a 1-pixel blank image instead?
|
||||
@@ -1235,7 +1235,7 @@ class Pageimage extends Pagefile {
|
||||
// rebuild the variation
|
||||
$o['forceNew'] = true;
|
||||
$o['suffix'] = $info['suffix'];
|
||||
if(is_file($info['path'])) unlink($info['path']);
|
||||
if(is_file($info['path'])) $this->wire('files')->unlink($info['path'], true);
|
||||
|
||||
/*
|
||||
if(!$info['width'] && $info['actualWidth']) {
|
||||
@@ -1477,7 +1477,7 @@ class Pageimage extends Pagefile {
|
||||
$variations = $this->getVariations();
|
||||
|
||||
foreach($variations as $variation) {
|
||||
if(is_file($variation->filename)) unlink($variation->filename);
|
||||
if(is_file($variation->filename)) $this->wire('files')->unlink($variation->filename, true);
|
||||
}
|
||||
|
||||
$this->variations = null;
|
||||
|
@@ -96,7 +96,7 @@ class PagesExportImport extends Wire {
|
||||
$qty++;
|
||||
}
|
||||
} else {
|
||||
if(unlink($pathname)) {
|
||||
if($files->unlink($pathname, true)) {
|
||||
$this->message($this->_('Removed old file') . " - $pathname", Notice::debug);
|
||||
$qty++;
|
||||
}
|
||||
@@ -151,8 +151,9 @@ class PagesExportImport extends Wire {
|
||||
'allowHidden' => false,
|
||||
'allowEmptyDirs' => false
|
||||
));
|
||||
if($zipInfo) {} // ignore
|
||||
|
||||
unlink($jsonFile);
|
||||
$files->unlink($jsonFile, true);
|
||||
|
||||
return $zipName;
|
||||
}
|
||||
|
@@ -668,7 +668,7 @@ class WireDatabaseBackup {
|
||||
$success = false;
|
||||
if($file && file_exists($file)) {
|
||||
if(!filesize($file)) {
|
||||
unlink($file);
|
||||
$this->wire('files')->unlink($file, true);
|
||||
} else {
|
||||
$success = true;
|
||||
}
|
||||
@@ -904,7 +904,7 @@ class WireDatabaseBackup {
|
||||
|
||||
if(file_exists($file)) {
|
||||
if(filesize($file) > 0) return $file;
|
||||
unlink($file);
|
||||
$this->wire('files')->unlink($file);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@@ -29,7 +29,7 @@ class WireFileTools extends Wire {
|
||||
* // directory created: /site/assets/cache/foo-bar/
|
||||
* }
|
||||
* ~~~~~
|
||||
*
|
||||
*
|
||||
* @param string $path Directory you want to create
|
||||
* @param bool|string $recursive If set to true, all directories will be created as needed to reach the end.
|
||||
* @param string|null|bool $chmod Optional mode to set directory to (default: $config->chmodDir), format must be a string i.e. "0755"
|
||||
@@ -65,31 +65,54 @@ class WireFileTools extends Wire {
|
||||
* for the `$recursive` argument. You should be careful with this option, as it can easily wipe out an entire
|
||||
* directory tree in a flash.
|
||||
*
|
||||
* Note that the $options argument was added in 3.0.118.
|
||||
*
|
||||
* ~~~~~
|
||||
* // Remove directory /site/assets/cache/foo-bar/ and everything in it
|
||||
* $files->rmdir($config->paths->cache . 'foo-bar/', true);
|
||||
* $files->rmdir($config->paths->cache . 'foo-bar/', true);
|
||||
*
|
||||
* // Remove directory after ensuring $pathname is somewhere within /site/assets/
|
||||
* $files->rmdir($pathname, true, [ 'limitPath' => $config->paths->assets ]);
|
||||
* ~~~~~
|
||||
*
|
||||
* @param string $path Path/directory you want to remove
|
||||
* @param bool $recursive If set to true, all files and directories in $path will be recursively removed as well (default=false).
|
||||
* @param array|bool|string $options Optional settings to adjust behavior or (bool|string) for limitPath option:
|
||||
* - `limitPath` (string|bool|array): Must be somewhere within given path, boolean true for site assets, or false to disable (default=false).
|
||||
* - `throw` (bool): Throw verbose WireException (rather than return false) when potentially consequential fail (default=false).
|
||||
* @return bool True on success, false on failure
|
||||
*
|
||||
*/
|
||||
public function rmdir($path, $recursive = false) {
|
||||
public function rmdir($path, $recursive = false, $options = array()) {
|
||||
|
||||
$defaults = array(
|
||||
'limitPath' => false,
|
||||
'throw' => false,
|
||||
);
|
||||
|
||||
if(!is_array($options)) $options = array('limitPath' => $options);
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
// if there's nothing to remove, exit now
|
||||
if(!is_dir($path)) return false;
|
||||
if(!strlen(trim($path, '/.'))) return false; // just for safety, don't proceed with empty string
|
||||
|
||||
// verify that path is allowed for this operation
|
||||
if(!$this->allowPath($path, $options['limitPath'], $options['throw'])) return false;
|
||||
|
||||
// handle recursive rmdir
|
||||
if($recursive === true) {
|
||||
$files = @scandir($path);
|
||||
if(is_array($files)) foreach($files as $file) {
|
||||
if($file == '.' || $file == '..') continue;
|
||||
if($file == '.' || $file == '..' || strpos($file, '..') !== false) continue;
|
||||
$pathname = "$path/$file";
|
||||
if(is_dir($pathname)) {
|
||||
$this->rmdir($pathname, true);
|
||||
$this->rmdir($pathname, $recursive, $options);
|
||||
} else {
|
||||
@unlink($pathname);
|
||||
$this->unlink($pathname, $options['limitPath'], $options['throw']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return @rmdir($path);
|
||||
}
|
||||
|
||||
@@ -109,7 +132,7 @@ class WireFileTools extends Wire {
|
||||
* // Update the mode of /site/assets/cache/foo-bar/ recursively
|
||||
* $files->chmod($config->paths->cache . 'foo-bar/', true);
|
||||
* ~~~~~
|
||||
*
|
||||
*
|
||||
* @param string $path Path or file that you want to adjust mode for (may be a path/directory or a filename).
|
||||
* @param bool|string $recursive If set to true, all files and directories in $path will be recursively set as well (default=false).
|
||||
* @param string|null|bool $chmod If you want to set the mode to something other than ProcessWire's chmodFile/chmodDir settings,
|
||||
@@ -176,16 +199,19 @@ class WireFileTools extends Wire {
|
||||
* // Copy everything from /site/assets/cache/foo/ to /site/assets/cache/bar/
|
||||
* $copyFrom = $config->paths->cache . "foo/";
|
||||
* $copyTo = $config->paths->cache . "bar/";
|
||||
* copy($copyFrom, $copyTo);
|
||||
* $files->copy($copyFrom, $copyTo);
|
||||
* ~~~~~
|
||||
*
|
||||
*
|
||||
* @param string $src Path to copy files from, or filename to copy.
|
||||
* @param string $dst Path (or filename) to copy file(s) to. Directory is created if it doesn't already exist.
|
||||
* @param bool|array $options Array of options:
|
||||
* - `recursive` (boolean): Whether to copy directories within recursively. (default=true)
|
||||
* - `allowEmptyDirs` (boolean): Copy directories even if they are empty? (default=true)
|
||||
* - If a boolean is specified for $options, it is assumed to be the 'recursive' option.
|
||||
* - `limitPath` (bool|string|array): Limit copy to within path given here, or true for site assets path (default=false).
|
||||
* - Note that the limitPath option was added in 3.0.118.
|
||||
* - If a boolean is specified for $options, it is assumed to be the `recursive` option.
|
||||
* @return bool True on success, false on failure.
|
||||
* @throws WireException if `limitPath` option is used and either $src or $dst is not allowed
|
||||
*
|
||||
*/
|
||||
public function copy($src, $dst, $options = array()) {
|
||||
@@ -193,10 +219,16 @@ class WireFileTools extends Wire {
|
||||
$defaults = array(
|
||||
'recursive' => true,
|
||||
'allowEmptyDirs' => true,
|
||||
'limitPath' => false,
|
||||
);
|
||||
|
||||
if(is_bool($options)) $options = array('recursive' => $options);
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
if($options['limitPath'] !== false) {
|
||||
$this->allowPath($src, $options['limitPath'], true);
|
||||
$this->allowPath($dst, $options['limitPath'], true);
|
||||
}
|
||||
|
||||
if(!is_dir($src)) {
|
||||
// just copy a file
|
||||
@@ -250,6 +282,220 @@ class WireFileTools extends Wire {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink/delete file with additional protections relative to PHP unlink()
|
||||
*
|
||||
* - This method requires a full pathname to a file to unlink and does not
|
||||
* accept any kind of relative path traversal.
|
||||
*
|
||||
* - This method will only unlink files in /site/assets/ if you specify `true`
|
||||
* for the `$limitPath` option (recommended).
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string|bool $limitPath Limit only to files within some starting path? (default=false)
|
||||
* - Boolean true to limit unlink operations to somewhere within /site/assets/ (only known always writable path).
|
||||
* - Boolean false to disable to security feature. (default)
|
||||
* - An alternative path (string) that represents the starting path (full disk path) to limit deletions to.
|
||||
* - An array with multiple of the above string option.
|
||||
* @param bool $throw Throw exception on error?
|
||||
* @return bool True on success, false on fail
|
||||
* @throws WireException If file is not allowed to be removed or unlink fails
|
||||
* @since 3.0.118
|
||||
*
|
||||
*/
|
||||
public function unlink($filename, $limitPath = false, $throw = false) {
|
||||
|
||||
if(!$this->allowPath($filename, $limitPath, $throw)) {
|
||||
// path not allowed
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!is_file($filename) && !is_link($filename)) {
|
||||
// only files or links (that exist) can be deleted
|
||||
return false;
|
||||
}
|
||||
|
||||
if(@unlink($filename)) {
|
||||
return true;
|
||||
} else {
|
||||
if($throw) throw new WireException("Unable to unlink file $filename");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename a file or directory and update permissions
|
||||
*
|
||||
* Note that this method will fail if pathname given by $newName argument already exists.
|
||||
*
|
||||
* @param string $oldName Old pathname, must be full disk path.
|
||||
* @param string $newName New pathname, must be full disk path OR can be basename to assume same path as $oldName.
|
||||
* @param array|bool|string $options Options array to modify behavior or substitute `limitPath` (bool or string) option here.
|
||||
* - `limitPath` (bool|string|array): Limit renames to within this path, or boolean TRUE for site/assets, or FALSE to disable (default=false).
|
||||
* - `throw` (bool): Throw WireException with verbose details on error? (default=false)
|
||||
* - `chmod` (bool): Adjust permissions to be consistent with $config after rename? (default=true)
|
||||
* - If given a bool or string for $options the `limitPath` option is assumed.
|
||||
* @return bool True on success, false on fail (or WireException if throw option specified).
|
||||
* @throws WireException If error occurs and $throw argument was true.
|
||||
* @since 3.0.118
|
||||
*
|
||||
*/
|
||||
public function rename($oldName, $newName, $options = array()) {
|
||||
|
||||
$defaults = array(
|
||||
'limitPath' => false,
|
||||
'throw' => false,
|
||||
'chmod' => true,
|
||||
);
|
||||
|
||||
if(!is_array($options)) $options = array('limitPath' => $options);
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
// if only basename was specified for the newName then use path from oldName
|
||||
if(basename($newName) === $newName) {
|
||||
$newName = dirname($oldName) . '/' . $newName;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->allowPath($oldName, $options['limitPath'], true);
|
||||
} catch(\Exception $e) {
|
||||
if($options['throw']) throw new WireException("Rename oldName path invalid: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->allowPath($newName, $options['limitPath'], true);
|
||||
} catch(\Exception $e) {
|
||||
if($options['throw']) throw new WireException("Rename newName path invalid: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!file_exists($oldName)) {
|
||||
if($options['throw']) throw new WireException("Rename given pathname (oldName) that does not exist: $oldName");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(file_exists($newName)) {
|
||||
if($options['throw']) throw new WireException("Rename to pathname (newName) that already exists: $newName");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!rename($oldName, $newName)) {
|
||||
if($options['throw']) throw new WireException("Rename failed: $oldName => $newName");
|
||||
}
|
||||
|
||||
if($options['chmod']) {
|
||||
$this->chmod($newName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow path or filename to to be used for file manipulation actions?
|
||||
*
|
||||
* Given path must be a full path (no relative references). If given a $limitPath, it must be a
|
||||
* directory that already exists.
|
||||
*
|
||||
* Note that this method does not indicate whether or not the given pathname exists, only that it is allowed.
|
||||
* As a result this can be used for checking a path before creating something in it too.
|
||||
*
|
||||
* #pw-internal
|
||||
*
|
||||
* @param string $pathname File or directory name to check
|
||||
* @param bool|string|array $limitPath Any one of the following (default=false):
|
||||
* - Full disk path (string) that $pathname must be within (whether directly or in subdirectory of).
|
||||
* - Array of the above.
|
||||
* - Boolean false to disable (default).
|
||||
* - Boolean true for site assets path, which is the only known always-writable path in PW.
|
||||
* @param bool $throw Throw verbose exceptions on error? (default=false).
|
||||
* @return bool True if given pathname allowed, false if not.
|
||||
* @throws WireException when $throw argument is true and function would otherwise return false.
|
||||
* @since 3.0.118
|
||||
*
|
||||
*/
|
||||
public function allowPath($pathname, $limitPath = false, $throw = false) {
|
||||
|
||||
if(is_array($limitPath)) {
|
||||
// run allowPath() for each of the specified limitPaths
|
||||
$allow = false;
|
||||
foreach($limitPath as $dir) {
|
||||
if(!is_string($dir) || empty($dir)) continue;
|
||||
$allow = $this->allowPath($pathname, $dir, false);
|
||||
if($allow) break; // found one that is allowed
|
||||
}
|
||||
if(!$allow && $throw) {
|
||||
throw new WireException("Given pathname is not within any of the paths allowed by limitPath");
|
||||
}
|
||||
return $allow;
|
||||
|
||||
} else if($limitPath === true) {
|
||||
// default limitPath
|
||||
$limitPath = $this->wire('config')->paths->assets;
|
||||
|
||||
} else if($limitPath === false) {
|
||||
// no limitPath in use
|
||||
|
||||
} else if(empty($limitPath) || !is_string($limitPath)) {
|
||||
// invalid limitPath argument (wrong type or path does not exist)
|
||||
if($throw) throw new WireException("Invalid type for limitPath argument");
|
||||
return false;
|
||||
|
||||
} else if(!is_dir($limitPath)) {
|
||||
if($throw) throw new WireException("$limitPath (limitPath) does not exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
if($limitPath !== false) try {
|
||||
// if limitPath can't pass allowPath then neither can $pathname
|
||||
$this->allowPath($limitPath, false, true);
|
||||
} catch(\Exception $e) {
|
||||
if($throw) throw new WireException("Validating limitPath reported: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(DIRECTORY_SEPARATOR != '/') {
|
||||
$pathname = str_replace(DIRECTORY_SEPARATOR, '/', $pathname);
|
||||
if(is_string($limitPath)) $limitPath = str_replace(DIRECTORY_SEPARATOR, '/', $limitPath);
|
||||
$testname = $pathname;
|
||||
if(strpos($pathname, ':')) list(,$testname) = explode(':', $pathname, 2); // reduce to no drive letter, if present
|
||||
} else {
|
||||
$testname = $pathname;
|
||||
}
|
||||
|
||||
if(!strlen(trim($testname, '/.')) || substr_count($testname, '/') < 2) {
|
||||
// do not allow paths that consist of nothing but slashes and/or dots
|
||||
// and do not allow paths off root or lacking absolute path reference
|
||||
if($throw) throw new WireException("pathname not allowed: $pathname");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(strpos($pathname, '..') !== false) {
|
||||
// not allowed to traverse anywhere
|
||||
if($throw) throw new WireException('pathname may not traverse “../”');
|
||||
return false;
|
||||
}
|
||||
|
||||
if(strpos($pathname, '.') === 0 || empty($pathname)) {
|
||||
if($throw) throw new WireException('pathname may not begin with “.”');
|
||||
return false;
|
||||
}
|
||||
|
||||
if(strpos($pathname, '//') !== false) {
|
||||
// URLs or accidental extra slashes not allowed
|
||||
if($throw) throw new WireException('pathname may not contain double slash “//”');
|
||||
return false;
|
||||
}
|
||||
|
||||
if($limitPath !== false && strpos($pathname, $limitPath) !== 0) {
|
||||
// disallow paths that do not begin with limitPath (i.e. /path/to/public_html/site/assets/)
|
||||
if($throw) throw new WireException("Given pathname is not within $limitPath (limitPath)");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new temporary directory/path ready to use for files
|
||||
*
|
||||
@@ -360,6 +606,8 @@ class WireFileTools extends Wire {
|
||||
* // $items is an array of filenames that were unzipped into $dst
|
||||
* }
|
||||
* ~~~~~
|
||||
*
|
||||
* #pw-group-archives
|
||||
*
|
||||
* @param string $file ZIP file to extract
|
||||
* @param string $dst Directory where files should be unzipped into. Directory is created if it doesn't exist.
|
||||
@@ -424,6 +672,8 @@ class WireFileTools extends Wire {
|
||||
* }
|
||||
* }
|
||||
* ~~~~~
|
||||
*
|
||||
* #pw-group-archives
|
||||
*
|
||||
* @param string $zipfile Full path and filename to create or update (i.e. /path/to/myfile.zip)
|
||||
* @param array|string $files Array of files to add (full path and filename), or directory (string) to add.
|
||||
@@ -474,7 +724,7 @@ class WireFileTools extends Wire {
|
||||
if(!is_dir($zippath)) throw new WireException("Path for ZIP file ($zippath) does not exist");
|
||||
if(!is_writable($zippath)) throw new WireException("Path for ZIP file ($zippath) is not writable");
|
||||
if(empty($files)) throw new WireException("Nothing to add to ZIP file $zipfile");
|
||||
if(is_file($zipfile) && $options['overwrite'] && !unlink($zipfile)) throw new WireException("Unable to overwrite $zipfile");
|
||||
if(is_file($zipfile) && $options['overwrite'] && !$this->unlink($zipfile)) throw new WireException("Unable to overwrite $zipfile");
|
||||
if(!is_array($files)) $files = array($files);
|
||||
if(!is_array($options['exclude'])) $options['exclude'] = array($options['exclude']);
|
||||
$recursive = false;
|
||||
@@ -547,6 +797,7 @@ class WireFileTools extends Wire {
|
||||
*
|
||||
*/
|
||||
public function send($filename, array $options = array(), array $headers = array()) {
|
||||
$this->allowPath($filename, false, true);
|
||||
$http = new WireHttp();
|
||||
$http->sendFile($filename, $options, $headers);
|
||||
}
|
||||
@@ -563,9 +814,11 @@ class WireFileTools extends Wire {
|
||||
* - `FILE_APPEND` (constant): Append to file if it already exists .
|
||||
* - `LOCK_EX` (constant): Acquire exclusive lock to file while writing.
|
||||
* @return int|bool Number of bytes written or boolean false on fail
|
||||
* @throws WireException if given invalid $filename (since 3.0.118)
|
||||
*
|
||||
*/
|
||||
public function filePutContents($filename, $contents, $flags = 0) {
|
||||
$this->allowPath($filename, false, true);
|
||||
$result = file_put_contents($filename, $contents, $flags);
|
||||
if($result !== false) $this->chmod($filename);
|
||||
return $result;
|
||||
@@ -585,6 +838,8 @@ class WireFileTools extends Wire {
|
||||
*
|
||||
* Note this function returns the output to you, so that you can send the output wherever you want (delayed output).
|
||||
* For direct output, use the `$files->include()` function instead.
|
||||
*
|
||||
* #pw-group-includes
|
||||
*
|
||||
* @param string $filename Assumed relative to /site/templates/ unless you provide a full path name with the filename.
|
||||
* If you provide a path, it must resolve somewhere in site/templates/, site/modules/ or wire/modules/.
|
||||
@@ -671,7 +926,6 @@ class WireFileTools extends Wire {
|
||||
return $t->render();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Include a PHP file passing it all API variables and optionally your own specified variables
|
||||
*
|
||||
@@ -684,6 +938,8 @@ class WireFileTools extends Wire {
|
||||
*
|
||||
* Note this function produces direct output. To retrieve output as a return value, use the
|
||||
* `$files->render()` function instead.
|
||||
*
|
||||
* #pw-group-includes
|
||||
*
|
||||
* @param string $filename Filename to include
|
||||
* @param array $vars Optional variables you want to hand to the include (associative array)
|
||||
@@ -770,6 +1026,8 @@ class WireFileTools extends Wire {
|
||||
*
|
||||
* See the `WireFileTools::include()` method for details, arguments and options.
|
||||
*
|
||||
* #pw-group-includes
|
||||
*
|
||||
* @param string $filename
|
||||
* @param array $vars
|
||||
* @param array $options
|
||||
@@ -884,7 +1142,7 @@ class WireFileTools extends Wire {
|
||||
/**
|
||||
* Compile the given file using ProcessWire’s file compiler
|
||||
*
|
||||
* #pw-group-compiler
|
||||
* #pw-internal
|
||||
*
|
||||
* @param string $file File to compile
|
||||
* @param array $options Optional associative array of the following:
|
||||
@@ -916,7 +1174,7 @@ class WireFileTools extends Wire {
|
||||
/**
|
||||
* Compile and include() the given file
|
||||
*
|
||||
* #pw-group-compiler
|
||||
* #pw-internal
|
||||
*
|
||||
* @param string $file File to compile and include
|
||||
* @param array $options Optional associative array of the following:
|
||||
@@ -937,7 +1195,7 @@ class WireFileTools extends Wire {
|
||||
/**
|
||||
* Compile and include_once() the given file
|
||||
*
|
||||
* #pw-group-compiler
|
||||
* #pw-group-internal
|
||||
*
|
||||
* @param string $file File to compile and include
|
||||
* @param array $options Optional associative array of the following:
|
||||
@@ -958,7 +1216,7 @@ class WireFileTools extends Wire {
|
||||
/**
|
||||
* Compile and require() the given file
|
||||
*
|
||||
* #pw-group-compiler
|
||||
* #pw-internal
|
||||
*
|
||||
* @param string $file File to compile and include
|
||||
* @param array $options Optional associative array of the following:
|
||||
@@ -979,7 +1237,7 @@ class WireFileTools extends Wire {
|
||||
/**
|
||||
* Compile and require_once() the given file
|
||||
*
|
||||
* #pw-group-compiler
|
||||
* #pw-internal
|
||||
*
|
||||
* @param string $file File to compile and include
|
||||
* @param array $options Optional associative array of the following:
|
||||
@@ -1000,6 +1258,8 @@ class WireFileTools extends Wire {
|
||||
/**
|
||||
* Convert given directory name to use unix slashes and enforce trailing or no-trailing slash
|
||||
*
|
||||
* #pw-group-filenames
|
||||
*
|
||||
* @param string $dir Directory name to adust (if it needs it)
|
||||
* @param bool $trailingSlash True to force trailing slash, false to force no trailing slash (default=true)
|
||||
* @return string Adjusted directory name
|
||||
@@ -1016,6 +1276,8 @@ class WireFileTools extends Wire {
|
||||
|
||||
/**
|
||||
* Convert given file name to use unix slashes (if it isn’t already)
|
||||
*
|
||||
* #pw-group-filenames
|
||||
*
|
||||
* @param string $file File name to adjust (if it needs it)
|
||||
* @return string Adjusted file name
|
||||
@@ -1029,7 +1291,9 @@ class WireFileTools extends Wire {
|
||||
* Is given $file name in given $path name? (aka: is $file a subdirectory somewhere within $path)
|
||||
*
|
||||
* This is purely for string comparison purposes, it does not check if file/path actually exists.
|
||||
* Note that if $file and $path are identical, this method returns false.
|
||||
* Note that if $file and $path are identical, this method returns false.
|
||||
*
|
||||
* #pw-group-filenames
|
||||
*
|
||||
* @param string $file May be a file or a directory
|
||||
* @param string $path
|
||||
|
@@ -744,16 +744,15 @@ class WireHttp extends Wire {
|
||||
|
||||
$methods = implode(", ", $triedMethods);
|
||||
if(count($this->error) || ($this->httpCode >= 400 && isset($this->httpCodes[$this->httpCode]))) {
|
||||
unlink($toFile);
|
||||
$this->wire('files')->unlink($toFile);
|
||||
$error = $this->_('File could not be downloaded') . ' ' . htmlentities("($fromURL) ") . $this->getError() . " (tried: $methods)";
|
||||
throw new WireException($error);
|
||||
} else {
|
||||
$bytes = filesize($toFile);
|
||||
$this->message("Downloaded " . htmlentities($fromURL) . " => $toFile (using: $methods) [$bytes bytes]", Notice::debug);
|
||||
}
|
||||
|
||||
$chmodFile = $this->wire('config')->chmodFile;
|
||||
if($chmodFile) chmod($toFile, octdec($chmodFile));
|
||||
|
||||
$this->wire('files')->chmod($toFile);
|
||||
|
||||
return $toFile;
|
||||
}
|
||||
|
@@ -369,8 +369,8 @@ class WireTempDir extends Wire {
|
||||
$dir = $this->wire('files')->unixDirName($dir);
|
||||
if(!strlen($dir) || !is_dir($dir)) return true;
|
||||
if(!$this->isTempDir($dir)) return false;
|
||||
if(is_file($dir . self::hiddenFileName)) unlink($dir . self::hiddenFileName);
|
||||
return $this->wire('files')->rmdir($dir, $recursive);
|
||||
if(is_file($dir . self::hiddenFileName)) $this->wire('files')->unlink($dir . self::hiddenFileName, true);
|
||||
return $this->wire('files')->rmdir($dir, $recursive, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -179,7 +179,7 @@ class WireUpload extends Wire {
|
||||
public function __destruct() {
|
||||
// cleanup files that were backed up when overwritten
|
||||
foreach($this->overwrittenFiles as $bakDestination => $destination) {
|
||||
if(is_file($bakDestination)) unlink($bakDestination);
|
||||
if(is_file($bakDestination)) $this->wire('files')->unlink($bakDestination);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,7 +491,7 @@ class WireUpload extends Wire {
|
||||
if(!$destination || !$filename) $destination = $this->destinationPath . 'invalid-filename';
|
||||
if(!$error) $error = "Unable to move uploaded file to: $destination";
|
||||
$this->error($error);
|
||||
if(is_file($tmp_name)) @unlink($tmp_name);
|
||||
if(is_file($tmp_name)) $this->wire('files')->unlink($tmp_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -533,7 +533,7 @@ class WireUpload extends Wire {
|
||||
} catch(\Exception $e) {
|
||||
$this->error($e->getMessage());
|
||||
$this->wire('files')->rmdir($tmpDir, true);
|
||||
unlink($zipFile);
|
||||
$this->wire('files')->unlink($zipFile);
|
||||
return $files;
|
||||
}
|
||||
|
||||
@@ -544,7 +544,7 @@ class WireUpload extends Wire {
|
||||
$pathname = $tmpDir . $file;
|
||||
|
||||
if(!$this->isValidUpload($file, filesize($pathname), UPLOAD_ERR_OK)) {
|
||||
@unlink($pathname);
|
||||
$this->wire('files')->unlink($pathname, $tmpDir);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -574,12 +574,12 @@ class WireUpload extends Wire {
|
||||
$this->completedFilenames[] = basename($destination);
|
||||
$cnt++;
|
||||
} else {
|
||||
@unlink($pathname);
|
||||
$this->wire('files')->unlink($pathname, $tmpDir);
|
||||
}
|
||||
}
|
||||
|
||||
$this->wire('files')->rmdir($tmpDir, true);
|
||||
@unlink($zipFile);
|
||||
$this->wire('files')->unlink($zipFile);
|
||||
|
||||
if(!$cnt) return false;
|
||||
return true;
|
||||
|
@@ -368,7 +368,7 @@ class ImageSizerEngineIMagick extends ImageSizerEngine {
|
||||
}
|
||||
|
||||
// save to file
|
||||
@unlink($dstFilename);
|
||||
$this->wire('files')->unlink($dstFilename);
|
||||
@clearstatcache(dirname($dstFilename));
|
||||
##if(!$this->im->writeImage($this->destFilename)) {
|
||||
// We use this approach for saving so that it behaves the same like core ImageSizer with images that
|
||||
|
@@ -760,8 +760,8 @@ class InputfieldFile extends Inputfield implements InputfieldItemList, Inputfiel
|
||||
$err = false;
|
||||
foreach($ul->getOverwrittenFiles() as $bakFile => $newFile) {
|
||||
if(basename($newFile) != $filename) continue;
|
||||
unlink($newFile);
|
||||
rename($bakFile, $newFile); // restore
|
||||
$this->wire('files')->unlink($newFile);
|
||||
$this->wire('files')->rename($bakFile, $newFile); // restore
|
||||
$ul->error(sprintf($this->_('Refused file %s because it is already on the file system and owned by a different field.'), $filename));
|
||||
$err = true;
|
||||
}
|
||||
|
@@ -439,8 +439,8 @@ class InputfieldImage extends InputfieldFile implements InputfieldItemList, Inpu
|
||||
}
|
||||
$pagefile2 = $pagefile->size($maxWidth, $maxHeight, array('cropping' => false));
|
||||
if($pagefile->filename != $pagefile2->filename) {
|
||||
unlink($pagefile->filename);
|
||||
rename($pagefile2->filename, $pagefile->filename);
|
||||
$this->wire('files')->unlink($pagefile->filename);
|
||||
$this->wire('files')->rename($pagefile2->filename, $pagefile->filename);
|
||||
}
|
||||
$pagefile->getImageInfo(true); // force it to reload its dimensions
|
||||
}
|
||||
@@ -510,7 +510,7 @@ class InputfieldImage extends InputfieldFile implements InputfieldItemList, Inpu
|
||||
$exists = is_file($f);
|
||||
|
||||
if($exists && $remove) {
|
||||
unlink($f);
|
||||
$this->wire('files')->unlink($f);
|
||||
$exists = false;
|
||||
}
|
||||
|
||||
|
@@ -648,7 +648,7 @@ class ProcessLanguageTranslator extends Process {
|
||||
|
||||
if(is_null($this->fp)) {
|
||||
$f = $this->language->filesManager()->path() . '.phrase-index.txt'; // @todo make hidden
|
||||
if(is_file($f)) unlink($f);
|
||||
if(is_file($f)) $this->wire('files')->unlink($f);
|
||||
$this->fp = fopen($f, "a");
|
||||
}
|
||||
|
||||
|
@@ -151,7 +151,7 @@ class LazyCron extends WireData implements Module {
|
||||
// other LazyCron process potentially running
|
||||
if(filemtime($lockfile) < (time() - 3600)) {
|
||||
// expired lock file, some fatal error must have occurred during last LazyCron run
|
||||
@unlink($lockfile);
|
||||
$this->wire('files')->unlink($lockfile);
|
||||
} else {
|
||||
// skip running this time as an active lock file exists
|
||||
return;
|
||||
@@ -168,7 +168,7 @@ class LazyCron extends WireData implements Module {
|
||||
|
||||
// file is probably locked, so skip it this time
|
||||
if($filedata === false) {
|
||||
@unlink($lockfile);
|
||||
$this->wire('files')->unlink($lockfile);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -210,7 +210,7 @@ class LazyCron extends WireData implements Module {
|
||||
if($this->config->chmodFile) @chmod($filename, octdec($this->config->chmodFile));
|
||||
}
|
||||
|
||||
@unlink($lockfile);
|
||||
$this->wire('files')->unlink($lockfile);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -743,10 +743,10 @@ class PageRender extends WireData implements Module, ConfigurableModule {
|
||||
foreach($d as $f) {
|
||||
if(!$f->isDir() && preg_match('/\.cache$/D', $f->getFilename())) {
|
||||
$numFiles++;
|
||||
@unlink($f->getPathname());
|
||||
$this->wire('files')->unlink($f->getPathname());
|
||||
}
|
||||
}
|
||||
@rmdir($file->getPathname());
|
||||
$this->wire('files')->rmdir($file->getPathname());
|
||||
}
|
||||
|
||||
if($clearNow) {
|
||||
|
@@ -234,13 +234,13 @@ class ProcessModuleInstall extends Wire {
|
||||
$mkdirDestination = false;
|
||||
|
||||
try {
|
||||
$files = wireUnzipFile($file, $tempDir);
|
||||
if(is_file($file)) unlink($file);
|
||||
$files = $this->wire('files')->unzip($file, $tempDir);
|
||||
if(is_file($file)) $this->wire('files')->unlink($file, true);
|
||||
foreach($files as $f) $this->message("Extracted: $f", Notice::debug);
|
||||
|
||||
} catch(\Exception $e) {
|
||||
$this->error($e->getMessage());
|
||||
if(is_file($file)) unlink($file);
|
||||
if(is_file($file)) $this->wire('files')->unlink($file, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ class ProcessModuleInstall extends Wire {
|
||||
|
||||
if(!$success) {
|
||||
$this->error($this->_('Unable to copy module files:') . ' ' . $dirLabel);
|
||||
if($mkdirDestination && !wireRmdir($destinationDir, true)) {
|
||||
if($mkdirDestination && !$this->wire('files')->rmdir($destinationDir, true)) {
|
||||
$this->error($this->_('Could not delete failed module dir:') . ' ' . $destinationDir, Notice::log);
|
||||
}
|
||||
}
|
||||
@@ -306,11 +306,13 @@ class ProcessModuleInstall extends Wire {
|
||||
// remove symbolic link
|
||||
unlink(rtrim($moduleDir, '/'));
|
||||
$dir = str_replace($this->wire('config')->paths->root, '/', $moduleDir);
|
||||
$this->error(sprintf($this->_('Please note that %s was a symbolic link and has been converted to a regular directory'), $dir), Notice::warning);
|
||||
$this->warning(sprintf(
|
||||
$this->_('Please note that %s was a symbolic link and has been converted to a regular directory'), $dir
|
||||
));
|
||||
} else {
|
||||
// module is a regular directory
|
||||
// just rename it to become the new backup dir
|
||||
if(rename($moduleDir, $backupDir)) $success = true;
|
||||
if($this->wire('files')->rename($moduleDir, $backupDir)) $success = true;
|
||||
}
|
||||
|
||||
if($success) {
|
||||
@@ -352,6 +354,7 @@ class ProcessModuleInstall extends Wire {
|
||||
|
||||
$tempDir = $this->getTempDir();
|
||||
|
||||
/** @var WireUpload $ul */
|
||||
$ul = $this->wire(new WireUpload($inputName));
|
||||
$ul->setValidExtensions(array('zip'));
|
||||
$ul->setMaxFiles(1);
|
||||
@@ -416,7 +419,7 @@ class ProcessModuleInstall extends Wire {
|
||||
|
||||
} catch(\Exception $e) {
|
||||
$this->error($e->getMessage());
|
||||
@unlink($tempZIP);
|
||||
$this->wire('files')->unlink($tempZIP);
|
||||
}
|
||||
|
||||
return $success ? $destinationDir : false;
|
||||
|
@@ -1154,15 +1154,15 @@ class ProcessPageEditImageSelect extends Process implements ConfigurableModule {
|
||||
$thumb = $thumb['thumb'];
|
||||
if($thumb->url != $original->url) {
|
||||
// there is a thumbnail, distinct from the original image
|
||||
unlink($thumb->filename);
|
||||
$this->wire('files')->unlink($thumb->filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// replace original image
|
||||
$target = $path . $this->original;
|
||||
unlink($target);
|
||||
rename($image2->filename(), $target);
|
||||
$this->wire('files')->unlink($target);
|
||||
$this->wire('files')->rename($image2->filename(), $target);
|
||||
|
||||
$this->wire('pages')->uncacheAll();
|
||||
$page = $this->wire('pages')->get($this->page->id);
|
||||
@@ -1365,7 +1365,7 @@ class ProcessPageEditImageSelect extends Process implements ConfigurableModule {
|
||||
foreach($delete as $name) {
|
||||
if(!isset($variations[$name])) continue;
|
||||
$info = $variations[$name];
|
||||
if(is_file($info['path']) && unlink($info['path'])) {
|
||||
if(is_file($info['path']) && $this->wire('files')->unlink($info['path'])) {
|
||||
$this->message($this->_('Deleted image variation') . " - $info[url]");
|
||||
unset($variations[$name]);
|
||||
} else {
|
||||
|
@@ -199,7 +199,7 @@ class ProcessPagesExportImport extends Process {
|
||||
if(!$zipFile || !is_file($zipFile)) throw new WireException('No ZIP file found: ' . $zipFile);
|
||||
$unzipPath = $this->exportImport->getExportPath('import-zip');
|
||||
$zipFileItems = $this->wire('files')->unzip($zipFile, $unzipPath);
|
||||
unlink($zipFile);
|
||||
$this->wire('files')->unlink($zipFile);
|
||||
if(empty($zipFileItems)) throw new WireException("No files found in ZIP");
|
||||
$jsonFile = $unzipPath . "pages.json";
|
||||
$this->wire('session')->setFor($this, 'filesPath', $unzipPath);
|
||||
@@ -1109,7 +1109,7 @@ class ProcessPagesExportImport extends Process {
|
||||
'forceDownload' => true,
|
||||
'exit' => false
|
||||
));
|
||||
unlink($zipFile);
|
||||
$this->wire('files')->unlink($zipFile);
|
||||
exit;
|
||||
} else {
|
||||
throw new WireException('Export failed during ZIP file generation');
|
||||
|
Reference in New Issue
Block a user