2

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

2
  • did you get the fix? Jun 15, 2020 at 10:22
  • Hey, it turns out I was passing incorrect data to the uploader. It expected that $_FILES would be an array with all the necessary file data, instead it was a string. I updated my code to prepare a proper $_FILES array before the upload is executed. Jan 29, 2021 at 13:39

2 Answers 2

3

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):

  • PHPs 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.
  • The temp path being using to store the uploaded file is not writable (the related setting is upload_tmp_dir )
1
  • same for me ... and setting max_post_size
    – cljk
    Oct 25, 2022 at 10:21
1

I have had the same issue today. It ended up with the situation that within: _setUploadFileId() variable $_FILES[$fileId] did not have correct values. For example:

2020-09-29T15:05:45+00:00 INFO (6): array (
  'name' => 'WhateverFileName.png',
  'type' => '',
  'tmp_name' => '',
  'error' => 1,
  'size' => 0,
)

Which means there is something wrong with the Image File itself and does not contain relevant meta data that can be read by Magento to Upload it to relevant location

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.