首页 > 解决方案 > 如何在 Laravel 中构建图像上传对象并附加到请求

问题描述

我正在尝试构建图像上传对象并附加到 Laravel 中的请求。

我目前有一个中间件,它拦截请求并检查其中是否有 base64 图像字符串,如果有,它将其转换为图像对象并将其附加回请求。

我未能成功地将转换后的图像附加到请求中,作为一个实例,Illuminate\Http\UploadedFile我尝试了一些我发现的最接近的事情,UploadedFile::fake()->image('avatar.jpg');但是我如何使用自己的 base64 转换后的图像而不是生成假图像来查看UploadedFile Api我想不出一个解决方案。

这就是我到目前为止所拥有的

<?php

    namespace App\Http\Middleware;

    use Closure;
    use Illuminate\Support\Facades\Validator;
    use Illuminate\Support\Facades\Storage;
    use Illuminate\Http\UploadedFile;

    class Base64EncodedImageHandler
    {
        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @return mixed
         */
        public function handle($request, Closure $next)
        {
            if ($request->has('photos')) {

                $validator = Validator::make($request->all(), [
                    'photos' => 'nullable|array|filled',
                    'photos.*' => 'required_unless:photos,'.null.'|image',
                ]);

                if ($validator->fails()) {

                    $images = collect($request->input('photos'))->map(function ($item, $key) {

                        if (preg_match('/^data:image\/(\w+);base64,/', $item)) {
                            $data = substr($item, strpos($item, ',') + 1);

                            $data = base64_decode($data);

                            // Testing to see if the image decoding worked
                            // Storage::disk('local')->put("public/test/".uniqid().".png", $data);


                            // Build image object


                            return $data;

                        }

                        return $item;
                    });

                    $request = $request->merge(['photos' => $images]);

                }

                // Dumping request object here
                dd($request);

            }

            return $next($request);
        }
    }

根据我得到的答案,我能够实现我的最初目标

<?php

    namespace App\Http\Middleware;

    use Closure;
    use Illuminate\Support\Facades\Storage;
    use Illuminate\Http\UploadedFile;

    class Base64EncodedImageHandler
    {
        /**
         * Handle an incoming request.
         *
         * @author Sayra
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @return mixed
         */
        public function handle($request, Closure $next)
        {
            // Add an additional method
            $request::macro('setConvertedFiles', function ($files) {
                $this->convertedFiles = $files;
                return $this;
            });

            if ($request->has('portrait')) {

                $images = collect($request->input('portrait'))->map(function ($item, $key) {

                    if (preg_match('/^data:image\/(\w+);base64,/', $item)) {
                        $item = substr($item, strpos($item, ',') + 1);
                        $image = base64_decode($item);

                        $path = 'public/test/';
                        $name = uniqid();
                        $extension = '.jpg';

                        // Store converted file
                        if (Storage::put($path.$name, $image)){

                            return new UploadedFile(storage_path('app/').$path.$name, $name.$extension, 'image/jpeg');
                        }
                    }

                })->all();

                // Added base64 converted files to request, clear base64 params
                $photos = $request->photos? $request->photos : [];
                $merge = array_merge($photos, $images);
                $request->setConvertedFiles(['photos' => $merge]);
                $request->merge(['photos' => $merge]);
                $request->merge(['portrait' => []]);



                // the isValid() method fails as the file was not a direct upload
                dd($request->file('photos.0')->isValid(),$request->file('photos'),$request);

            }

            return $next($request);
        }
    }

我当前唯一的问题是,当isValid或被is_uploaded_file()调用时,图像被视为无效图像,我想正确伪造图像上传,以便 base64 转换后的图像能够正常工作并经历与普通图像相同的过程。谢谢。

标签: phplaravelimage

解决方案


您可以尝试Symfony\Component\HttpFoundation\File\UploadedFile创建图像对象(您应该首先将 base64 文件保存在临时位置,因为UploadedFile需要路径)。然后在你的Base64EncodedImageHandler使用 trait 中Illuminate\Http\Concerns\InteractsWithInput

你将需要这个方法:protected function convertUploadedFiles(array $files)它接受 symfony UploadedFile 的数组。这将使Illuminate\Http\UploadedFile对象。现在,当您说$request->merge(['photos' => $images])您的“照片”将是您可以操作的 UploadedFile 对象数组时。

我不确定,但也许你的$request->file()会仍然是空的。如果这是真的,您可以创建新请求,用原始请求中的所有其他数据填充它,但对于文件,请提供转换后的 UploadedFile 数组。

还要检查这个https://github.com/laravel/framework/issues/10791#issuecomment-213529251 他们正在使用自定义FormRequest特征来覆盖->all()方法。您可以尝试使用相同的方法,->allFiles()甚至覆盖$files属性。请记住它接受FileBag,而不是array


推荐阅读