php - end() expects parameter 1 to be array, string given when working with $_FILES

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 frommyfile
usingimplode()
and use
it onend()
. 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';
}
...
Answer
Solution:
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.
Answer
Solution:
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 themultiple
keyword to your input element. Also making your elementreadonly
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, theend
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 not .
breaks a string into an array of parts.
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 asMultiple
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 youexplode
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 thename
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 aswitch
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);
Share solution ↓
Additional Information:
Link To Answer People are also looking for solutions of the problem: err_ossl_pem_no_start_line
Didn't find the answer?
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Similar questions
Find the answer in similar questions on our website.
Write quick answer
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.