/** * Insert a file into a folder by it's local path. * * @param string $localFilePath The local file path of the file to insert. * @param AssetFolderModel $folder The assetFolderModel where the file should be uploaded to. * @param string $fileName The name of the file to insert. * @param bool $preventConflicts If set to true, will ensure that a conflict is not encountered by * checking the file name prior insertion. * * @return AssetOperationResponseModel */ public function insertFileByPath($localFilePath, AssetFolderModel $folder, $fileName, $preventConflicts = false) { // Fire an 'onBeforeUploadAsset' event $event = new Event($this, array('path' => $localFilePath, 'folder' => $folder, 'filename' => $fileName)); craft()->assets->onBeforeUploadAsset($event); if ($event->performAction) { // We hate Javascript and PHP in our image files. if (IOHelper::getFileKind(IOHelper::getExtension($localFilePath)) == 'image' && ImageHelper::isImageManipulatable(IOHelper::getExtension($localFilePath))) { craft()->images->cleanImage($localFilePath); } if ($preventConflicts) { $newFileName = $this->getNameReplacement($folder, $fileName); $response = $this->insertFileInFolder($folder, $localFilePath, $newFileName); } else { $response = $this->insertFileInFolder($folder, $localFilePath, $fileName); // Naming conflict. create a new file and ask the user what to do with it if ($response->isConflict()) { $newFileName = $this->getNameReplacement($folder, $fileName); $conflictResponse = $response; $response = $this->insertFileInFolder($folder, $localFilePath, $newFileName); } } if ($response->isSuccess()) { $filename = IOHelper::getFileName($response->getDataItem('filePath')); $fileModel = new AssetFileModel(); $fileModel->sourceId = $this->model->id; $fileModel->folderId = $folder->id; $fileModel->filename = IOHelper::getFileName($filename); $fileModel->kind = IOHelper::getFileKind(IOHelper::getExtension($filename)); $fileModel->size = filesize($localFilePath); $fileModel->dateModified = IOHelper::getLastTimeModified($localFilePath); if ($fileModel->kind == 'image') { list($width, $height) = getimagesize($localFilePath); $fileModel->width = $width; $fileModel->height = $height; } craft()->assets->storeFile($fileModel); if (!$this->isSourceLocal() && $fileModel->kind == 'image') { craft()->assetTransforms->storeLocalSource($localFilePath, craft()->path->getAssetsImageSourcePath() . $fileModel->id . '.' . IOHelper::getExtension($fileModel->filename)); } // Check if we stored a conflict response originally - send that back then. if (isset($conflictResponse)) { $response = $conflictResponse; } $response->setDataItem('fileId', $fileModel->id); } } else { $response = new AssetOperationResponseModel(); $response->setError(Craft::t('The file upload was cancelled.')); } return $response; }
/** * @inheritDoc BaseAssetSourceType::moveSourceFile() * * @param AssetFileModel $file * @param AssetFolderModel $targetFolder * @param string $fileName * @param bool $overwrite * * @return mixed */ protected function moveSourceFile(AssetFileModel $file, AssetFolderModel $targetFolder, $fileName = '', $overwrite = false) { if (empty($fileName)) { $fileName = $file->filename; } $newServerPath = $this->_getPathPrefix() . $targetFolder->path . $fileName; $conflictingRecord = craft()->assets->findFile(array('folderId' => $targetFolder->id, 'filename' => $fileName)); $this->_prepareForRequests(); $settings = $this->getSettings(); $fileInfo = $this->_s3->getObjectInfo($settings->bucket, $newServerPath); $conflict = !$overwrite && ($fileInfo || !craft()->assets->isMergeInProgress() && is_object($conflictingRecord)); if ($conflict) { $response = new AssetOperationResponseModel(); return $response->setPrompt($this->getUserPromptOptions($fileName))->setDataItem('fileName', $fileName); } $bucket = $this->getSettings()->bucket; // Just in case we're moving from another bucket with the same access credentials. $originatingSourceType = craft()->assetSources->getSourceTypeById($file->sourceId); $originatingSettings = $originatingSourceType->getSettings(); $sourceBucket = $originatingSettings->bucket; $this->_prepareForRequests($originatingSettings); if (!$this->_s3->copyObject($sourceBucket, $this->_getPathPrefix($originatingSettings) . $file->getFolder()->path . $file->filename, $bucket, $newServerPath, \S3::ACL_PUBLIC_READ)) { $response = new AssetOperationResponseModel(); return $response->setError(Craft::t("Could not save the file")); } @$this->_s3->deleteObject($sourceBucket, $this->_getS3Path($file, $originatingSettings)); if ($file->kind == 'image') { if ($targetFolder->sourceId == $file->sourceId) { $transforms = craft()->assetTransforms->getAllCreatedTransformsForFile($file); $destination = clone $file; $destination->filename = $fileName; // Move transforms foreach ($transforms as $index) { // For each file, we have to have both the source and destination // for both files and transforms, so we can reliably move them $destinationIndex = clone $index; if (!empty($index->filename)) { $destinationIndex->filename = $fileName; craft()->assetTransforms->storeTransformIndexData($destinationIndex); } $from = $file->getFolder()->path . craft()->assetTransforms->getTransformSubpath($file, $index); $to = $targetFolder->path . craft()->assetTransforms->getTransformSubpath($destination, $destinationIndex); $this->copySourceFile($from, $to); $this->deleteSourceFile($from); } } else { craft()->assetTransforms->deleteAllTransformData($file); } } $response = new AssetOperationResponseModel(); return $response->setSuccess()->setDataItem('newId', $file->id)->setDataItem('newFileName', $fileName); }
/** * Insert a file into a folder by it's local path. * * @param string $localFilePath The local file path of the file to insert. * @param AssetFolderModel $folder The assetFolderModel where the file should be uploaded to. * @param string $filename The name of the file to insert. * @param bool $preventConflicts If set to true, will ensure that a conflict is not encountered by * checking the file name prior insertion. * * @return AssetOperationResponseModel */ public function insertFileByPath($localFilePath, AssetFolderModel $folder, $filename, $preventConflicts = false) { // Fire an 'onBeforeUploadAsset' event $event = new Event($this, array('path' => $localFilePath, 'folder' => $folder, 'filename' => $filename)); craft()->assets->onBeforeUploadAsset($event); if ($event->performAction) { // We hate Javascript and PHP in our image files. if (IOHelper::getFileKind(IOHelper::getExtension($localFilePath)) == 'image' && ImageHelper::isImageManipulatable(IOHelper::getExtension($localFilePath)) && IOHelper::getExtension($localFilePath) != 'svg') { craft()->images->cleanImage($localFilePath); } $mobileUpload = false; if (IOHelper::getFileName($filename, false) == "image" && craft()->request->isMobileBrowser(true)) { $mobileUpload = true; $date = DateTimeHelper::currentUTCDateTime(); $filename = "image_" . $date->format('Ymd_His') . "." . IOHelper::getExtension($filename); } if ($preventConflicts) { $newFileName = $this->getNameReplacementInFolder($folder, $filename); $response = $this->insertFileInFolder($folder, $localFilePath, $newFileName); } else { $response = $this->insertFileInFolder($folder, $localFilePath, $filename); // Naming conflict. create a new file and ask the user what to do with it if ($response->isConflict()) { $newFileName = $this->getNameReplacementInFolder($folder, $filename); $conflictResponse = $response; $response = $this->insertFileInFolder($folder, $localFilePath, $newFileName); } } if ($response->isSuccess()) { $fileModel = new AssetFileModel(); $title = $fileModel->generateAttributeLabel(IOHelper::getFileName($filename, false)); // If there were double spaces, it's because the filename had a space followed by a // capital letter. We convert the space to a dash, but Yii thinks it's a new "word" // and adds another space. $fileModel->getContent()->title = str_replace(' ', ' ', $title); $filename = IOHelper::getFileName($response->getDataItem('filePath')); $fileModel->filename = IOHelper::getFileName($filename); $fileModel->sourceId = $this->model->id; $fileModel->folderId = $folder->id; $fileModel->kind = IOHelper::getFileKind(IOHelper::getExtension($filename)); $fileModel->size = filesize($localFilePath); $fileModel->dateModified = IOHelper::getLastTimeModified($localFilePath); if ($fileModel->kind == 'image') { list($width, $height) = ImageHelper::getImageSize($localFilePath); $fileModel->width = $width; $fileModel->height = $height; } if ($mobileUpload) { $fileModel->getContent()->title = Craft::t('Mobile Upload'); } craft()->assets->storeFile($fileModel); if (!$this->isSourceLocal() && $fileModel->kind == 'image') { craft()->assetTransforms->storeLocalSource($localFilePath, craft()->path->getAssetsImageSourcePath() . $fileModel->id . '.' . IOHelper::getExtension($fileModel->filename)); } // Check if we stored a conflict response originally - send that back then. if (isset($conflictResponse)) { $response = $conflictResponse; } $response->setDataItem('fileId', $fileModel->id); } } else { $response = new AssetOperationResponseModel(); $response->setError(Craft::t('The file upload was cancelled.')); } return $response; }
/** * Move or rename files. * * @param $fileIds * @param $folderId * @param string $filename If this is a rename operation or not. * @param array $actions Actions to take in case of a conflict. * * @throws Exception * @return bool|AssetOperationResponseModel */ public function moveFiles($fileIds, $folderId, $filename = '', $actions = array()) { if ($filename && is_array($fileIds) && count($fileIds) > 1) { throw new Exception(Craft::t("It’s not possible to rename multiple files!")); } if (!is_array($fileIds)) { $fileIds = array($fileIds); } if (!is_array($actions)) { $actions = array($actions); } $results = array(); $response = new AssetOperationResponseModel(); $folder = $this->getFolderById($folderId); $newSourceType = craft()->assetSources->getSourceTypeById($folder->sourceId); // Does the source folder exist? $parent = $folder->getParent(); if ($parent && $folder->parentId && !$newSourceType->folderExists($parent ? $parent->path : '', $folder->name)) { $response->setError(Craft::t("The target folder does not exist!")); } else { foreach ($fileIds as $i => $fileId) { $file = $this->getFileById($fileId); // If this is not a rename operation, then the filename remains the original if (count($fileIds) > 1 || empty($filename)) { $filename = $file->filename; } // If the new file does not have an extension, give it the old file extension. if (!IOHelper::getExtension($filename)) { $filename .= '.' . $file->getExtension(); } $filename = AssetsHelper::cleanAssetName($filename); if ($folderId == $file->folderId && $filename == $file->filename) { $response = new AssetOperationResponseModel(); $response->setSuccess(); $results[] = $response; } $originalSourceType = craft()->assetSources->getSourceTypeById($file->sourceId); if ($originalSourceType && $newSourceType) { if (!($response = $newSourceType->moveFileInsideSource($originalSourceType, $file, $folder, $filename, $actions[$i]))) { $response = $this->_moveFileBetweenSources($originalSourceType, $newSourceType, $file, $folder, $actions[$i]); } } else { $response->setError(Craft::t("There was an error moving the file {file}.", array('file' => $file->filename))); } } } return $response; }
/** * @inheritDoc BaseAssetSourceType::moveSourceFile() * * @param AssetFileModel $file * @param AssetFolderModel $targetFolder * @param string $fileName * @param bool $overwrite * * @return mixed */ protected function moveSourceFile(AssetFileModel $file, AssetFolderModel $targetFolder, $fileName = '', $overwrite = false) { if (empty($fileName)) { $fileName = $file->filename; } $newServerPath = $this->getSourceFileSystemPath() . $targetFolder->path . $fileName; $conflictingRecord = craft()->assets->findFile(array('folderId' => $targetFolder->id, 'filename' => $fileName)); $conflict = !$overwrite && (IOHelper::fileExists($newServerPath) || !craft()->assets->isMergeInProgress() && is_object($conflictingRecord)); if ($conflict) { $response = new AssetOperationResponseModel(); return $response->setPrompt($this->getUserPromptOptions($fileName))->setDataItem('fileName', $fileName); } if (!IOHelper::move($this->_getFileSystemPath($file), $newServerPath)) { $response = new AssetOperationResponseModel(); return $response->setError(Craft::t('Could not move the file “{filename}”.', array('filename' => $fileName))); } if ($file->kind == 'image') { if ($targetFolder->sourceId == $file->sourceId) { $transforms = craft()->assetTransforms->getAllCreatedTransformsForFile($file); $destination = clone $file; $destination->filename = $fileName; // Move transforms foreach ($transforms as $index) { // For each file, we have to have both the source and destination // for both files and transforms, so we can reliably move them $destinationIndex = clone $index; if (!empty($index->filename)) { $destinationIndex->filename = $fileName; craft()->assetTransforms->storeTransformIndexData($destinationIndex); } $from = $file->getFolder()->path . craft()->assetTransforms->getTransformSubpath($file, $index); $to = $targetFolder->path . craft()->assetTransforms->getTransformSubpath($destination, $destinationIndex); $this->copySourceFile($from, $to); $this->deleteSourceFile($from); } } else { craft()->assetTransforms->deleteAllTransformData($file); } } $response = new AssetOperationResponseModel(); return $response->setSuccess()->setDataItem('newId', $file->id)->setDataItem('newFileName', $fileName); }
/** * Move a file in source. * * @param AssetFileModel $file * @param AssetFolderModel $targetFolder * @param string $fileName * @param bool $overwrite if True, will overwrite target destination * @return mixed */ protected function _moveSourceFile(AssetFileModel $file, AssetFolderModel $targetFolder, $fileName = '', $overwrite = false) { if (empty($fileName)) { $fileName = $file->filename; } $newServerPath = $this->_getPathPrefix() . $targetFolder->fullPath . $fileName; $conflictingRecord = craft()->assets->findFile(array('folderId' => $targetFolder->id, 'filename' => $fileName)); $this->_prepareForRequests(); $settings = $this->getSettings(); $fileInfo = $this->_s3->getObjectInfo($settings->bucket, $newServerPath); $conflict = !$overwrite && ($fileInfo || !craft()->assets->isMergeInProgress() && is_object($conflictingRecord)); if ($conflict) { $response = new AssetOperationResponseModel(); return $response->setPrompt($this->_getUserPromptOptions($fileName))->setDataItem('fileName', $fileName); } $bucket = $this->getSettings()->bucket; // Just in case we're moving from another bucket with the same access credentials. $originatingSourceType = craft()->assetSources->getSourceTypeById($file->sourceId); $originatingSettings = $originatingSourceType->getSettings(); $sourceBucket = $originatingSettings->bucket; $this->_prepareForRequests($originatingSettings); if (!$this->_s3->copyObject($sourceBucket, $this->_getPathPrefix($originatingSettings) . $file->getFolder()->fullPath . $file->filename, $bucket, $newServerPath, \S3::ACL_PUBLIC_READ)) { $response = new AssetOperationResponseModel(); return $response->setError(Craft::t("Could not save the file")); } @$this->_s3->deleteObject($sourceBucket, $this->_getS3Path($file)); if ($file->kind == 'image') { $this->_deleteGeneratedThumbnails($file); // Move transforms $transforms = craft()->assetTransforms->getGeneratedTransformLocationsForFile($file); $baseFromPath = $this->_getPathPrefix() . $file->getFolder()->fullPath; $baseToPath = $this->_getPathPrefix() . $targetFolder->fullPath; foreach ($transforms as $location) { // Surpress errors when trying to move image transforms. Maybe the user hasn't updated them yet. $copyResult = @$this->_s3->copyObject($sourceBucket, $baseFromPath . $location . '/' . $file->filename, $bucket, $baseToPath . $location . '/' . $fileName, \S3::ACL_PUBLIC_READ); // If we failed to copy, that's because source wasn't there. Skip delete and save time - everyone's a winner! if ($copyResult) { @$this->_s3->deleteObject($sourceBucket, $baseFromPath . $location . '/' . $file->filename); } } } $response = new AssetOperationResponseModel(); return $response->setSuccess()->setDataItem('newId', $file->id)->setDataItem('newFileName', $fileName); }
/** * Move a file in source. * * @param AssetFileModel $file The file to move. * @param AssetFolderModel $targetFolder The folder where to move the file. * @param string $fileName The filename to use. * @param bool $overwrite If true, will overwrite target * * @return mixed */ protected function moveSourceFile(AssetFileModel $file, AssetFolderModel $targetFolder, $fileName = '', $overwrite = false) { if (empty($fileName)) { $fileName = $file->filename; } $newServerPath = $this->getSourceFileSystemPath() . $targetFolder->path . $fileName; $conflictingRecord = craft()->assets->findFile(array('folderId' => $targetFolder->id, 'filename' => $fileName)); $conflict = !$overwrite && (IOHelper::fileExists($newServerPath) || !craft()->assets->isMergeInProgress() && is_object($conflictingRecord)); if ($conflict) { $response = new AssetOperationResponseModel(); return $response->setPrompt($this->getUserPromptOptions($fileName))->setDataItem('fileName', $fileName); } if (!IOHelper::move($this->_getFileSystemPath($file), $newServerPath)) { $response = new AssetOperationResponseModel(); return $response->setError(Craft::t('Could not move the file “{filename}”.', array('filename' => $fileName))); } if ($file->kind == 'image') { if ($targetFolder->sourceId == $file->sourceId) { $transforms = craft()->assetTransforms->getAllCreatedTransformsForFile($file); // Move transforms foreach ($transforms as $index) { $this->copyTransform($file, $targetFolder, $index, $index); $this->deleteSourceFile($file->getFolder()->path . craft()->assetTransforms->getTransformSubpath($file, $index)); } } else { craft()->assetTransforms->deleteCreatedTransformsForFile($file); } } $response = new AssetOperationResponseModel(); return $response->setSuccess()->setDataItem('newId', $file->id)->setDataItem('newFileName', $fileName); }
/** * Delete a list of files by an array of ids (or a single id). * * @param $fileIds * @return AssetOperationResponseModel */ public function deleteFiles($fileIds) { if (!is_array($fileIds)) { $fileIds = array($fileIds); } $response = new AssetOperationResponseModel(); try { foreach ($fileIds as $fileId) { $file = $this->getFileById($fileId); $source = craft()->assetSources->getSourceTypeById($file->sourceId); $source->deleteFile($file); craft()->elements->deleteElementById($fileId); } $response->setSuccess(); } catch (Exception $exception) { $response->setError($exception->getMessage()); } return $response; }
/** * Move a file in source. * * @param AssetFileModel $file * @param AssetFolderModel $targetFolder * @param string $fileName * @param bool $overwrite if True, will overwrite target destination * @return mixed */ protected function _moveSourceFile(AssetFileModel $file, AssetFolderModel $targetFolder, $fileName = '', $overwrite = false) { if (empty($fileName)) { $fileName = $file->filename; } $newServerPath = $this->_getSourceFileSystemPath() . $targetFolder->fullPath . $fileName; $conflictingRecord = craft()->assets->findFile(array('folderId' => $targetFolder->id, 'filename' => $fileName)); $conflict = !$overwrite && (IOHelper::fileExists($newServerPath) || !craft()->assets->isMergeInProgress() && is_object($conflictingRecord)); if ($conflict) { $response = new AssetOperationResponseModel(); return $response->setPrompt($this->_getUserPromptOptions($fileName))->setDataItem('fileName', $fileName); } if (!IOHelper::move($this->_getFileSystemPath($file), $newServerPath)) { $response = new AssetOperationResponseModel(); return $response->setError(Craft::t("Could not save the file")); } if ($file->kind == 'image') { $this->_deleteGeneratedThumbnails($file); // Move transforms $transforms = craft()->assetTransforms->getGeneratedTransformLocationsForFile($file); $baseFromPath = $this->_getSourceFileSystemPath() . $file->getFolder()->fullPath; $baseToPath = $this->_getSourceFileSystemPath() . $targetFolder->fullPath; foreach ($transforms as $location) { if (IOHelper::fileExists($baseFromPath . $location . '/' . $file->filename)) { IOHelper::ensureFolderExists($baseToPath . $location); IOHelper::move($baseFromPath . $location . '/' . $file->filename, $baseToPath . $location . '/' . $fileName); } } } $response = new AssetOperationResponseModel(); return $response->setSuccess()->setDataItem('newId', $file->id)->setDataItem('newFileName', $fileName); }