3

I am trying to implement a image upload with other form elements with dropzone.js in laravel. So far I've managed to display the drag and drop image upload view with other form elements. And also get POST details from the submitted form. But when dropzone is passing the uploaded image to the database data save function it encode image with base64. I think I've managed to get the file extension also. And when I submit the button it gives me this error "Call to a member function move() on string" . Please put me in the right direction.

Here is the Form

<form class="form-horizontal" action="{{ route('save-slider-content') }}" method="POST" enctype="multipart/form-data">
   {{ csrf_field() }}
   <div class="box-body">
     <div class="form-group">
       <label for="inputEmail3" class="col-sm-2 control-label">Title</label>
       <div class="col-sm-10">
         <input type="text" class="form-control" name="sliderTitle" id="sliderTitle" placeholder="Title of the post goes here">
       </div>
     </div>
     <input type="hidden" name="date" id="date" value="<?php echo date("d-m-Y"); ?>">
     <div class="form-group">
       <label for="image" class="col-sm-2 control-label">Image</label>
       <input hidden id="file" name="file"/>
       <div class="col-sm-10">
         <div class="dropzone needsclick dz-clickable" id="fileUpload">
           <div class="dz-default dz-message">
              <i class="fa fa-image fa-5x"></i>
              <h3 class="sbold">Drop an image here to upload</h3>
              <span>You can also click to open file browser</span>
          </div>
         </div>
       </div>
     </div>
     <div class="form-group">
       <label for="inputEmail3" class="col-sm-2 control-label">Link</label>
       <div class="col-sm-10">
         <input type="text" class="form-control" name="sliderLink" id="sliderLink" placeholder="Provide a link">
       </div>
     </div>
   </div><br>
   <!-- /.box-body -->
   <div class="box-footer">
     <button type="submit" class="btn btn-default">Cancel</button>
     <button type="submit" class="btn btn-info pull-right">Post</button>
   </div>
   <!-- /.box-footer -->
 </form>

Here is the dropzone configuration

<script type="text/javascript">
Dropzone.options.fileUpload = {
  url: "save-slider-content",
  addRemoveLinks: true,
  accept: function(file) {
      let fileReader = new FileReader();

      fileReader.readAsDataURL(file);
      fileReader.onloadend = function() {

          let content = fileReader.result;
          $('#file').val(content);
          file.previewElement.classList.add("dz-success");
      }
      file.previewElement.classList.add("dz-complete");
  }
}
  </script>

Route

Route::post('store-slider-content', [ 'as' => 'save-slider-content', 'uses' => 'SliderContent@save_slider_data']);

save_slider_data function in Controller

public function save_slider_data(Request $request)
{
  $slider = new Slider;
  $slider->title = $request->sliderTitle;
  $slider->title_sin = $request->sliderTitleSin;
  $slider->date = $request->date;
  $slider->link = $request->sliderLink;

  $file = $request->file;;
  $image_data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $file));
  $f = finfo_open();
  $mime_type = finfo_buffer($f, $image_data, FILEINFO_MIME_TYPE);
  $imageName = time().'.'.$mime_type;
  $image_data->move(public_path('slider_uploads'), $imageName);
  return response()->json(['success'=>$imageName]);

  $slider->img_url = $imageName;

  $slider->save();
}
Kasun
  • 473
  • 1
  • 10
  • 32

2 Answers2

3

Edited to include the logic for either Symfony\Component\HttpFoundation\File\File or Illuminate\Support\Facades\File (Illuminate\Filesystem\Filesystem)

move is a method of a File object, but $image_data is just a string. So one thing you could do is write the decoded image to a temp file, instantiate a File of it, and move it, like

//... your code ...
   $image_data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $file));
  // ... and then:
//grab a new tmp file
    $tmpFilePath=sys_get_temp_dir().'/'.uniqid(); 
    //write the image to it
    file_put_contents($tmpFilePath, $image_data); 
    //move it. 
    //give it a name
     $imageName = time().'.'.str_replace("image/","",$mime_type);
    //if using Symfony\Component\HttpFoundation\File\File;
    //get an instance of File from the temp file and call ->move on it
    $tmpFile=new File($tmpFilePath);
    $tmpFile->move(public_path('slider_uploads'), $imageName);
    //or if using File facade
    File::move($tmpFilePath, public_path("slider_uploads/$imageName")); 
//...and then, back to your code...
  $slider->img_url = $imageName;
  $slider->save();
  return response()->json(['success'=>$imageName]);
}
chiliNUT
  • 18,989
  • 14
  • 66
  • 106
  • now I get this error **Call to undefined method Illuminate\Support\Facades\File::move()** even though I've added **use File** in the controller already – Kasun Feb 14 '18 at 18:06
  • @Kasun interesting! I was actually using `Symfony\Component\HttpFoundation\File\File`, I updated with the correct code for `Illuminate\Support\Facades\File` – chiliNUT Feb 14 '18 at 18:30
1

You can do this:

In config/filesystems.php, register a new disk slider_uploads

'disks' => [

    'local' => [
        'driver' => 'local',
        'root'   => storage_path('app'),
    ],
    'slider_uploads' => [
        'driver' => 'local',
        'root'   => public_path('slider_uploads')
    ]
]

And then use your new disk in storing your image

$image_data = $request->file; 

@list($type, $image_data ) = explode(';', $image_data );
@list(, $image_data ) = explode(',', $image_data ); 
if($image_data !=""){ // storing image in public/slider_uploads/ Folder 
    \Storage::disk('slider_uploads')->put($imageName, base64_decode($image_data )); 
} 
Dexter Bengil
  • 5,995
  • 6
  • 35
  • 54
  • It works thanks ! but I think I've a mistake in getting file extension after it save the image, image name it shows like **1518632094.image/png** so in slider_uploads folder instead of images **1518632094.image** these folders are created – Kasun Feb 14 '18 at 18:21