mirror of
https://github.com/processwire/processwire.git
synced 2025-08-10 16:54:44 +02:00
Minor optimizations and improvements to WireUpload class
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
* Saves uploads of single or multiple files, saving them to the destination path.
|
* Saves uploads of single or multiple files, saving them to the destination path.
|
||||||
* If the destination path does not exist, it will be created.
|
* If the destination path does not exist, it will be created.
|
||||||
*
|
*
|
||||||
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
* ProcessWire 3.x, Copyright 2023 by Ryan Cramer
|
||||||
* https://processwire.com
|
* https://processwire.com
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -141,6 +141,12 @@ class WireUpload extends Wire {
|
|||||||
*/
|
*/
|
||||||
protected $errorInfo = array();
|
protected $errorInfo = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $initialized = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct with the given input name
|
* Construct with the given input name
|
||||||
*
|
*
|
||||||
@@ -148,6 +154,29 @@ class WireUpload extends Wire {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function __construct($name) {
|
public function __construct($name) {
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->setName($name);
|
||||||
|
$this->maxFiles = 0; // no limit
|
||||||
|
$this->overwrite = false;
|
||||||
|
$this->destinationPath = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wired to API
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function wired() {
|
||||||
|
parent::wired();
|
||||||
|
$this->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function init() {
|
||||||
|
$this->initialized = true;
|
||||||
|
|
||||||
$this->errorInfo = array(
|
$this->errorInfo = array(
|
||||||
UPLOAD_ERR_OK => $this->_('Successful Upload'),
|
UPLOAD_ERR_OK => $this->_('Successful Upload'),
|
||||||
@@ -160,14 +189,11 @@ class WireUpload extends Wire {
|
|||||||
UPLOAD_ERR_EXTENSION => $this->_('File upload stopped by extension.')
|
UPLOAD_ERR_EXTENSION => $this->_('File upload stopped by extension.')
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->setName($name);
|
$config = $this->wire()->config;
|
||||||
$this->maxFiles = 0; // no limit
|
|
||||||
$this->overwrite = false;
|
|
||||||
$this->destinationPath = '';
|
|
||||||
|
|
||||||
if($this->config->uploadBadExtensions) {
|
if($config->uploadBadExtensions) {
|
||||||
$badExtensions = $this->config->uploadBadExtensions;
|
$badExtensions = $config->uploadBadExtensions;
|
||||||
if(is_string($badExtensions) && $badExtensions) $badExtensions = explode(' ', $badExtensions);
|
if(is_string($badExtensions) && strlen($badExtensions)) $badExtensions = explode(' ', $badExtensions);
|
||||||
if(is_array($badExtensions)) $this->badExtensions = $badExtensions;
|
if(is_array($badExtensions)) $this->badExtensions = $badExtensions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,7 +205,7 @@ class WireUpload extends Wire {
|
|||||||
public function __destruct() {
|
public function __destruct() {
|
||||||
// cleanup files that were backed up when overwritten
|
// cleanup files that were backed up when overwritten
|
||||||
foreach($this->overwrittenFiles as $bakDestination => $destination) {
|
foreach($this->overwrittenFiles as $bakDestination => $destination) {
|
||||||
if(is_file($bakDestination)) $this->wire('files')->unlink($bakDestination);
|
if(is_file($bakDestination)) $this->wire()->files->unlink($bakDestination);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,13 +218,14 @@ class WireUpload extends Wire {
|
|||||||
*/
|
*/
|
||||||
public function execute() {
|
public function execute() {
|
||||||
|
|
||||||
|
if(!$this->initialized) $this->init();
|
||||||
if(!$this->name) throw new WireException("You must set the name for WireUpload before executing it");
|
if(!$this->name) throw new WireException("You must set the name for WireUpload before executing it");
|
||||||
if(!$this->destinationPath) throw new WireException("You must set the destination path for WireUpload before executing it");
|
if(!$this->destinationPath) throw new WireException("You must set the destination path for WireUpload before executing it");
|
||||||
|
|
||||||
$files = array();
|
$uploadFiles = array();
|
||||||
|
|
||||||
$f = $this->getPhpFiles();
|
$f = $this->getPhpFiles();
|
||||||
if(!$f) return $files;
|
if(!$f) return $uploadFiles;
|
||||||
|
|
||||||
if(is_array($f['name'])) {
|
if(is_array($f['name'])) {
|
||||||
// multi file upload
|
// multi file upload
|
||||||
@@ -213,17 +240,17 @@ class WireUpload extends Wire {
|
|||||||
$cnt++;
|
$cnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
$files = $this->completedFilenames;
|
$uploadFiles = $this->completedFilenames;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// single file upload, including ajax
|
// single file upload, including ajax
|
||||||
if($this->isValidUpload($f['name'], $f['size'], $f['error'])) {
|
if($this->isValidUpload($f['name'], $f['size'], $f['error'])) {
|
||||||
$this->saveUpload($f['tmp_name'], $f['name'], !empty($f['ajax'])); // returns filename or false
|
$this->saveUpload($f['tmp_name'], $f['name'], !empty($f['ajax'])); // returns filename or false
|
||||||
$files = $this->completedFilenames;
|
$uploadFiles = $this->completedFilenames;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $files;
|
return $uploadFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -249,7 +276,7 @@ class WireUpload extends Wire {
|
|||||||
*/
|
*/
|
||||||
protected function getUploadDir() {
|
protected function getUploadDir() {
|
||||||
|
|
||||||
$config = $this->wire('config');
|
$config = $this->wire()->config;
|
||||||
$dir = $config->uploadTmpDir;
|
$dir = $config->uploadTmpDir;
|
||||||
|
|
||||||
if(!$dir && stripos(PHP_OS, 'WIN') === 0) {
|
if(!$dir && stripos(PHP_OS, 'WIN') === 0) {
|
||||||
@@ -283,8 +310,9 @@ class WireUpload extends Wire {
|
|||||||
*/
|
*/
|
||||||
protected function getPhpFilesAjax() {
|
protected function getPhpFilesAjax() {
|
||||||
|
|
||||||
if(!$filename = $_SERVER['HTTP_X_FILENAME']) return false;
|
if(empty($_SERVER['HTTP_X_FILENAME'])) return false;
|
||||||
$filename = rawurldecode($filename); // per #1487
|
|
||||||
|
$filename = rawurldecode($_SERVER['HTTP_X_FILENAME']); // per #1487
|
||||||
$dir = $this->getUploadDir();
|
$dir = $this->getUploadDir();
|
||||||
$tmpName = tempnam($dir, wireClassName($this, false));
|
$tmpName = tempnam($dir, wireClassName($this, false));
|
||||||
|
|
||||||
@@ -348,11 +376,12 @@ class WireUpload extends Wire {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected function isValidUpload($name, $size, $error) {
|
protected function isValidUpload($name, $size, $error) {
|
||||||
$valid = false;
|
|
||||||
$fname = $this->wire('sanitizer')->name($name);
|
$fname = $this->wire()->sanitizer->name($name);
|
||||||
|
|
||||||
if($error && $error != UPLOAD_ERR_NO_FILE) {
|
if($error && $error != UPLOAD_ERR_NO_FILE) {
|
||||||
$this->error($this->errorInfo[$error]);
|
$this->error($this->errorInfo[$error]);
|
||||||
|
$valid = false;
|
||||||
} else if(!$size) {
|
} else if(!$size) {
|
||||||
$valid = false; // no data
|
$valid = false; // no data
|
||||||
} else if($name[0] == '.') {
|
} else if($name[0] == '.') {
|
||||||
@@ -362,8 +391,10 @@ class WireUpload extends Wire {
|
|||||||
"$fname - " . $this->_('Invalid file extension, please use one of:') . ' ' .
|
"$fname - " . $this->_('Invalid file extension, please use one of:') . ' ' .
|
||||||
implode(', ', $this->validExtensions)
|
implode(', ', $this->validExtensions)
|
||||||
);
|
);
|
||||||
|
$valid = false;
|
||||||
} else if($this->maxFileSize > 0 && $size > $this->maxFileSize) {
|
} else if($this->maxFileSize > 0 && $size > $this->maxFileSize) {
|
||||||
$this->error("$fname - " . $this->_('Exceeds max allowed file size'));
|
$this->error("$fname - " . $this->_('Exceeds max allowed file size'));
|
||||||
|
$valid = false;
|
||||||
} else {
|
} else {
|
||||||
$valid = true;
|
$valid = true;
|
||||||
}
|
}
|
||||||
@@ -379,7 +410,7 @@ class WireUpload extends Wire {
|
|||||||
*/
|
*/
|
||||||
protected function checkDestinationPath() {
|
protected function checkDestinationPath() {
|
||||||
if(!is_dir($this->destinationPath)) {
|
if(!is_dir($this->destinationPath)) {
|
||||||
$this->error("Destination path does not exist {$this->destinationPath}");
|
$this->error("Destination path does not exist: $this->destinationPath");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -416,9 +447,11 @@ class WireUpload extends Wire {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function validateFilename($value, $extensions = array()) {
|
public function validateFilename($value, $extensions = array()) {
|
||||||
|
|
||||||
$value = basename($value);
|
$value = basename($value);
|
||||||
if($value[0] == '.') return false; // no hidden files
|
if($value[0] == '.') return false; // no hidden files
|
||||||
$value = $this->wire('sanitizer')->filename($value, Sanitizer::translate);
|
|
||||||
|
$value = $this->wire()->sanitizer->filename($value, Sanitizer::translate);
|
||||||
if($this->lowercase) $value = strtolower($value);
|
if($this->lowercase) $value = strtolower($value);
|
||||||
$value = trim($value, "_");
|
$value = trim($value, "_");
|
||||||
if(!strlen($value)) return false;
|
if(!strlen($value)) return false;
|
||||||
@@ -506,11 +539,11 @@ class WireUpload extends Wire {
|
|||||||
if(!$destination || !$filename) $destination = $this->destinationPath . 'invalid-filename';
|
if(!$destination || !$filename) $destination = $this->destinationPath . 'invalid-filename';
|
||||||
if(!$error) $error = "Unable to move uploaded file to: $destination";
|
if(!$error) $error = "Unable to move uploaded file to: $destination";
|
||||||
$this->error($error);
|
$this->error($error);
|
||||||
if(is_file($tmp_name)) $this->wire('files')->unlink($tmp_name);
|
if(is_file($tmp_name)) $this->wire()->files->unlink($tmp_name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->wire('files')->chmod($destination);
|
$this->wire()->files->chmod($destination);
|
||||||
|
|
||||||
if($p['extension'] == 'zip' && ($this->maxFiles == 0) && $this->extractArchives) {
|
if($p['extension'] == 'zip' && ($this->maxFiles == 0) && $this->extractArchives) {
|
||||||
if($this->saveUploadZip($destination)) {
|
if($this->saveUploadZip($destination)) {
|
||||||
@@ -536,30 +569,35 @@ class WireUpload extends Wire {
|
|||||||
|
|
||||||
// unzip with command line utility
|
// unzip with command line utility
|
||||||
|
|
||||||
|
$fileTools = $this->wire()->files;
|
||||||
$files = array();
|
$files = array();
|
||||||
$dir = dirname($zipFile) . '/';
|
$dir = dirname($zipFile) . '/';
|
||||||
$tmpDir = $dir . '.zip_tmp/';
|
$tmpDir = $dir . '.zip_tmp/';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$files = $this->wire('files')->unzip($zipFile, $tmpDir);
|
$files = $fileTools->unzip($zipFile, $tmpDir);
|
||||||
if(!count($files)) {
|
if(!count($files)) {
|
||||||
throw new WireException($this->_('No files found in ZIP file'));
|
throw new WireException($this->_('No files found in ZIP file'));
|
||||||
}
|
}
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
$this->error($e->getMessage());
|
$this->error($e->getMessage());
|
||||||
$this->wire('files')->rmdir($tmpDir, true);
|
$fileTools->rmdir($tmpDir, true);
|
||||||
$this->wire('files')->unlink($zipFile);
|
$fileTools->unlink($zipFile);
|
||||||
return $files;
|
return $files;
|
||||||
}
|
}
|
||||||
|
|
||||||
$cnt = 0;
|
$cnt = 0;
|
||||||
|
|
||||||
|
// allow files within ZIP to be up to 10x the size of max upload size
|
||||||
|
$maxFileSize = $this->maxFileSize;
|
||||||
|
$this->setMaxFileSize($maxFileSize * 10);
|
||||||
|
|
||||||
foreach($files as $file) {
|
foreach($files as $file) {
|
||||||
|
|
||||||
$pathname = $tmpDir . $file;
|
$pathname = $tmpDir . $file;
|
||||||
|
|
||||||
if(!$this->isValidUpload($file, filesize($pathname), UPLOAD_ERR_OK)) {
|
if(!$this->isValidUpload($file, filesize($pathname), UPLOAD_ERR_OK)) {
|
||||||
$this->wire('files')->unlink($pathname, $tmpDir);
|
$fileTools->unlink($pathname, $tmpDir);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -575,7 +613,7 @@ class WireUpload extends Wire {
|
|||||||
$bakDestination = $dir . $bakName;
|
$bakDestination = $dir . $bakName;
|
||||||
} while(file_exists($bakDestination));
|
} while(file_exists($bakDestination));
|
||||||
rename($destination, $bakDestination);
|
rename($destination, $bakDestination);
|
||||||
$this->wire('log')->message("Renamed $destination => $bakDestination");
|
$this->wire()->log->message("Renamed $destination => $bakDestination");
|
||||||
$this->overwrittenFiles[$bakDestination] = $destination;
|
$this->overwrittenFiles[$bakDestination] = $destination;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -589,15 +627,16 @@ class WireUpload extends Wire {
|
|||||||
$this->completedFilenames[] = basename($destination);
|
$this->completedFilenames[] = basename($destination);
|
||||||
$cnt++;
|
$cnt++;
|
||||||
} else {
|
} else {
|
||||||
$this->wire('files')->unlink($pathname, $tmpDir);
|
$fileTools->unlink($pathname, $tmpDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->wire('files')->rmdir($tmpDir, true);
|
$this->setMaxFileSize($maxFileSize); // restore original
|
||||||
$this->wire('files')->unlink($zipFile);
|
|
||||||
|
|
||||||
if(!$cnt) return false;
|
$fileTools->rmdir($tmpDir, true);
|
||||||
return true;
|
$fileTools->unlink($zipFile);
|
||||||
|
|
||||||
|
return $cnt > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -732,7 +771,7 @@ class WireUpload extends Wire {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function setName($name) {
|
public function setName($name) {
|
||||||
$this->name = $this->wire('sanitizer')->fieldName($name);
|
$this->name = $this->wire()->sanitizer->fieldName($name);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user