I've been fighting an issue with file/image uploading through my custom Catalog module. The upload field is in a programmatically generated UI Component form. Here is how my upload field is defined in my CustomOptions.php :
const FIELD_IMAGE_NAME = 'image';
static::FIELD_IMAGE_NAME => $this->getImageConfig(45),
protected function getImageConfig(int $sortOrder): array
{
return [
'arguments' => [
'data' => [
'config' => [
'label' => __('Image'),
'componentType' => 'field',
'dataScope' => static::FIELD_IMAGE_NAME,
'dataType' => 'string',
'source' => 'image',
'formElement' => 'imageUploader',
'sortOrder' => $sortOrder,
'elementTmpl' => 'ui/form/element/uploader/uploader',
'previewTmpl' => 'Vendor_Catalog/image-preview',
'uploaderConfig' => [
'url' => 'catalog/image/upload',
],
],
],
],
];
}
My di.xml:
<type name="Vendor\Catalog\Model\ImageUploader">
<arguments>
<argument name="baseTmpPath" xsi:type="string">tmp/options/etchings</argument>
<argument name="basePath" xsi:type="string">options/etchings</argument>
<argument name="allowedExtensions" xsi:type="array">
<item name="jpg" xsi:type="string">jpg</item>
<item name="jpeg" xsi:type="string">jpeg</item>
<item name="gif" xsi:type="string">gif</item>
<item name="png" xsi:type="string">png</item>
</argument>
</arguments>
</type>
Controller:
<?php
namespace Vendor\Catalog\Controller\Adminhtml\Image;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Vendor\Catalog\Model\ImageUploader;
use Magento\Framework\Controller\ResultFactory;
class Upload extends Action
{
public $imageUploader;
public function __construct(
Context $context,
ImageUploader $imageUploader
) {
parent::__construct($context);
$this->imageUploader = $imageUploader;
}
public function execute()
{
try {
$result = $this->imageUploader->saveFileToTmpDir('image');
$result['cookie'] = [
'name' => $this->_getSession()->getName(),
'value' => $this->_getSession()->getSessionId(),
'lifetime' => $this->_getSession()->getCookieLifetime(),
'path' => $this->_getSession()->getCookiePath(),
'domain' => $this->_getSession()->getCookieDomain(),
];
} catch (\Exception $e) {
$result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()];
}
return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData($result);
}
}
And my Model:
<?php
namespace Vendor\Catalog\Model;
use Exception;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem;
use Magento\Framework\UrlInterface;
use Magento\MediaStorage\Helper\File\Storage\Database;
use Magento\MediaStorage\Model\File\UploaderFactory;
use Magento\Store\Model\StoreManagerInterface;
use Psr\Log\LoggerInterface;
class ImageUploader
{
private $coreFileStorageDatabase;
private $mediaDirectory;
private $uploaderFactory;
private $storeManager;
private $logger;
public $baseTmpPath;
public $basePath;
public $allowedExtensions;
public function __construct(
Database $coreFileStorageDatabase,
Filesystem $filesystem,
UploaderFactory $uploaderFactory,
StoreManagerInterface $storeManager,
LoggerInterface $logger
) {
$this->coreFileStorageDatabase = $coreFileStorageDatabase;
$this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
$this->uploaderFactory = $uploaderFactory;
$this->storeManager = $storeManager;
$this->logger = $logger;
$this->baseTmpPath = 'tmp/options/etchings';
$this->basePath = 'options/etchings';
$this->allowedExtensions= ['jpg', 'jpeg', 'gif', 'png'];
}
public function setBaseTmpPath($baseTmpPath)
{
$this->baseTmpPath = $baseTmpPath;
}
public function setBasePath($basePath)
{
$this->basePath = $basePath;
}
public function setAllowedExtensions($allowedExtensions)
{
$this->allowedExtensions = $allowedExtensions;
}
public function getBaseTmpPath()
{
return $this->baseTmpPath;
}
public function getBasePath()
{
return $this->basePath;
}
public function getAllowedExtensions()
{
return $this->allowedExtensions;
}
public function getFilePath($path, $imageName)
{
return rtrim($path, '/') . '/' . ltrim($imageName, '/');
}
public function moveFileFromTmp($imageName)
{
$baseTmpPath = $this->getBaseTmpPath();
$basePath = $this->getBasePath();
$baseImagePath = $this->getFilePath($basePath, $imageName);
$baseTmpImagePath = $this->getFilePath($baseTmpPath, $imageName);
try {
$this->coreFileStorageDatabase->copyFile(
$baseTmpImagePath,
$baseImagePath
);
$this->mediaDirectory->renameFile(
$baseTmpImagePath,
$baseImagePath
);
} catch (\Exception $e) {
throw new \Magento\Framework\Exception\LocalizedException(
__('Something went wrong while saving the file(s).')
);
}
return $imageName;
}
public function saveFileToTmpDir($fileId)
{
$baseTmpPath = $this->getBaseTmpPath();
$uploader = $this->uploaderFactory->create(['fileId' => $fileId]);
$uploader->setAllowedExtensions($this->getAllowedExtensions());
$uploader->setAllowRenameFiles(true);
$result = $uploader->save($this->mediaDirectory->getAbsolutePath($baseTmpPath));
if (!$result) {
throw new LocalizedException(
__('File can not be saved to the destination folder.')
);
}
$result['tmp_name'] = str_replace('\\', '/', $result['tmp_name']);
$result['path'] = str_replace('\\', '/', $result['path']);
$result['url'] = $this->storeManager
->getStore()
->getBaseUrl(
UrlInterface::URL_TYPE_MEDIA
) . $this->getFilePath($baseTmpPath, $result['file']);
$result['name'] = $result['file'];
if (isset($result['file'])) {
try {
$relativePath = rtrim($baseTmpPath, '/') . '/' . ltrim($result['file'], '/');
$this->coreFileStorageDatabase->saveFile($relativePath);
} catch (Exception $e) {
$this->logger->critical($e);
throw new LocalizedException(
__('Something went wrong while saving the file(s).')
);
}
}
return $result;
}
}
It's not a permissions issue. I've also tried using the Magento default ImageUploader with a virtualtype, it did not work either. Only result I get is a failure in the File/Uploader framework over here:
if (!file_exists($this->_file['tmp_name'])) {
$code = empty($this->_file['tmp_name']) ? self::TMP_NAME_EMPTY : 0;
throw new \DomainException('The file was not uploaded.', $code);
}
_file is always null.
Does anyone know what could possibly be wrong here?
I will greatly appreciate any suggestions, I am really backed up here.
Thanks,
Kristians
Best Answer
We experienced this issue when trying to upload large files for downloadable products.
It looks like there are a few causes for the same error code (
666
):upload_max_filesize
is smaller than the file being uploaded.You can validate this by checking
phpinfo()
from a web request.If this is the case you can update your PHP-FPM configuration with something like:
upload_max_filesize=100M
then restarting PHP-FPM.upload_tmp_dir
)