0

I'm having some troubles to upload files and data to my server using Angular 2 and PHP.

I've followed this File Upload In Angular 2? to upload the data and file from Angular 2 and all seems to be OK (I can see the data received by printing php://input). My Angular 2 code is something like this:

upload(data: data, file: File): Observable<any> {
  let header = new Headers();
  header.append('Content-Type', 'multipart/form-data');
  header.append('Accept', 'application/json');
  let options = new RequestOptions({ headers: header });

  let formData:FormData = new FormData();
  formData.append('file', file, file.name)
  formData.append('data', JSON.stringify({data}));

  return this.http
    .post('myurl', formData, options)
    .map(response => {
      return response;
    })
    .catch(error => Observable.throw(error.message || error));
}

The problem is that the superglobals $_POST and $_FILES aren't populated, so I can't access them (and the data and file uploaded so). I have the same problem when uploading only data and I solved it manually-populating the $_POST superglobal by doing

$_POST = file_get_contents("php://input");

but here I can't do this because of the $_FILES....

I see in this post PHP - empty $_POST and $_FILES - when uploading larger files that the problem could be that post_max_size or upload_max_filesize are small, but I set them to 100M (enought for my purposes) and still the same. Even I toured memory_limit higiher but nothing.

I think that my problem have to be in my server side, could be the headers I set or some configuration I missed. I discarded any CodeIgniter issue (I'm using last version of CodeIgniter) because I tryed to post to a simple php file and I have the same problem. The simplest server side I'm used is:

<?php
  header('Content-Type: application/json');
  header('Access-Control-Allow-Origin: *');
  header('Access-Control-Allow-Methods: GET, POST');
  header('Access-Control-Allow-Headers: Content-Type');

  exit(var_dump($_POST, $_FILES));
?>

But I get empty arrays...

Does anybody have any idea of what can I do?

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • I have tried a simple non-Angular2 multipart/form-data post request (I mean, a "standard" HTML post request as many years ago) and the $_POST and $_FILES variables were populated correctly... –  Dec 10 '17 at 21:47

1 Answers1

0

I finally have found the solution to this problem.

In non-technical speaking (I'm not an expert), an htpp post multipart/form-data request use a boundary random string to identify the different parameters sent by the client in order to give the server a reference to parse the input. A valid request header looks like this:

Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryYnNrniY34QSJ48LC

In my implementatation, when setting the request header as:

header.append('Content-Type', 'multipart/form-data');

no boundary is set so PHP can't parse the input to populete $_POST and $_FILES. I tried to define my own boundary by appending at the end of the header but it didn't work. But... The solution is even easier: there is no need to specify the Content-Type header, Angular 2 will make it by only passing the data as FormData and performing a post request, creating a valid boundary that PHP can use.

So, a valid code to do this is:

upload(data: data, file: File): Observable<any> {
  let formData:FormData = new FormData();
  formData.append('file', file, file.name)
  formData.append('data', JSON.stringify({data}));

  return this.http
    .post('myurl', formData)
    .map(response => {
      return response;
    })
    .catch(error => Observable.throw(error.message || error));
}

When performing this post request, Angular 2 will add a valid boundary in the multipart/form-data header.

That's all.

If someone can add more technical details about this, it would be great.

Hope this could help someone else.