Search code examples
laravel-5vuejs2image-uploading

Saving blob image in laravel's controller


In my Laravel 5/vuejs 2.6 I upload an image with the vue-upload-component and am sending a requested image blob I try to save it with the controller code like :

    if ( !empty($requestData['avatar_filename']) and !empty($requestData['avatar_blob']) ) {
        $dest_image = 'public/' . Customer::getUserAvatarPath($newCustomer->id, $requestData['avatar_filename']);

        $requestData['avatar_blob']= str_replace('blob:','',$requestData['avatar_blob']);
        Storage::disk('local')->put($dest_image, file_get_contents($requestData['avatar_blob']));
        ImageOptimizer::optimize( storage_path().'/app/'.$dest_image, null );
    } // if ( !empty($page_content_image) ) {

As result, I have an image uploaded, but it is not readable. The source file has 5 Kib, the resulting file has 5.8 Kib and in the browser's console I see the blobs path as

avatar_blob: "blob:http://local-hostels2.com/91a18493-36a7-4023-8ced-f5ea4a3c58af"

Have do I convert my blob to save it correctly?

MODIFIED : a bit more detailed : In vue file I send request using axios :

               let customerRegisterArray =
                    {
                        username: this.previewCustomerRegister.username,
                        email: this.previewCustomerRegister.email,
                        first_name: this.previewCustomerRegister.first_name,
                        last_name: this.previewCustomerRegister.last_name,
                        account_type: this.previewCustomerRegister.account_type,
                        phone: this.previewCustomerRegister.phone,
                        website: this.previewCustomerRegister.website,
                        notes: this.previewCustomerRegister.notes,
                        avatar_filename: this.previewCustomerRegister.avatarFile.name,
                        avatar_blob: this.previewCustomerRegister.avatarFile.blob,
                    };
                console.log("customerRegisterArray::")
                console.log(customerRegisterArray)

                axios({
                    method: ('post'),
                    url: window.API_VERSION_LINK + '/customer_register_store',
                    data: customerRegisterArray,
                }).then((response) => {
                    this.showPopupMessage("Customer Register", 'Customer added successfully ! Check entered email for activation link !', 'success');
alert( "SAVED!!::"+var_dump() )
                }).catch((error) => {
                });

and this.previewCustomerRegister.avatarFile.blob has value: "blob:http://local-hostels2.com/91a18493-36a7-4023-8ced-f5ea4a3c58af" where http://local-hostels2.com is my hosting... I set this value to preview image defined as :

            <img
                class="img-preview-wrapper"
                :src="previewCustomerRegister.avatarFile.blob"
                alt="Your avatar"
                v-show="previewCustomerRegister.avatarFile.blob"
                width="256"
                height="auto"
                id="preview_avatar_file"
            >

and when previewCustomerRegister.avatarFile.blob is assigned with uploaded file I see it in preview image. I show control with saving function in first topic but when I tried to opened my generated file with kate, I found that it has content of my container file resources/views/index.blade.php...

What I did wrong and which is the valid way ?

MODIFIED BLOCK #2 : I added 'Content-Type' in request

axios({
  method: ('post'),
  url: window.API_VERSION_LINK + '/customer_register_store',
  data: customerRegisterArray,
  headers: {
    'Content-Type': 'multipart/form-data'
  }

but with it I got validation errors in my control, as I define control action with request:

public function store(CustomerRegisterRequest $request)
{

and in app/Http/Requests/CustomerRegisterRequest.php :

<?php

namespace App\Http\Requests;

use App\Http\Traits\funcsTrait;
use Illuminate\Foundation\Http\FormRequest;
use App\Customer;
class CustomerRegisterRequest extends FormRequest
{
    use funcsTrait;

    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        $request= Request();
        $requestData= $request->all();

        $this->debToFile(print_r( $requestData,true),'  getCustomerValidationRulesArray $requestData::');
        /* My debugging method to write data to text file 
        and with Content-Type defined above I see that $requestData is always empty
        and I got validations errors
         */

        // Validations rules 
        $customerValidationRulesArray= Customer::getCustomerValidationRulesArray( $request->get('id'), ['status'] );
        return $customerValidationRulesArray;
    }
}

In routes/api.php defined :

Route::post('customer_register_store', 'CustomerRegisterController@store');

In the console of my bhrowser I see : https://i.sstatic.net/HUfhO.jpg, https://i.sstatic.net/o7U56.jpg

I suppose that something is wrong in axios header ? without 'Content-Type' defined my validation rules work ok...

MODIFIED BLOCK #3

I managed to make fetch of blob with metod like :

            var self = this;

            fetch(this.previewCustomerRegister.avatarFile.blob) .then(function(response) {
                console.log("fetch response::")
                console.log( response )

                if (response.ok) {
                    return response.blob().then(function(myBlob) {
                        var objectURL = URL.createObjectURL(myBlob);
                        // myImage.src = objectURL;
                        console.log("objectURL::")
                        console.log( objectURL )

                        console.log("self::")
                        console.log( self )



                        let customerRegisterArray =
                            {
                                username: self.previewCustomerRegister.username,
                                email: self.previewCustomerRegister.email,
                                first_name: self.previewCustomerRegister.first_name,
                                last_name: self.previewCustomerRegister.last_name,
                                account_type: self.previewCustomerRegister.account_type,
                                phone: self.previewCustomerRegister.phone,
                                website: self.previewCustomerRegister.website,
                                notes: self.previewCustomerRegister.notes,
                                avatar_filename: self.previewCustomerRegister.avatarFile.name,
                                avatar: objectURL,
                            };

                        console.log("customerRegisterArray::")
                        console.log(customerRegisterArray)

                        axios({
                            method: 'POST',
                            url: window.API_VERSION_LINK + '/customer_register_store',
                            data: customerRegisterArray,
                            // headers: {
                            //     'Content-Type': 'multipart/form-data'  // multipart/form-data - as we need to upload with image
                            // }
                        }).then((response) => {
                            self.is_page_updating = false
                            self.message = ''
                            self.showPopupMessage("Customer Register", 'Customer added successfully ! Check entered email for activation link !', 'success');
                            alert( "SAVED!!::")
                        }).catch((error) => {







  self.$setLaravelValidationErrorsFromResponse(error.response.data);
                            self.is_page_updating = false
                            self.showRunTimeError(error, this);
                            self.showPopupMessage("Customer Register", 'Error adding customer ! Check Details fields !', 'warn');
                            // window.grecaptcha.reset()
                            self.is_recaptcha_verified = false;
                            self.$refs.customer_register_wizard.changeTab(3,0)
                        });


                    });
                } else {
                    return response.json().then(function(jsonError) {
                        // ...
                    });
                }
            }).catch(function(error) {
                console.log('There has been a problem with your fetch operation: ', error.message);
            });

In objectURL and self I see proper values : https://i.sstatic.net/AQDuX.jpg

1) But checking data on server in laravel's control I see the same values I had at start of my attemps to upload image:

[avatar_filename] => patlongred.jpg [avatar] => blob:http://local-hostels2.com/d9bf4b66-42b9-4990-9325-a72dc8c3a392

Have To manipulate with fetched bnlob in some other way ?

2) If I set :

  headers: {
    'Content-Type': 'multipart/form-data'
  }

I got validation errors that my data were not correctly requested...

?


Solution

  • You're using request type as application/json hence you won't be able to save the image this way, for a file upload a request type should be multipart/form-data in this case you'll need to send request as

    let customerRegisterArray = new FormData();
    customerRegisterArray.put('username', this.previewCustomerRegister.username);
    customerRegisterArray.put('email', this.previewCustomerRegister.email);
    ....
    customerRegisterArray.put('avatar', this.previewCustomerRegister.avatarFile);
    
    console.log("customerRegisterArray::")
    console.log(customerRegisterArray)
    
    axios({
      method: ('post'),
      url: window.API_VERSION_LINK + '/customer_register_store',
      data: customerRegisterArray,
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    }).then((response) => {
         this.showPopupMessage("Customer Register", 'Customer added successfully !Check entered email for activation link !', 'success');
         alert( "SAVED!!::"+var_dump() )
    }).catch((error) => {});