/** * Handles the upload request. This is a static function to ensure that it is easily * accessible to other classes without having to instantiate a {@link Controller} object. * A lot of this code is lifted from {@link AssetAdmin}. * * @todo Error handling on this is crap. * @param SS_HTTPRequest * @param Folder A folder that will be the destination of the upload. * @return array|string */ public static function handle_upload(SS_HTTPRequest $r, $folder = null, $allowed_extensions = null) { if (!$folder) { $folder = singleton('Folder'); } $newFiles = array(); $errorResponse = ""; if (isset($_FILES['file']) && is_array($_FILES['file'])) { $file_array = $_FILES['file']; foreach ($file_array['tmp_name'] as $index => $value) { if (is_uploaded_file($value)) { $tmpFile = array('tmp_name' => $value, 'name' => $file_array['name'][$index], 'size' => $file_array['size'][$index], 'error' => $file_array['error'][$index]); // validate files (only if not logged in as admin) if (!File::$apply_restrictions_to_admin && Permission::check('ADMIN')) { $valid = true; } else { // Set up the validator instance with rules $validator = new Upload_Validator(); if (!$allowed_extensions) { $allowed_extensions = File::$allowed_extensions; } $validator->setAllowedExtensions($allowed_extensions); $validator->setAllowedMaxFileSize(self::$allowed_max_file_size); // Do the upload validation with the rules $upload = new Upload(); $upload->setValidator($validator); $valid = $upload->validate($tmpFile); if (!$valid) { $errors = $upload->getErrors(); if ($errors) { foreach ($errors as $error) { $errorResponse .= $error; } } } } // move file to given folder if ($valid) { $newFile = $folder->addUploadToFolder($tmpFile); $newFiles[] = $newFile; } else { return $errorResponse; } foreach ($newFiles as $newFile) { $fileIDs[] = $newFile; $fileObj = DataObject::get_one('File', "\"File\".\"ID\"={$newFile}"); if (method_exists($fileObj, 'onAfterUpload')) { $fileObj->onAfterUpload(); } } } } } else { return "File is too large."; } return $newFiles; }
public function testInvalidFileExtensionValidatingMimeType() { // setup plaintext file with invalid extension $tmpFileName = 'UploadTest-testUpload.jpg'; $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, 'size' => filesize($tmpFilePath), 'tmp_name' => $tmpFilePath, 'extension' => 'jpg', 'error' => UPLOAD_ERR_OK); $u = new Upload(); $u->setValidator(new MimeUploadValidator()); $result = $u->load($tmpFile); $errors = $u->getErrors(); $this->assertFalse($result, 'Load failed because file extension does not match excepted MIME type'); $this->assertEquals('File extension does not match known MIME type', $errors[0]); unlink($tmpFilePath); }
/** * This method processes the results of the UploadForm. * It will save the uploaded files to /assets/ and create new File objects as required. */ function doUpload($data, $form) { $newFiles = array(); $fileIDs = array(); $fileNames = array(); $fileSizeWarnings = ''; $uploadErrors = ''; $jsErrors = ''; $status = ''; $statusMessage = ''; $processedFiles = array(); foreach ($data['Files'] as $param => $files) { if (!is_array($files)) { $files = array($files); } foreach ($files as $key => $value) { $processedFiles[$key][$param] = $value; } } // Load POST data from arrays in to the correct dohickey. $processedData = array(); foreach ($data as $dataKey => $value) { if ($dataKey == 'Files') { continue; } if (is_array($value)) { $i = 0; foreach ($value as $fileId => $dataValue) { if (!isset($processedData[$i])) { $processedData[$i] = array(); } $processedData[$i][$dataKey] = $dataValue; $i++; } } } $processedData = array_reverse($processedData); if ($data['FolderID'] && $data['FolderID'] != '') { $folder = DataObject::get_by_id("Folder", $data['FolderID']); if (!$folder) { throw new InvalidArgumentException(sprintf("Folder #%d doesn't exist", (int) $data['FolderID'])); } } else { $folder = singleton('Folder'); } foreach ($processedFiles as $filePostId => $tmpFile) { if ($tmpFile['error'] == UPLOAD_ERR_NO_TMP_DIR) { $status = 'bad'; $statusMessage = _t('AssetAdmin.NOTEMP', 'There is no temporary folder for uploads. Please set upload_tmp_dir in php.ini.'); break; } if ($tmpFile['tmp_name']) { // Workaround open_basedir problems if (ini_get("open_basedir")) { $newtmp = TEMP_FOLDER . '/' . $tmpFile['name']; move_uploaded_file($tmpFile['tmp_name'], $newtmp); $tmpFile['tmp_name'] = $newtmp; } // validate files (only if not logged in as admin) if (!File::$apply_restrictions_to_admin && Permission::check('ADMIN')) { $valid = true; } else { // Set up the validator instance with rules $validator = new Upload_Validator(); $validator->setAllowedExtensions(File::$allowed_extensions); $validator->setAllowedMaxFileSize(self::$allowed_max_file_size); // Do the upload validation with the rules $upload = new Upload(); $upload->setValidator($validator); $valid = $upload->validate($tmpFile); if (!$valid) { $errors = $upload->getErrors(); if ($errors) { foreach ($errors as $error) { $jsErrors .= "alert('" . Convert::raw2js($error) . "');"; } } } } // move file to given folder if ($valid) { if ($newFile = $folder->addUploadToFolder($tmpFile)) { if (self::$metadata_upload_enabled && isset($processedData[$filePostId])) { $fileObject = DataObject::get_by_id('File', $newFile); $metadataForm = new Form($this, 'MetadataForm', $fileObject->uploadMetadataFields(), new FieldSet()); $metadataForm->loadDataFrom($processedData[$filePostId]); $metadataForm->saveInto($fileObject); $fileObject->write(); } $newFiles[] = $newFile; } } } } if ($newFiles) { $numFiles = sizeof($newFiles); $statusMessage = sprintf(_t('AssetAdmin.UPLOADEDX', "Uploaded %s files"), $numFiles); $status = "good"; } else { if ($status != 'bad') { $statusMessage = _t('AssetAdmin.NOTHINGTOUPLOAD', 'There was nothing to upload'); $status = ""; } } $fileObj = false; foreach ($newFiles as $newFile) { $fileIDs[] = $newFile; $fileObj = DataObject::get_one('File', "\"File\".\"ID\"={$newFile}"); // notify file object after uploading if (method_exists($fileObj, 'onAfterUpload')) { $fileObj->onAfterUpload(); } $fileNames[] = $fileObj->Name; } // workaround for content editors image upload.Passing an extra hidden field // in the content editors view of 'UploadMode' @see HtmlEditorField // this will be refactored for 2.5 if (isset($data['UploadMode']) && $data['UploadMode'] == "CMSEditor" && $fileObj) { // we can use $fileObj considering that the uploader in the cmseditor can only upload // one file at a time. Once refactored to multiple files this is going to have to be changed $width = is_a($fileObj, 'Image') ? $fileObj->getWidth() : '100'; $height = is_a($fileObj, 'Image') ? $fileObj->getHeight() : '100'; $values = array('Filename' => $fileObj->Filename, 'Width' => $width, 'Height' => $height); return Convert::raw2json($values); } $sFileIDs = implode(',', $fileIDs); $sFileNames = implode(',', $fileNames); echo <<<HTML \t\t\t<script type="text/javascript"> \t\t\t/* IDs: {$sFileIDs} */ \t\t\t/* Names: {$sFileNames} */ \t\t\t \t\t\tvar form = parent.document.getElementById('Form_EditForm'); \t\t\tparent.statusMessage("{$statusMessage}","{$status}"); \t\t\t{$jsErrors} \t\t\tparent.document.getElementById('sitetree').getTreeNodeByIdx( "{$folder->ID}" ).getElementsByTagName('a')[0].className += ' contents'; \t\t\tform.getPageFromServer(form.elements.ID.value); \t\t\t</script> HTML; }
public function testFileVersioningWithAnExistingFile() { $upload = function ($tmpFileName) { // create tmp file $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' => 'jpg', 'error' => UPLOAD_ERR_OK); $v = new UploadTest_Validator(); // test upload into default folder $u = new Upload(); $u->setReplaceFile(false); $u->setValidator($v); $u->loadIntoFile($tmpFile); return $u->getFile(); }; // test empty file version prefix Config::inst()->update('SilverStripe\\Filesystem\\Storage\\DefaultAssetNameGenerator', 'version_prefix', ''); $file1 = $upload('UploadTest-IMG001.jpg'); $this->assertEquals('UploadTest-IMG001.jpg', $file1->Name, 'File does not receive new name'); $file2 = $upload('UploadTest-IMG001.jpg'); $this->assertEquals('UploadTest-IMG002.jpg', $file2->Name, 'File does receive new name'); $file3 = $upload('UploadTest-IMG002.jpg'); $this->assertEquals('UploadTest-IMG003.jpg', $file3->Name, 'File does receive new name'); $file4 = $upload('UploadTest-IMG3.jpg'); $this->assertEquals('UploadTest-IMG3.jpg', $file4->Name, 'File does not receive new name'); $file1->delete(); $file2->delete(); $file3->delete(); $file4->delete(); // test '-v' file version prefix Config::inst()->update('SilverStripe\\Filesystem\\Storage\\DefaultAssetNameGenerator', 'version_prefix', '-v'); $file1 = $upload('UploadTest2-IMG001.jpg'); $this->assertEquals('UploadTest2-IMG001.jpg', $file1->Name, 'File does not receive new name'); $file2 = $upload('UploadTest2-IMG001.jpg'); $this->assertEquals('UploadTest2-IMG001-v2.jpg', $file2->Name, 'File does receive new name'); $file3 = $upload('UploadTest2-IMG001.jpg'); $this->assertEquals('UploadTest2-IMG001-v3.jpg', $file3->Name, 'File does receive new name'); $file4 = $upload('UploadTest2-IMG001-v3.jpg'); $this->assertEquals('UploadTest2-IMG001-v4.jpg', $file4->Name, 'File does receive new name'); }
/** * Set custom validator for this field * * @param object $validator */ public function setValidator($validator) { $this->upload->setValidator($validator); return $this; }
function testUploadFileWithNoExtensionTwiceAppendsNumber() { // 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->load($tmpFile); $file2 = $u->getFile(); $this->assertEquals('UploadTest-testUpload-2', $file2->Name, 'File receives a number attached to the end'); $file->delete(); $file2->delete(); }
public function testFileVersioningWithAnExistingFile() { $upload = function ($tmpFileName) { // create tmp file $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' => 'jpg', 'error' => UPLOAD_ERR_OK); $v = new UploadTest_Validator(); // test upload into default folder $u = new Upload(); $u->setReplaceFile(false); $u->setValidator($v); $u->load($tmpFile); return $u->getFile(); }; $file1 = $upload('UploadTest-testUpload.jpg'); $this->assertEquals('UploadTest-testUpload.jpg', $file1->Name, 'File does not receive new name'); $file2 = $upload('UploadTest-testUpload.jpg'); $this->assertEquals('UploadTest-testUpload2.jpg', $file2->Name, 'File does receive new name'); $file3 = $upload('UploadTest-testUpload.jpg'); $this->assertEquals('UploadTest-testUpload3.jpg', $file3->Name, 'File does receive new name'); $file4 = $upload('UploadTest-testUpload3.jpg'); $this->assertEquals('UploadTest-testUpload4.jpg', $file4->Name, 'File does receive new name'); $file1->delete(); $file2->delete(); $file3->delete(); $file4->delete(); }
private function buildScreenshots(Addon $addon, PackageInterface $package, $path) { $extra = $package->getExtra(); $screenshots = array(); $target = self::SCREENSHOTS_DIR . '/' . $addon->Name; if (isset($extra['screenshots'])) { $screenshots = (array) $extra['screenshots']; } elseif (isset($extra['screenshot'])) { $screenshots = (array) $extra['screenshot']; } // Delete existing screenshots. foreach ($addon->Screenshots() as $screenshot) { $screenshot->delete(); } $addon->Screenshots()->removeAll(); foreach ($screenshots as $screenshot) { if (!is_string($screenshot)) { continue; } $scheme = parse_url($screenshot, PHP_URL_SCHEME); // Handle absolute image URLs. if ($scheme == 'http' || $scheme == 'https') { $temp = TEMP_FOLDER . '/' . md5($screenshot); if (!copy($screenshot, $temp)) { continue; } $data = array('name' => basename($screenshot), 'size' => filesize($temp), 'tmp_name' => $temp, 'error' => 0); } else { $source = $path . '/' . ltrim($screenshot, '/'); // Prevent directory traversal. if ($source != realpath($source)) { continue; } if (!file_exists($source)) { continue; } $data = array('name' => basename($source), 'size' => filesize($source), 'tmp_name' => $source, 'error' => 0); } $upload = new Upload(); $upload->setValidator(new AddonBuilderScreenshotValidator()); $upload->load($data, $target); if ($file = $upload->getFile()) { $addon->Screenshots()->add($file); } } }
/** * The main upload handler. Takes the $_FILES data from the request and stores a File * record {@see $defaults['file_class']}. Returns the ID of this new file to the * Javascript handler, for insertion into the parent form. * Note: This handler may require authentication, and that may not be possible * if the PHP setting "session_use_only_cookies" is on. * * @return int */ public function upload() { if (isset($_FILES["Filedata"]) && is_uploaded_file($_FILES["Filedata"]["tmp_name"])) { $upload_folder = $this->getUploadFolder(); if ($this->Backend()) { if (isset($_REQUEST['FolderID'])) { if ($folder = DataObject::get_by_id("Folder", Convert::raw2sql($_REQUEST['FolderID']))) { $upload_folder = self::relative_asset_dir($folder->Filename); } } } $ext = strtolower(end(explode('.', $_FILES['Filedata']['name']))); $class = in_array($ext, self::$image_extensions) ? $this->getSetting('image_class') : $this->getSetting('file_class'); $file = new $class(); // Perform check on allowed file extension, preventing upload of unallowed file types $u = new Upload(); $u->setValidator($validator = new Upload_Validator()); $validator->setAllowedExtensions(File::$allowed_extensions); if ($u->validate($_FILES['Filedata'])) { $u->loadIntoFile($_FILES['Filedata'], $file, $upload_folder); } else { return _t('Uploadify.FILETYPENOTALLOWED', 'File type not allowed!'); } $file->write(); if (method_exists($file, 'onAfterUpload')) { $file->onAfterUpload(); } echo $file->ID; } else { echo ' '; // return something or SWFUpload won't fire uploadSuccess } }
/** * @param ISummit $summit * @param $speaker_id * @param $tmp_file * @return BetterImage */ public function uploadSpeakerPic(ISummit $summit, $speaker_id, $tmp_file) { $speaker_repository = $this->speaker_repository; return $this->tx_service->transaction(function () use($summit, $speaker_id, $tmp_file, $speaker_repository) { $speaker_id = intval($speaker_id); $speaker = $speaker_repository->getById($speaker_id); if (is_null($speaker)) { throw new NotFoundEntityException('PresentationSpeaker'); } $image = new BetterImage(); $upload = new Upload(); $validator = new Upload_Validator(); $validator->setAllowedExtensions(array('png', 'jpg', 'jpeg', 'gif')); $validator->setAllowedMaxFileSize(800 * 1024); // 300Kb $upload->setValidator($validator); if (!$upload->loadIntoFile($tmp_file, $image, 'profile-images')) { throw new EntityValidationException($upload->getErrors()); } $image->write(); return $image; }); }
public function testDeleteResampledImagesOnUpload() { $tmpFileName = 'UploadTest-testUpload.jpg'; $tmpFilePath = TEMP_FOLDER . '/' . $tmpFileName; $uploadImage = function () use($tmpFileName, $tmpFilePath) { copy(__DIR__ . '/gdtest/test_jpg.jpg', $tmpFilePath); // emulates the $_FILES array $tmpFile = array('name' => $tmpFileName, 'type' => 'text/plaintext', 'size' => filesize($tmpFilePath), 'tmp_name' => $tmpFilePath, 'extension' => 'jpg', 'error' => UPLOAD_ERR_OK); $v = new UploadTest_Validator(); // test upload into default folder $u = new Upload(); $u->setReplaceFile(true); $u->setValidator($v); $u->load($tmpFile); return $u->getFile(); }; // Image upload and generate a resampled image $image = $uploadImage(); $resampled = $image->ResizedImage(123, 456); $resampledPath = $resampled->getFullPath(); $this->assertTrue(file_exists($resampledPath)); // Re-upload the image, overwriting the original // Resampled images should removed when their parent file is overwritten $image = $uploadImage(); $this->assertFalse(file_exists($resampledPath)); unlink($tmpFilePath); $image->delete(); }