From 083b6b2164053b0680f42183ba431137fbe76485 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Tue, 5 Feb 2013 19:10:15 +0100 Subject: [PATCH] NEW Upload->replaceFile setting --- _config/config.yml | 6 +++ docs/en/reference/uploadfield.md | 7 +++ filesystem/Upload.php | 77 ++++++++++++++++++++++---------- forms/FileField.php | 2 +- tests/filesystem/UploadTest.php | 56 +++++++++++++++++++++++ 5 files changed, 124 insertions(+), 24 deletions(-) create mode 100644 _config/config.yml diff --git a/_config/config.yml b/_config/config.yml new file mode 100644 index 000000000..5d1786a10 --- /dev/null +++ b/_config/config.yml @@ -0,0 +1,6 @@ +--- +Name: coreconfig +--- +Upload: + # Replace an existing file rather than renaming the new one. + replaceFile: false \ No newline at end of file diff --git a/docs/en/reference/uploadfield.md b/docs/en/reference/uploadfield.md index 1d8db946f..842deedd0 100644 --- a/docs/en/reference/uploadfield.md +++ b/docs/en/reference/uploadfield.md @@ -219,6 +219,13 @@ editform, or 'fileEditValidator' to determine the validator (eg RequiredFields). (of a method on File to provide a actions) for the EditForm (Example: 'getCMSActions') - `fileEditValidator`: (string) Validator (eg RequiredFields) or string $name (of a method on File to provide a Validator) for the EditForm (Example: 'getCMSValidator') + +You can also configure the underlying `[api:Upload]` class, by using the YAML config system. + + :::yaml + Upload: + # Globally disables automatic renaming of files + replaceFile: true ## TODO: Using the UploadField in a frontend form diff --git a/filesystem/Upload.php b/filesystem/Upload.php index 5cfa95b07..d8b2ef3d1 100644 --- a/filesystem/Upload.php +++ b/filesystem/Upload.php @@ -45,6 +45,12 @@ class Upload extends Controller { * @var array */ protected $tmpFile; + + /** + * Replace an existing file rather than renaming the new one. + * @var Boolean + */ + protected $replaceFile; /** * Processing errors that can be evaluated, @@ -61,10 +67,11 @@ class Upload extends Controller { * @var string */ public static $uploads_folder = "Uploads"; - + public function __construct() { parent::__construct(); $this->validator = new Upload_Validator(); + $this->replaceFile = $this->config()->get('replaceFile'); } /** @@ -100,11 +107,6 @@ class Upload extends Controller { if(!$folderPath) $folderPath = self::$uploads_folder; - if(!$this->file) { - $fileClass = File::get_class_for_file_extension(pathinfo($tmpFile['name'], PATHINFO_EXTENSION)); - $this->file = new $fileClass(); - } - if(!is_array($tmpFile)) { user_error("Upload::load() Not passed an array. Most likely, the form hasn't got the right enctype", E_USER_ERROR); @@ -137,25 +139,40 @@ class Upload extends Controller { $fileName = basename($file); $relativeFilePath = ASSETS_DIR . "/" . $folderPath . "/$fileName"; + + // Create a new file record (or try to retrieve an existing one) + if(!$this->file) { + $fileClass = File::get_class_for_file_extension(pathinfo($tmpFile['name'], PATHINFO_EXTENSION)); + if($this->replaceFile) { + $this->file = File::get() + ->filter(array( + 'Name' => $fileName, + 'ParentID' => $parentFolder ? $parentFolder->ID : 0 + ))->First(); + } + if(!$this->file) $this->file = new $fileClass(); + } // if filename already exists, version the filename (e.g. test.gif to test1.gif) - while(file_exists("$base/$relativeFilePath")) { - $i = isset($i) ? ($i+1) : 2; - $oldFilePath = $relativeFilePath; - // make sure archives retain valid extensions - if(substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.gz')) == '.tar.gz' || - substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.bz2')) == '.tar.bz2') { - $relativeFilePath = preg_replace('/[0-9]*(\.tar\.[^.]+$)/', $i . '\\1', $relativeFilePath); - } else if (strpos($relativeFilePath, '.') !== false) { - $relativeFilePath = preg_replace('/[0-9]*(\.[^.]+$)/', $i . '\\1', $relativeFilePath); - } else if (strpos($relativeFilePath, '_') !== false) { - $relativeFilePath = preg_replace('/_([^_]+$)/', '_'.$i, $relativeFilePath); - } else { - $relativeFilePath .= '_'.$i; - } - if($oldFilePath == $relativeFilePath && $i > 2) { - user_error("Couldn't fix $relativeFilePath with $i tries", E_USER_ERROR); - } + if(!$this->replaceFile) { + while(file_exists("$base/$relativeFilePath")) { + $i = isset($i) ? ($i+1) : 2; + $oldFilePath = $relativeFilePath; + // make sure archives retain valid extensions + if(substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.gz')) == '.tar.gz' || + substr($relativeFilePath, strlen($relativeFilePath) - strlen('.tar.bz2')) == '.tar.bz2') { + $relativeFilePath = preg_replace('/[0-9]*(\.tar\.[^.]+$)/', $i . '\\1', $relativeFilePath); + } else if (strpos($relativeFilePath, '.') !== false) { + $relativeFilePath = preg_replace('/[0-9]*(\.[^.]+$)/', $i . '\\1', $relativeFilePath); + } else if (strpos($relativeFilePath, '_') !== false) { + $relativeFilePath = preg_replace('/_([^_]+$)/', '_'.$i, $relativeFilePath); + } else { + $relativeFilePath .= '_'.$i; + } + if($oldFilePath == $relativeFilePath && $i > 2) { + user_error("Couldn't fix $relativeFilePath with $i tries", E_USER_ERROR); + } + } } if(file_exists($tmpFile['tmp_name']) && copy($tmpFile['tmp_name'], "$base/$relativeFilePath")) { @@ -181,6 +198,20 @@ class Upload extends Controller { $this->file = $file; return $this->load($tmpFile, $folderPath); } + + /** + * @return Boolean + */ + public function setReplaceFile($bool) { + $this->replaceFile = $bool; + } + + /** + * @return Boolean + */ + public function getReplaceFile() { + return $this->replaceFile; + } /** * Container for all validation on the file diff --git a/forms/FileField.php b/forms/FileField.php index f8a9d6b8c..5aeb68f78 100644 --- a/forms/FileField.php +++ b/forms/FileField.php @@ -78,7 +78,7 @@ class FileField extends FormField { * @param int $value The value of the field. */ public function __construct($name, $title = null, $value = null) { - $this->upload = new Upload(); + $this->upload = Upload::create(); parent::__construct($name, $title, $value); } diff --git a/tests/filesystem/UploadTest.php b/tests/filesystem/UploadTest.php index d384aac2e..118886db8 100644 --- a/tests/filesystem/UploadTest.php +++ b/tests/filesystem/UploadTest.php @@ -316,6 +316,62 @@ class UploadTest extends SapphireTest { $file2->delete(); } + public function testReplaceFile() { + // create tmp file + $tmpFileName = 'UploadTest-testUpload'; + $tmpFilePath = TEMP_FOLDER . '/' . $tmpFileName; + $tmpFileContent = ''; + for($i=0; $i<10000; $i++) $tmpFileContent .= '0'; + file_put_contents($tmpFilePath, $tmpFileContent); + + // emulates the $_FILES array + $tmpFile = array( + 'name' => $tmpFileName, + 'type' => 'text/plaintext', + 'size' => filesize($tmpFilePath), + 'tmp_name' => $tmpFilePath, + 'extension' => 'txt', + 'error' => UPLOAD_ERR_OK, + ); + + // Make sure there are none here, otherwise they get renamed incorrectly for the test. + $this->deleteTestUploadFiles("/UploadTest-testUpload.*/"); + + $v = new UploadTest_Validator(); + $v->setAllowedExtensions(array('')); + + // test upload into default folder + $u = new Upload(); + $u->setValidator($v); + $u->load($tmpFile); + $file = $u->getFile(); + + $this->assertEquals( + 'UploadTest-testUpload', + $file->Name, + 'File is uploaded without extension' + ); + + $u = new Upload(); + $u->setValidator($v); + $u->setReplaceFile(true); + $u->load($tmpFile); + $file2 = $u->getFile(); + $this->assertEquals( + 'UploadTest-testUpload', + $file2->Name, + 'File does not receive new name' + ); + $this->assertEquals( + $file->ID, + $file2->ID, + 'File database record is the same' + ); + + $file->delete(); + $file2->delete(); + } + } class UploadTest_Validator extends Upload_Validator implements TestOnly {