2

I am experiencing a weird behaviour when trying to upload a file from Angular 5.2 to to a Laravel 5.5 application. The file data is not visible/accessible on server side.

I've tried different headers and approaches but they all seem to fail -

HTML:

<input type="file" (change)="handleFileInput($event.target.files)" multiple/>

JS:

handleFileInput(files: FileList) {
        let formData = new FormData();
        formData.append('file', files[0], files[0].name);

        let headers = new HttpHeaders({
            'Content-Type': 'application/json' // also tried 'multipart/form-data' and undefined
        });
        const req = new HttpRequest('POST', 'https://uploader.test/upload', formData, {headers: headers});
        this.http.request(req).subscribe(res => console.log(res)); 
    }

on Laravel side

logger('$request', [$request->all()]);

prints []

Also tried $request->file('file') and Input::file('file') which both return null.

The Browser's developer tools shows the following payload is submitted:

------WebKitFormBoundaryqZauUjRcPnD6wRmx
Content-Disposition: form-data; name="file"; filename="31562207_10106275826879542_6883202223082307584_n.jpg"
Content-Type: image/jpeg


------WebKitFormBoundaryqZauUjRcPnD6wRmx--

UPDATE The controller code is really super simple

 public function upload(Request $request)
    {
        logger('$request->all()', [$request->all()]);    // prints $request->all() [[]] []
        logger('Input::all()', [Input::all()]);    // prints Input::all() [[]] []
        logger('input.file', [ Input::file('file') ]);    // prints input.file [null] []
        logger('request.file', [ $request->file('file')]);    // prints request.file [null] []
        logger('$_POST', [$_POST]);    // prints $_POST [[]] []
        logger('$_FILES', [$_FILES]);    // prints $_FILES [[]] []
}

When I replace formData with an object:

const req = new HttpRequest('POST', 'https://uploader.test/upload', {
            data: formData,
            file: files[0],
            test: '123'
        }, {headers: headers});
        this.http.request(req).subscribe(res => console.log(res));

I get [{"data":[],"file":[],"test":"123"}]

I've also tried the following workarounds (found in various forums):

  • Laravel workaround - formData.append('_method', 'PUT');
  • using http.post instead of http.request
  • adding options with contentType: false and processData: false
  • Already tried solutions suggested in other questions such as Angular-5 File Upload

In each one of my tests, the file data itself is not being passed on to the server.

Any help would be greatly appreciated!

UPDATE 2 - a screenshot of the request headers enter image description here

dev7
  • 6,259
  • 6
  • 32
  • 65
  • judging from the payload you should be getting the file by $request->file, can you add your controller code for laravel side? – Hussein May 06 '18 at 06:26
  • Well files can only be uploaded with `multipart/form-data`, which should be what made you get the browser output, php/laravel should have thus received it, could you share some of the controller code? – Quezler May 06 '18 at 06:26
  • @Hussein updated with controller code, which really just tries to log the request data. – dev7 May 06 '18 at 14:05
  • @Quezler updated with controller code, which really just tries to log the request data. When I set `multipart/form-data` manually, I get "Missing boundary in multipart/form-data POST data" error. – dev7 May 06 '18 at 14:08
  • @Yani can you show all the headers that are sent by the request? normally the boundary is set in the header, and should contain `------WebKitFormBoundaryqZauUjRcPnD6wRmx` as value – Quezler May 06 '18 at 14:24
  • @Quezler added a screenshot. Thanks! – dev7 May 06 '18 at 15:44
  • @Yani [apparently if you set the header to `undefined` it just might work for some weird reason](https://stackoverflow.com/questions/39280438/fetch-missing-boundary-in-multipart-form-data-post) – Quezler May 06 '18 at 17:07
  • I have had the same problem, and even Hussein answer solved my problem in local env, however when I moved to production env, I have the same problem, and after long investigation, I came to know that Network Firewall blocks the contents. I am having the same problem in AWS too, uploading the file to EC2 – Musa Haidari Jul 07 '18 at 12:37
  • @dev7, can you look into this question? I think you can answer it. https://stackoverflow.com/questions/65678554/file-upload-from-angular-9-to-laravel-not-working – Deepu Sasidharan Jan 18 '21 at 05:20

1 Answers1

2

let's try this:

for js file handling add this:

import {Injectable} from "@angular/core";
import {HttpClient} from "@angular/common/http";

@Injectable()
export class FileUploader{
  constructor(public http:HttpClient){}

  handleFileInput(files: any){
    let xhr = new XMLHttpRequest();
    let form = new FormData();
    let token = "YOUR_TOKEN";
    form.append('file', files[0], files[0].name);
    xhr.onload = (e) =>{
      console.log('file uploaded');
    };
    xhr.open('POST', "https://uploader.test/upload", true);
    xhr.withCredentials = true;
    xhr.setRequestHeader('Authorization', 'Bearer ' + token);
    xhr.send(form);
  }
}

now for laravel side add this:

public function saveFile(Request $request){
   $path = $request->file('file')->store('uploaded');
   return response()-json($path);
}

in the js code i used the HttpClient, you can use XMLHttpRequest, try it, if it didn't work let me know

Hussein
  • 1,143
  • 1
  • 9
  • 16
  • I'm getting the following error - `Symfony\Component\Debug\Exception\FatalThrowableError: Call to a member function store() on null`. The file is not coming through. I removed all middlewares just to make sure and still. – dev7 May 06 '18 at 15:40
  • ok before you send the request can you make sure it's there in the array of `files` ? – Hussein May 06 '18 at 15:45
  • There is - this is what console log prints - `FileList {0: File(59965), length: 1} 0 : File(59965) {name: "tick_answered.jpeg", lastModified: 1525393170101, lastModifiedDate: Thu May 03 2018 17:19:30 GMT-0700 (PDT), webkitRelativePath: "", size: 59965, …} length : 1` – dev7 May 06 '18 at 15:46
  • Yes this works, however it is outside of angular scope and therefore the http interceptors will not run (in charge of adding jwt token and api key). Any idea how to make this work using the http service? – dev7 May 06 '18 at 16:14
  • i edited the answer, you can set any headers you wants through `xhr.setRequestHeader` – Hussein May 06 '18 at 16:41
  • the latest angular version should work with uploading files, check this: https://angular.io/guide/http – Hussein May 06 '18 at 16:47
  • Thanks for your replies - I found out that the issue was with the HTTP interceptor overriding the headers and setting `application/json` header. I somehow missed it while debugging. +1 for your help. Your method did help but I wouldn't recommend it to someone who came across this question since the right solution allows using the Http service.Thanks. – dev7 May 06 '18 at 20:46