-1

This is some part of my HTML code, I added [] because I have multiple row that requires more image to be uploaded for each row.

<td><input type="file" class="form-control total" name="myfile[]" readonly></td>

Problem is, when I ran the code to extract string from myfile using implode() and use it on end(). It return this error message

Warning: end() expects parameter 1 to be array, string given in ... on line 39

    $arr_supplier = $_POST['supplier'];
    
    $f_name = $_FILES['myfile']['name'];
    $f_tmp = $_FILES['myfile']['tmp_name']; 
    $f_size = $_FILES['myfile']['size'];
    $f_extension = implode('.',$f_name); 
    $f_extension = strtolower(end($f_extension)); // Line 39
    echo $f_newfile = uniqid().'.'.$f_extension;
    $store = "productimages/".$f_newfile;
    if($f_extension == 'jpg' || $f_extension == 'png' || $f_extension == 'gif' || $f_extension == 'jpeg'){
        if($f_size >= 1000000){
        echo 'file size too large';
                
        } else {
            if(move_uploaded_file($f_tmp, $store)){
                $product_details = $f_newfile;
            }
        }
    } else {
        echo 'file type invalid';
    }
...
Martin
  • 22,212
  • 11
  • 70
  • 132
mnamz
  • 3
  • 1
  • 3
  • 1
    On the previous line, you probably meant to use `explode()` rather than `implode()`. – Nigel Ren Oct 03 '20 at 11:15
  • when i use explode, it returns this `Warning: explode() expects parameter 2 to be string, array given` – mnamz Oct 03 '20 at 11:16
  • @MuhammadNurAliif when you are uploading multiple files, the data layout is a little different. You need to do some research (or `print_r()` your variables to observe) to see what's going on and why. – Martin Oct 03 '20 at 11:18
  • Read this : https://stackoverflow.com/questions/2704314/multiple-file-upload-in-php – Martin Oct 03 '20 at 11:19
  • you should use explode instead of implode, implode will join the array by glue and return to string – Jerson Oct 03 '20 at 12:01

3 Answers3

0

The error pretty much explains the problem, the end method expects an array as argument and you are passing a string that is returned from the call to implode.

Claudio
  • 5,078
  • 1
  • 22
  • 33
0

You need to upload each and every product image separately through loop. Your code should be something like:

  $product_Details = array();   
  for($i=0;$i<COUNT($_FILES['myfile']);$i++)
  {
     $f_name = $_FILES['myfile']['name'][$i];
     $f_tmp = $_FILES['myfile']['tmp_name'][$i]; 
     $f_size = $_FILES['myfile']['size'][$i];
     $f_extension = end((explode(".", $f_name)));
     echo $f_newfile = uniqid().'.'.$f_extension;
     $store = "productimages/".$f_newfile;
     if($f_extension == 'jpg' || $f_extension == 'png' || $f_extension == 'gif' || 
     $f_extension == 'jpeg')
     {
        if($f_size >= 1000000){
          echo 'file size too large';                
        } else {
          if(move_uploaded_file($f_tmp, $store)){
             $product_details[$i] = $f_newfile;
          }
        }
     } else {
       echo 'file type invalid';
     }
  }

Note: Do not forget to use multiple attribute while uploading multiple files at once. Also remove read-only attribute as it'll make input read-only hence meaningless.

Martin
  • 22,212
  • 11
  • 70
  • 132
  • counting `$_FILES['myfile']` will not give you the correct result – Martin Oct 03 '20 at 11:51
  • You should be using `===` rather than `==` comparison. It's not too vital for strings but it's a bad habit to get into. – Martin Oct 03 '20 at 12:13
0

Let's go through this step by step:

1:

I added [] because I have multiple row that requires more image to be uploaded for each row.

Ok, to upload multiple files in one call, you need to add the multiple keyword to your input element. Also making your element readonly seems somewhat at odds with uploading files.....

<td><input type="file" class="form-control total" name="myfile[]" multiple></td>

2:

The error you report states:

Warning: end() expects parameter 1 to be array, string given in ... on line 39

Which is pretty clear; you're passing it a string when it expects an array. This is obvious from the typo on line 38:

$f_extension = implode('.',$f_name); 

Your line here is taking an array of values ($f_name) and compacting them into a string

As you can see from the error, the end function expects an array, not a string.

The solution to this is to stop imploding. As commented by Nigel you almost certainly are looking for explode not implode.

explode breaks a string into an array of parts. implode does the exact opposite.

3:

You further reference in your comment:

when i use explode, it returns this Warning: explode() expects parameter 2 to be string, array given

This is the crux of your issue and is because you are defining a multiple file upload rather than a single file.

As outlined in more detail here, when uploading files via PHP there are two structure layouts, one for single files and one for multiple sets of files.

You are coding as if you're using single files, but the data being given to PHP from the upload process is actually for multiple files, here is an example of the difference:

Single file:

  $_FILES['myfile']['name'] = 'filename';
  $_FILES['myfile']['tmp_name'] = '/some/temp/server/addres';
  $_FILES['myfile']['size'] = 345;
  $_FILES['myfile']['error'] = 0;
  $_FILES['myfile']['type'] = 'file/mimetype';

multiple files:

Uploads marked as Multiple always have the same structure regardless of if they're uploading 1 or 10 files. The elements will always be numeric arrays rather than strings.

  // Each of these values are now numerical arrays, one for each file.
  $_FILES['myfile']['name'][0] = 'filename_1';
  $_FILES['myfile']['name'][1] = 'filename_2.css';
  $_FILES['myfile']['tmp_name'][0] = '/some/temp/server/address_1';
  $_FILES['myfile']['tmp_name'][1] = '/some/temp/server/address_2';
  $_FILES['myfile']['size'][0] = 345;
  $_FILES['myfile']['size'][1] = 678;
  $_FILES['myfile']['error'][0] = 0;
  $_FILES['myfile']['error'][1] = 0;
  $_FILES['myfile']['type'][0] = 'file/mimetype';
  $_FILES['myfile']['type'][1] = 'text/css';

So you should be able to see the difference, you are treating the $f_name as if it is a string when it is actually an array of all name values of all uploaded files.

  $f_name = [
            $_FILES['myfile']['name'][0],
            $_FILES['myfile']['name'][1],
            $_FILES['myfile']['name'][2]
            ];

Therefore, $f_extension returns an error when you explode it into an array because its subject is already an array.

Here is some further information about Multiple File Uploads, as well as the PHP Manual documentation.

4: How to fix this

I could show you how to fix this issue, but really, you should NEVER EVER TRUST USER DATA, so you must never trust the file extension set in the name key, or the mime type.

Instead you should read this Stack Overflow question and have your server independently check the mime type of the file that's been uploaded and then set an appropriate extenstion string.

Typically you should use FileInfo to check the expected file type and use a switch statement to then find the correct extension, such as (rough example):

$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type extension

// For a single file
$mimeType = finfo_file($finfo, $_FILES['myfile']['tmp_name']);

// OR

// For a multiple file in a loop ($i)
$mimeType = finfo_file($finfo, $_FILES['myfile']['tmp_name'][$i]);

// The above will return some form of mime type, check this format to set the extension:

$extension = "";
switch($mimeType){
   case "image/jpeg":
       $extension = ".jpeg";
       break;
   case "image/gif":
       $extension = ".gif";
       break;
   case "image/png":
       $extension = ".png";
       break;
   default:
       $error = "BAD! Invalid file MIME Type";
       // do something here. Feed error back to user.
}

finfo_close($finfo);

P.s Useful list of common mime types

Martin
  • 22,212
  • 11
  • 70
  • 132