Angular 2 http.post FormData() to PHP to upload a file - php

I have a project using A2 CLI, and I'm trying to upload a file using an input tag with type="file". I have things functioning as far as the overall workflow goes, but I am having trouble getting the file data from client to server.
I have the following code in TypeScript:
myFnc(event){
let fileList: FileList = event.target.files;
if(fileList.length > 0) {
let file: File = fileList[0];
console.log(file);
console.log(file.name);
let formData:FormData = new FormData();
formData.append('uploadFile', file, file.name);
let headers = new Headers();
/*
this was the culprit:
headers.append('Content-Type', 'multipart/form-data');
worked for me by changing it to:
*/
headers.append('enctype', 'multipart/form-data');
headers.append('Accept', 'application/json');
let options = new RequestOptions({ headers: headers });
console.log(formData);
console.log(options);
this.http.post('./assets/data/upload-persona-document.service.php', formData, options)
.map(res => res.json())
.catch(error => Observable.throw(error))
.subscribe(
data =>{
console.log(data);
},
error =>{
console.log(error);
}
)
}
}
I get no errors and get the results I'm inspecting in the console. (I understand that the console.log(formData) won't actually output formData's contents. I've tried .entries() but I've read that FormData methods are not well supported in TS.)
In upload-persona-document.service.php:
<?php
$target_dir = "../docs/Personas/";
$json = array();
$postData = file_get_contents("php://input");
$input = json_decode($postData);
$json['input'] = $input;
$json['post'] = ($_POST);
$json['files'] = $_FILES;
$target_file = $target_dir . basename($_FILES["uploadFile"]["name"]);
$uploadOk = 1;
$imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);
echo json_encode($json);
// ...a bunch of code that will act on the data when I can finally get it correctly...
When I get the response back, I get:
[Log] {input: null, post: [], files: []} (main.bundle.js, line 1117)
I'm stumped at what I'm missing.

So after a bit more digging and experimentation it turned out that I had to change Content-Type to enctype in the headers.append() line above (updated that bit.)

Related

slim 4 - multiple file upload empty $_FILES array

I'm havong some trouble to upload multiple file at once in my vue and php app. I'm using slim to have an endpoint where upload request is posted:
On the server side I have this code to test if all works fine:
$app->post('/compress', function(Request $request, Response $response){
$files = $request->getUploadedFiles();
var_dump($files); // this will result in empty
//return $response;
});
In my javascript code, inside a vue method I have this code that is called when the file input will change:
let formData = new FormData();
for(let i; i < this.$refs.selectedImages.files.length; i++){
formData.append('images[]', this.$refs.selectedImages.files[i]);
}
let config = {
header: {
'Content-Type': 'multipart/form-data',
},
withCredentials: true
}
axios.post('http://localhost:3000/compress', formData, config)
.then( (response) => {
console.log(response, response.data);
});
tha result is that the var_dump will give me empty. How I can fix?
Can you try this one?
for( var i = 0; i < this.$refs.selectedImages.files.length; i++ ){
let file = this.$refs.selectedImages.files[i];
formData.append('images[' + i + ']', file);
}
After a lot of debug I've fixed the code. The problem was with the for() loop that seems not working to iterate FileList in my case. I've replaced it with a forEach() and voilà! The server started to get the uploaded files.
let files = this.$resf.selectedImages.files;
let formData = new FormData();
files.forEach( (el) => {
formData.append('images[]', el);
});

How to receive $ FILES in PHP from Ionic?

I'm using FormData to send a file from ionic with angular to PHP, but in the PHP backend when you make var dump $_FILES appear empty.
This is my code in .ts:
file: File;
changeListener($event): void {
this.file = $event.target.files[0];
console.info(this.file); //First console info
const formData = new FormData();
const blobFile = new Blob([this.file], { type: this.file.type });
formData.append("file", blobFile, "filename");
this.myService.testing(formData).subscribe( resp => {
},(error)=>{
console.info(error);
})
}
In the service:
testing(data) {
return this.http.post(url, body, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
}
The PHP Backed :
$postdata = file_get_contents("php://input"); // this shows me the contents of the file
var_dump($_FILES); // returns an empty array
So, what's my mistake? Am I sending badly from Ionic or am I getting bad in PHP ?
I'm using codeigniter 3
Thanks !

Problem to upload image from Angular to php

I'm trying to upload an image from an angular application with php backend, but the file arrive as null to backend.
fileUploaded(event) { // called each time file input changes
let fileList: FileList = event.target.files;
if (fileList && fileList[0]) {
let file: File = fileList[0];
var reader = new FileReader();
reader.readAsDataURL(fileList[0]); // read file as data url
this.format.File = file;
reader.onload = (ev) => { // called once readAsDataURL is completed
this.format.Picture = ev.target['result'];
}
}
}
This is the caller to the service
createFormat(){
this.format.Label = this.format.Name;
const formData = new FormData();
formData.append('formatLogo', this.format.File);
this.formatService.uploadLogo(formData).subscribe()
}
this is the service.
I tried to use Content-Type also, with the same result
uploadLogo(formData){
let headers = new HttpHeaders();
headers.append('enctype', 'multipart/form-data');
headers.append('Accept', 'application/json');
let options = { headers: headers }
return this.http.post(this.formatsPath + '/uploadLogo', formData, options);
}
This is the request payload
------WebKitFormBoundaryUlyYDb5WjslMf3nw
Content-Disposition: form-data; name="formatLogo"; filename="fileName.jpg"
Content-Type: image/jpeg
------WebKitFormBoundaryUlyYDb5WjslMf3nw--
This is the server side
function uploadLogo(){
$name = $_FILES['formatLogo']['name'];
--code--
}
The server side, obviosly, have more things to do. But the simple file is empty, so it's not useful to post everything.
I can't get the mistake. :'(
Someone smarter than me can provide his help? Please

How to send both a file and JSON data to the server

tl;dr:
Using Angular 6 on the front end and PHP with Phalcon on the backend, I can send JSON data or a File with no problem but I am having a problem sending both in the same request.
Previously I was sending JSON data to the server using something like this
const HTTP_OPTIONS = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
}),
observe: 'response'
};
post(endPoint: string, body: object): Observable<any> {
return this.http.post<any>(this.apiUrl + endPoint, body, HTTP_OPTIONS)
.pipe(
tap(result => this.log(JSON.stringify(result, null, 2))),
catchError(this.handleError('post', []))
);
}
And I was able to get the data from PHP using Phalcon with
$app = new \Phalcon\Mvc\Micro();
$app->post('/upload', function() use ($app) {
$input = $app->request->getJsonRawBody();
// $input now contains my JSON data
});
Some time later, I needed to send a file so I used this answer with some minor modifications:
postFile(fileToUpload: File, endpoint: string): Observable<any> {
const formData: FormData = new FormData();
formData.append('fileKey', fileToUpload, fileToUpload.name);
return this.httpClient
.post(endpoint, formData, { headers: {'Authorization': this.jwt} }).pipe(
tap(result => this.log(JSON.stringify(result, null, 2))),
catchError(this.handleError('post', []))
);
}
And I received my file with no problems using the documentation as a guide:
$app->post('/uploads', function() use ($app) {
if ($app->request->hasFiles() == true) {
foreach ($app->request->getUploadedFiles() as $file) {
$file->moveTo('files/' .$file->getname());
}
} else {
$app->response->setStatusCode(400)->sendHeaders();
$app->response->setJsonContent(['error' => 'no file']);
return $app->response;
}
});
The problem: Now I would like to send both a file and some JSON data at the same time. I can always just upload the file and then send the data separately but I don't think that's the right way to do it. I don't want to make more than the minimum number of network calls.
What I've tried: Using the file upload code and simply appending another field to my FormData object with my JSON data
formData.append('fileKey', fileToUpload, fileToUpload.name);
formData.append('data', JSON.stringify(data));
and a variation of that
formData.append('fileKey', fileToUpload, fileToUpload.name);
formData.append('data', new Blob([JSON.stringify(data), {type: 'application/json'}]);
Either way, on the backend I can get the file but $app->request->getJsonRawBody and $app->request->getRawBody are empty.
I also tried using the original JSON-sending code and just changing a bit to include the file but with no success.
post(fileToUpload: File, data: CustomData): Observable<any> {
this.messageService.add('uploaded file');
const formData: FormData = new FormData();
formData.append('fileKey', fileToUpload, fileToUpload.name);
formData.append('data', JSON.stringify(data), 'data');
return this.http
.post(this.apiUrl + 'uploads/', {'data': data, 'file': fileToUpload}, HTTP_OPTIONS).pipe( // file is empty on the server like this
tap(result => this.log('POST file :\n' + JSON.stringify(result, null, 2))),
catchError(this.handleError('post', [], 'fileUpload'))
);
}
I can easily send either my JSON data or the file but not both.
I searched the Phalcon documentation and several QAs on sending files and/or JSON with Angular but I cannot figure out how to make this work.
You are sending json as text in post request, so instead of $app->request->getJsonRawBody you should try something like
$rawJson=$app->request->getPost('data');
$object=json_decode($rawJson);
you can get your json as #Błażej Kowalczyk said
$this->request->getPost()
and you can check for files and get them
if ($this->request->hasFiles()) {
foreach ($this->request->getUploadedFiles() as $file) {
// $file is an instance of Phalcon\Http\Request\File
var_dump($file->getName());
}
}
check these pages for more information
https://docs.phalconphp.com/3.4/en/api/phalcon_http_request
https://docs.phalconphp.com/3.4/en/api/phalcon_http_request_file

Accessing FormData file on the PHP server (symfony)

My problem is that I don't know how to get the file and file name on the server side after making ajax request with FormData. Let me add that it works for strings on the other hand. I also see the file and details in the request via FireBug.
Here is my code:
JavaScript:
var form = document.getElementById('file-form');
var fileSelect = document.getElementById('file-select');
var uploadButton = document.getElementById('upload-button');
// Get the selected files from the input.
var files = fileSelect.files;
// Create a new FormData object.
var formData = new FormData();
var myArray = [];
// Loop through each of the selected files.
for (var i = 0; i < files.length; i++) {
var file = files[i];
console.log(file.name);
myArray[i] = file.name;
// Check the file type.
if (!file.type.match('image.*')) {
continue;
}
// Add the file to the request.
formData.append('photos[]', file, file.name);
}
var xhr = new XMLHttpRequest();
// Open the connection.
xhr.open('POST',
'http://localhost/amsprojektgit/amsprojekt/admin/web/fileupload', true);
xhr.onload = function () {
if (xhr.status === 200) {
// File(s) uploaded.
alert('Files uploaded');
} else {
alert('An error occurred!');
}
};
xhr.send(formData);
Server side PHP (Symfony2 container)
public function fileUpload(Request $request)
{
$upload = $_POST;
$logger = $this->get('logger');
$logger->info($upload);
$logger->error('');
die();
}
The response via FireBug looks like this:
-----------------------------269272101016568
Content-Disposition: form-data; name="photos"; filename="elektpolaniec2.jpg"
Content-Type: image/jpeg
ÿØÿà�JFIF��H�H��ÿá#Exif��II*����������������¬������r������z��(�������
��������������2�������
������ ��� ��1�(���©��i�������$�� ������0220� ����0100 ������������
������ ������� ����X����������������������� ��"�������'���
�P���
��������������������������� �������
����!��¢��������£�������£�������¤��������¤��������¤��������¤����)��¤�
������¤��������¤��������¤�������� ¤��������
¤������������������������1������9��(�����������A������÷������H�����
�H������2014:02:28 11:05:03�Panasonic�DMC-FX01�PaintShop Pro 15,00���������������������������2013
:06:20 15:42:46�2013:06:20 15:42:46�
It doesn't log anything. Do you have an idea how can I access filenames of the files sent and the content of files themselves?
Thank you for the anser.
Uhm.. In plain PHP the files are stored in a temporary directory and the file information is served through the $_FILES array.
In Symfony we don't wish to use the superglobal array's directly but we could for example use the Request object. For file uploads you should read this.
Your Question
In your JS you have
formData.append('photos[]', file, file.name);
So that means symfony will get that in an array as photos.
$uploads = $request->files->get('photos');
$uploads is an Array of File objects. You will need to loop though $uploads and process each file.
Side note
If you are not uploading multiple in one request and want just an upload, not as an array then change your JS to:
formData.append('photo', file, file.name);
Then in Symfony you would use
$upload = $request->files->get('photo');
And $upload is a File reference

Categories