1

NodeJS devs, I have a situation where I have to upload local images from NodeJS to PHP Server. There's no error, the request is successful 200 OK, but the picture does not appear in the PHP server.

Note: I am a nodeJS developer, don't have much experience in PHP.

Here's what wanna do:

In NodeJs, there's a list of files, Now one by one I want to append these files into formData, after that, I have to post this form data to the PHP server so that the pictures are uploaded to the PHP server,

In PHP server, at the first line, it is receiving the files from the post request and then with loop moving files with supported extension one by one to the upload directory and after the loop completes it sends back a response with an array containing files' download URL

Everything is working, I've consoled everything and everything has the perfect values and even the HTTPS POST request is successful but the PHP server there is no images, PHP server is not receiving files in the request so looks like multipart data is not working in NodeJs.

Looks like formData is not working properly in NodeJs because the same code works on client JS in the browser.

NodeJS:-

 const Axios = require('axios');
 const Fs = require('fs');
 const FormData = require('form-data');



 var formData = new FormData();

 //here allFiles is an array of object , each object contains 1 file with details like local file path ,name,size
for (var index = 0; index < allFiles.length; index++) { //Append multiple files to formData.

            let currentFile = allFiles[index]
            //createReadStream Retyrns fileData
            let fileWithInfo = await Fs.createReadStream(currentFile.uri)
            formData.append("files[]", fileWithInfo );

       }
 Axios.post('example.com/upload.php',formData,
     {
         headers: formData.getHeaders()
     })
     .then(d => console.log("DONE=>>>> ", d.data))
     .catch((f) => console.log('FAILED=>> ', f))

    });

PHP CODE:-

<?php
// Count total files
$countfiles = count($_FILES['files']['name']);

// Upload directory
$upload_location = "uploads/";

// To store uploaded files path
$files_arr = array();

// Loop all files
for($index = 0;$index < $countfiles;$index++){

   // File name
   $filename = $_FILES['files']['name'][$index];

   // Get extension
   $ext = pathinfo($filename, PATHINFO_EXTENSION);

   // Valid image extension
   $valid_ext = array("png","jpeg","jpg");

   // Check extension
   if(in_array($ext, $valid_ext)){

     // File path
     $path = $upload_location.$filename;

     // Upload file
     if(move_uploaded_file($_FILES['files']['tmp_name'][$index],$path)){
        $files_arr[] = $path;
     }
   }

}

echo json_encode($files_arr);
die;

Kashan Haider
  • 1,036
  • 1
  • 13
  • 23
  • Right now as a temporary solution I am using restler library but it can only send single file in 1 request, i want a solution that can upload multiple files to PHP server. – Kashan Haider Oct 17 '20 at 15:38
  • have you tested that request is reaching the server – Chandan Oct 25 '20 at 11:25

5 Answers5

1

https://github.com/form-data/form-data#buffer-getbuffer

const { readFile } = require('fs/promises');

for (let index = 0; index < allFiles.length; index++) {
  const currentFile = allFiles[index];
  const fileWithInfo = await readFile(currentFile.uri);
  formData.append('files[]', fileWithInfo);
}

axios.post('https://example.com/', formData.getBuffer(), formData.getHeaders());

// you have to send files as buffer

there is also solution with stream https://stackoverflow.com/a/53126159/8784402

const response = await axios({
        method: 'post',
        url: 'http://www.yourserver.com/upload',
        data: formData,
        headers: {
        'content-type': `multipart/form-data; boundary=${form._boundary}`,
        },
    });
nkitku
  • 4,779
  • 1
  • 31
  • 27
  • Hello nkitku, thank you for your time, I have tried both of these solutions, the result is same not receiving the file on PHP server. https://i.postimg.cc/dVNmgKbN/Screenshot-2020-10-25-at-3-10-43-PM.png – Kashan Haider Oct 25 '20 at 10:39
1
Axios.post('example.com/upload.php', formData, {
  headers: formData.getHeaders()
})
.then(d => console.log("DONE=>>>> ", d.data))
.catch((f) => console.log('FAILED=>> ', f));

you are missing the data which is formData in your case from axios post request you can either directly pass formData or call formData.getBuffer().

Chandan
  • 11,465
  • 1
  • 6
  • 25
  • Hello Chandan, thank you for your response, I made a specific code for posting it on StackOverflow, so mistakenly removed formData from StackOverflow however the original code contains formData and still does not work. – Kashan Haider Oct 25 '20 at 10:41
1

Maybe my answer does not solve, but i advise few changes in PHP code. For sure, that keys in $_FILES array could not be numbers its better to use foreach instead of for. I allowed myself to change your code a bit to make it smaller

<?php
// Upload directory
$upload_location = "uploads/";

// To store uploaded files path
$files_arr = array();

// Valid image extension
$valid_ext = array("png","jpeg","jpg");

foreach($_FILES['files']['name'] as $key => $file) {
    if(
        in_array(pathinfo($_FILES['files']['name'][$key], PATHINFO_EXTENSION), $valid_ext)
        &&
        move_uploaded_file($_FILES['files']['tmp_name'][$key],$upload_location.$_FILES['files']['name'][$key])
    ) {
        $files_arr[] = $upload_location.$_FILES['files']['name'][$key];
    } else {
        //Only for debugging
        $files_arr[] = 'Not uploaded: '.$upload_location.$_FILES['files']['name'][$key];
    }
}

echo json_encode($files_arr);
die;
1
<?php
// Count total files
var_dump($_FILES['files']);

$countfiles = count($_FILES['files']['name']);
echo $countfiles;

// Upload directory
$upload_location = "uploads/";

// To store uploaded files path
$files_arr = array();

// Loop all files
for($index = 0;$index < $countfiles;$index++){
  echo $index;

   // File name
  $filename = $_FILES['files']['name'][$index];
  echo $filename;

   // Get extension
  $ext = pathinfo($filename, PATHINFO_EXTENSION);
  echo $ext;

   // Valid image extension
   $valid_ext = array("png","jpeg","jpg", "csv");

   // Check extension
   if(in_array($ext, $valid_ext)){

     // File path
     $path = $upload_location.$filename;

     // Upload file
     if(move_uploaded_file($_FILES['files']['tmp_name'][$index],$path)){
        $files_arr[] = $path;
     }
   }

}

/* echo json_encode($files_arr); */
die;
const Axios = require('axios');
 const Fs = require('fs');
 const FormData = require('form-data');

const allFiles = [
  {uri: 'my/Spark_Dataset/combin.csv'},
  {uri: 'my/Spark_Dataset/combine-csv.csv'},
  // {uri: 'C:\\Users\\my\\combine-csv.csv'}
];


(async function() {
  var formData = new FormData();

  //here allFiles is an array of object , each object contains 1 file with details like local file path ,name,size
  for (var index = 0; index < allFiles.length; index++) { //Append multiple files to formData.
    // console.log(index);

    let currentFile = allFiles[index]
    //createReadStream Retyrns fileData
    // console.log(currentFile);
    let fileWithInfo = await Fs.createReadStream(currentFile.uri)
    formData.append("files[]", fileWithInfo );
  }

  console.log(formData);

  Axios.post('http://localhost:8000/upload.php',
    formData,
    {
      headers: formData.getHeaders(),
      // 'Content-Type':'multipart/form-data',
    })
    .then(d => console.log("DONE=>>>> ", d.data))
    .catch((f) => console.log('FAILED=>> ', f))
})();
packages.json

"axios": "^0.20.0",
"form-data": "^3.0.0",
"fs": "0.0.1-security",

First i started local server by php -S localhost:8000

After running local server i run index.js file using node index.js
I tested the code locally and it was working correctly.

Chandan
  • 11,465
  • 1
  • 6
  • 25
  • can you show the response you've received from the server? I tried your JS code too, everything is the same, but it is still not working I am receiving an empty array and files are not being sent to PHP, Here's my response: https://i.postimg.cc/3xKfXfQS/Screenshot-2020-10-25-at-8-41-41-PM.png – Kashan Haider Oct 25 '20 at 15:43
  • It is working for you but not for me I am not sure why, if you don't mind can you try if it works with images too? I think it is working for you due to different file types. and thanks alot for your time i have upvoted your comment for the help. – Kashan Haider Oct 25 '20 at 20:11
  • can you share detail of what version of php and node you are using – Chandan Oct 26 '20 at 10:50
  • PHP Version 7.2.34 , Node version 12.18.2 – Kashan Haider Oct 26 '20 at 10:52
0

You missed allFiles.length param in loop in NodeJS code. Correct code will be

for (var index = 0; index < allFiles.length; index++) {

The PHP code is correct, but if you send an empty files array, it will not be an error and will be returned success response!