Search code examples
phplaravelfilesystemslaravel-9laravel-storage

Laravel 9: Can't write image data to path


I'm using Laravel 9 for making a forum project.

Now for this project, I need to upload some images.

So at the Controller, I added this:

if($request->has('filep')){
    $files = $request->file('filep');
    foreach ($files as $file) {
          $this->uploadImage($file, $questionCreated->id, 'question_image');
    }
}

And here is the uploadImage method:

public function uploadImage($request, $id, $type_image)
    {
        $imagesUrl = UploadFile::upload($request,"Question",$id);
        foreach ($imagesUrl['path'] as $path) {
            UploadedFile::create([
                'upf_object_id' => $id,
                'upf_object_type_id' => $this->objectTable('questions'),
                'upf_path' => $path['upf_path'],
                'upf_uploaded_as' => $type_image,
                'upf_dimension' => $path['upf_dimension'],
                'upf_type' => $imagesUrl['option']['upf_type'],
                'upf_category' => $imagesUrl['option']['upf_category'],
                'upf_mime_type' => $imagesUrl['option']['upf_mime_type'],
            ]);
        }
    }

As you can see I'm calling a helper class (see_it_here) named UploadFile and its upload method:

public static function upload($file,$cat,$queid)
    {
        self::directoryType($file->getClientOriginalExtension());
        self::$mimeType = $file->getMimeType();
        self::$catType = $cat;
        self::$objId = $queid;
        $fileName = self::checkExistFile($file->getClientOriginalName());

        if (in_array($file->getClientOriginalExtension(), self::resizeable())) {
            $file->storeAs(self::route(), $fileName);
            self::resize($file, $fileName);
        }
        $file->storeAs(self::route(), $fileName);
        $file_name_hash = md5($fileName);
        return [
            "path" =>
                array_merge(self::$urlResizeImage, [[
                    "upf_path" => self::route() . $fileName,
                    "upf_dimension" => "fullsize"
                ]]),
            "option" => [
                "upf_object_id" => "",
                "upf_object_type_id" => "",
                "upf_type" => self::$typeFile,
                "upf_category" => self::$catType,
                "upf_mime_type" => self::$mimeType,
                'upf_file_name' => $fileName,
                'upf_file_hash' => $file_name_hash,
            ]
        ];
    }

Now the problem is coming from the resize method which uses Image Intervention for resizing:

public static function resize($file, $fileName)
    {
        $path = self::route();
        foreach (self::size() as $key => $value) {
            $resizePath = self::route() . "{$value[0]}x{$value[1]}_" . $fileName;
            Image::make($file->getRealPath())
                ->resize($value[0], $value[1], function ($constraint) {
                    $constraint->aspectRatio();
                })
                ->save(storage_path($path));
            $urlResizeImage[] = ["upf_path" => $resizePath, "upf_dimension" => "{$value[0]}x{$value[1]}"];
        }
        self::$urlResizeImage = $urlResizeImage;
    }

And the line ->save(storage_path($path)); returns this error:

Can't write image data to path (C:\xampp\htdocs\forum\storage\upload/1401/10/images/questions/77)

enter image description here

I don't know what's really going on here.

So if you know, please let me know...

I would really appreciate any idea or suggestion from you guys.

Here is also my filesystems config.


Solution

  • There are 6 possible problems that I can see.

    First: The directory does not exist.

    Here you can both check for its existence and create it if it does not. Libraries will generally not create directories for you. Replace File here with whatever makes sense in your context:

    File::isDirectory($path) or File::makeDirectory($path, 0777, true, true);
    

    Second: The directory exists but is not writeable.

    Use a guard function to first check for writability at the top of Resize.

    if ( !File::isWritable($path)) throw new NotWritableException("The $path directory is not writable");
    

    Third: the filename is not sanitized and uses characters the underlying OS cannot accept

    A good general case to look for, but in this case it seems correct. In any case use a function like League\Flysystem\WhitespacePathNormalizer::normalizePath

    Fourth: Using the right variable

    You appear to save to $path rather than $resizePath.

    Fifth: OS-level restrictions like disk space limits

    The file_put_contents code in the library you use above makes a bunch of unhelpful assumptions. I'd check for disk space and permissions.

    Sixth: a xampp-level constraint on writable paths in its configs

    Just try to write a file in that directory from anywhere in your code to see if it works (after everything else has been tried), something like

    file_put_contents('C:\xampp\htdocs\forum\storage\upload\1401\10\images\questions/77/test.txt', 'test'); 
    

    which will bubble up the correct exception, before delving into xampp configuration arcana.