I am having a tough time trying to upload files through PHP.
My form:
<form action="blah.php" enctype="multipart/form-data" method="post">
<p> Upload file: <input type="file" name="xmlfile"/>
<input type="submit" name="upload_submit" value="Upload" /> </p>
</form>
Checklist:
No 'smart' quotes in sight. Fine.
Proper enctype. Fine.
name attrib in input tag. Fine.
My /tmp directory has the following permissions: drwxrwxrwt. Fine.
post_max_size = 50M, upload_max_filesize = 50M, file_uploads = On. Fine.
print_r($_FILES) gives Array(). Useless. Tried on images, xml files, etc. Nothing works.
What I don't understand even further is that there are pages on which file uploading works on the same server. The only thing different from what I can gather is that the page I am working on has a few other forms which aren't of enctype="multipart/form-data". Should this matter?
PHP code as requested:
if($_SERVER['REQUEST_METHOD'] == 'POST'){
if(isset($_POST['upload_submit'])){
print_r($_FILES);
exit();
...
}
}
Gives an empty array regardless of print_r's position; I also tried it right after the if($_SERVER['REQUEST_METHOD'] == 'POST'){
Are you sure that you are submitting the right form or you are dealing with the submitted data in the right place/script? Provide some of the PHP code please.
your from, this php script (as blah.php)
edit for debugging, dump $_POST if is false
error_reporting(E_STRICT);
ini_set('display_errors', 'on');
if(array_key_exists('xmlfile', $_FILES)) {
echo 'file ' , $_FILES['xmlfile']['name'] , ' recieved';
echo '<pre>'
, print_r($_POST, true)
, print_r($_FILES, true)
, '</pre>';
} else {
echo '<pre>'
, print_r($_POST, true)
, '</pre>';
}
(possible) output:
file rapid-gui-development-with-qtruby_p1_4.mobi recieved
Array
(
[upload_submit] => Upload
)
Array
(
[xmlfile] => Array
(
[name] => rapid-gui-development-with-qtruby_p1_4.mobi
[type] => application/octet-stream
[tmp_name] => /private/tmp/phpEyV3vy
[error] => 0
[size] => 556846
)
)
You mention having other forms on the page... are those properly closed? For instance, if you have:
<form method="post">
blah blah blah
<input type="submit" />
<!-- oops forgot to </form> here -->
<form method="post" enctype="multipart/form-data">
...
<input type="submit" />
</form>
Then the FIRST <form> tag could be taking precendence and submitting without the enctype set.
If you're on Firefox, I'd suggest using Firebug/HTTPFox/LiveHTTPHeaders (all available in FF's add-ons library) to see what's being sent over the wire, and running your page through a validator to make sure there's no goofy HTML bugs causing this.
Related
As for an assignment I created a filter that modifies a Config that's connected to an API which prints out Order files. The web application has the option to save the modified Orderlist with a date and number added to it.
I've been asked to add a feature that allows my task giver to remove the order files he wishes to delete. I've asked a question before how I could remove a file through a file input, but this doesn't seem to be efficient considering it'll be eventually thrown in a private server. Now the best idea was to include the directory and print it out in a list, allowing the user to select the file they wish to remove.
With a lot of looking around I tried to find something that suited my resolve to this as best as I could and stumbled on this. It does print out an array and show checkboxes, but the file names(example Order file 26-1-2021 version 1.xml) are not displayed right next to the checkboxes. - My second question: How do I delete the order file you specifically checked through the submit button?
my code
<?php
$dir = '..\api-ivolved\s_orderlist';
$files1 = scandir($dir, 1);
foreach ($files1 as $filename => $n) {
echo "<input type=\"checkbox\" name=\"files[]\" value=".$filename."/>";
}
if (isset($_POST['delete'])){
unlink( /* Value here */ );
}
?>
<form class="deleteFile" method="get" enctype="multipart/form-data">
<input type="submit" id="delete" value="Delete file"/>
</form>
It appears you are checking $_POST for the delete flag rather than $_GET. Because your form submits using "get", this will cause it to never detect the delete checkbox. I've added a corresponding "delete" field/checkbox within your form to reference the field you are checking for.
For displaying the filenames besides the textbox, you will need to output this separately. I've added this after the checkbox itself, followed by a line break.
I've also "buffered" your input fields so that they get outputted inside of the form tags (rather than before).
Try something like this:
<?php
$dir = '..\api-ivolved\s_orderlist';
$files1 = scandir($dir, 1);
// We need to output the fields AFTER the opening form field. We "buffer" them for now and output them later.
$fields = "":
foreach ($files1 as $filename => $n) {
// Output the filename beside the textbox.
$fields .= "<input type=\"checkbox\" name=\"files[]\" value=".$filename."/>" . htmlspecialchars($filename) . "<br />";
}
if (isset($_GET['delete'])){
// Make sure files are checked/marked for deletion.
if (!empty($_GET['files'])) {
// Loop through each file and delete
foreach ($_GET['files'] as $file) {
unlink($file);
}
}
}
?>
<form class="deleteFile" method="get" enctype="multipart/form-data">
<?php echo $fields; ?>
<br />
<strong> Delete checked files? </strong> <input type="checkbox" name="delete" value="1"/><br />
<input type="submit" id="delete" value="Delete file"/>
</form>
It's worth noting to make sure that you have robust permissions checking in your application, since a simple link will cause a file to be deleted. This can technically cause a CSRF vulnerability (a special type of vulnerability that would allow someone to create a image/link on another website with a full link to do unwanted business). To prevent this, look into adding CSRF tokens to check links in your script (various robust guides exist online for this sort of thing) :)
The question posed is a little different to the original so I hope the following helps you resolve your confusion.
<?php
$dir=__DIR__ . '/api/s_orderlist';
if( $_SERVER['REQUEST_METHOD']=='POST' && !empty( $_POST[ 'files' ] ) ){
ob_clean();
#process supplied files array - delete each file found. Fail silently
$files=$_POST['files'];
foreach( $files as $file ){
$filepath=sprintf('%s/%s',$dir,$file);
if( file_exists( $filepath ) )#unlink( $filepath );
}
#redirect back to the same page using GET to avoid POSTing again if page is reloaded.
exit( header( sprintf('Location: %s', $_SERVER['SCRIPT_NAME'] ) ) );
}
?>
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<title></title>
</head>
<body>
<form method='post'>
<?php
# find the files in target directory
$col=glob( $dir . '/*.*' );
#iterate through files, create checkbox for each file
foreach( $col as $file ){
printf(
'<label style="width:100%%;display:block;padding:0.5rem">
<input type="checkbox" name="files[]" value="%1$s" />%1$s
</label>',
basename( $file )
);
}
?>
<input type='submit' />
</form>
</body>
</html>
I have an html form, including an input file element. The form is processed by a php script. Most of the time, everything works fine — I can access the form data through $_POST and $_FILES, I can check the data submitted and I can manipulate the file. The action on the form is set to return to the same page as that on which the form appears.
However, I am unable to process anything when the user tries to upload a file which is too large. This is what happens:
Nothing gets uploaded and the page reloads.
$_FILES['uploadFile']['error'] is null, so I can't catch the error.
isset($_POST['submit']) is false, so I can't process the input.
There is no error message.
My form looks like this:
<form action="hwsa.html?form[id_assignment]=<?php echo($id_assignment); ?>" method="post" enctype="multipart/form-data" class="assignment-submission">
<p>Select file to upload. N.B. Only pdf files allowed; maximum size 5 MB.</p>
<input type="hidden" name="MAX_FILE_SIZE" value="5120000" />
<input type="file" name="uploadFile" id="assignment-file">
</p>
<p>
<input type="submit" name="submit" value="Submit" class="btn-reverse">
<input type="submit" name="submit" value="Cancel" class="btn-reverse">
</p>
</form>
I can process other errors, like using the wrong file type, in a block like this:
If (isset($_POST['submit']))
{
If ($_POST['submit']=='Cancel')
{
//Process cancel
}
If ($_POST['submit']=='Submit')
{
$size=$_FILES['uploadFile']['size'];
$sizeWarning = ($_FILES['uploadFile']['size'] > 5120000);
$fileType = strtolower(pathinfo($_FILES['uploadFile']['name'], PATHINFO_EXTENSION));
$typeWarning = ($fileType != 'pdf');
$emptyWarning = ($_FILES['upLoadFile']['size'] == 0);
// Process errors or process successful upload.
}
}
Any help would be greatly appreciated!
Thank you in advance.
When a file upload is so large that it gets discarded you get an empty post request but original request headers are kept so you can do the following checks:
Determine if it's a post request and skip checks if isn't:
$is_post = strtolower(filter_input(INPUT_SERVER, 'REQUEST_METHOD')) === 'post';
Determine if user agent (browser or script) sent a Content-Length header, maybe with a fallback check when $post_size is null (which will throw false positives if all form fields are optional):
$post_size = $_SERVER['CONTENT_LENGTH'] ?? null;
if (($post_size === null || $post_size > 0) && !$_POST && !$_FILES) {
// Error: post body was too large
}
You can test this code by setting an arbitrarily small size limit, e.g.:
post_max_size = 1K
Try thoroughly (I've used these ideas but I haven't tested this exact code).
I've got an HTML form that has a PHP pgm to write the results to a file. I've basically copied it from The Web. It's not rocket surgery. It's running with PHP 7 on a Raspberry Pi with the most recent Raspbian. The PHP pgm reports that the file is writeable, that it succeeded, and so on, but the file remains empty. I've changed the permissions to 777 (for testing) and that doesn't help. I'm stumped. Here is the HTML:
<!DOCTYPE html>
<html>
<head>
<title>Update</title>
</head>
<body>
<FORM NAME ="form1" METHOD ="POST" action="filewrite.php">
<INPUT TYPE = "TEXT" VALUE ="memory" NAME="memory">
<INPUT TYPE = "TEXT" VALUE ="desc" NAME="desc">
<INPUT TYPE = "TEXT" VALUE ="comm" NAME="comm">
<INPUT TYPE = "TEXT" VALUE ="reset" NAME="reset">
<INPUT TYPE = "Submit" Name = "Submit1" VALUE = "Create">
</FORM>
</body>
</html>
Here's the PHP (in filewrite.php):
<?php
ini_set('display_errors', true);
if(isset($_POST['memory']) && isset($_POST['desc']) && isset($_POST['comm']) && isset($_POST['reset']))
{
# $data = $_POST['memory'] . '\t' . $_POST['desc'] . '\t' . $_POST['comm'] . '\t' . $_POST['reset'] . "\n";
$data = "testing";
$file = "/tmp/data.txt";
var_dump($_POST);
if (is_writable($file)) {
echo nl2br("\n\nThe file is writable\n\n");
} else {
echo nl2br("The file is not writable\n\n");
}
touch($file);
$ret = file_put_contents($file, $data, LOCK_EX);
if($ret === false)
{
die('There was an error writing this file');
}
else
{
echo nl2br("$ret bytes written to file\n");
echo nl2br("data = $data\n");
echo nl2br("file = $file\n");
}
}
else
{
die('no post data to process');
}
?>
Here's what I get as output:
array(5) { ["memory"]=> string(4) "fred" ["desc"]=> string(6) "barney" ["comm"]=> string(5) "wilma" ["reset"]=> string(5) "betty" ["Submit1"]=> string(6) "Create" }
The file is writable
7 bytes written to file
data = testing
file = /tmp/data.txt
and here's the file:
-rwxrwxrwx 1 pi pi 0 Mar 29 16:43 /tmp/data.txt
I tried it without the file existing and with it there. At first I was trying to write the form data to the file but then switched to just trying to write "testing". I've tried other directories for the file, but they (as expected) failed due to permissions.
Edit:
When I tried writing the file to /home/pi (which I expected to fail as the webserver is www-data), I got this error in /var/log/apache2/error.log:
[Sun Mar 29 17:04:24.648150 2020] [php7:warn] [pid 12075] [client fe80::cceb:ba3c:da1d:6b2a:53052] PHP Warning: file_put_contents(/home/pi/data.txt): failed to open stream: Permission denied in /var/www/html/filewrite.php on line 19, referer: http://devberry-pi.local/rwupdate.html
Setting it back to /tmp/data.txt cleared that error (and no other errors are generated.)
Edit 2:
I copied a 6k file to /tmp to make sure there is enough space and that worked fine. I'm only writing 7 bytes at the moment ("testing") and really only want to write < 80b once I get it working. Also, this is a new installation and only has a few small pgms (that I've written) on it.
Edit 3:
Brand new card, brand new install, same results. 8^( I think my next step is a different Raspberry Pi, though I'm not sure how the hardware could be the issue. Note: I can create files in /tmp from the command line.
Ooh, new development -- I created a new folder, /home/www, set its permissions to 777, and it does successfully create the file there. The permissions for /tmp are drwxrwxrwt and it's owned by root/root. The webserver/php user is www-data. I can use that as a work-around, but it's not ideal in my book. Is there a better place than /tmp to put stuff that different users/pgms need to have access to?
Any thoughts? What should I be looking at?
You may use the PHP function file_put_contents which takes a filename and data you wish to write and writes it to a file. In your case, this could be some form of the HTML POST data sent. In the solution below I have encoded the values in JSON as it is a good representation of key/value pairs associated with forms like this. This could be done in any other form that suits your needs.
I have chosen to write the file to the same folder as the PHP file containing the form. This is not realistic in a production environment however, it shows that the PHP works saving the file.
If the location of the file is the problem then permissions is where you should be looking as that should be the only thing causing it to not write when using the below method. I have entered values in the form fields for easier testing but the placeholders should stay in a production environment and the values removed.
In any environment there should be both client and server-side validation taking place. I have removed the validation for simplicity and that it is off-topic but each value should be tested and filtered prior to anything else being done with it. Anyway, here is the working example combined into one file:
<?php
/**
* Check for submission of form.
*/
$nl="<br>";
if (isset($_POST['memory']) && isset($_POST['desc']) && isset($_POST['comm']) && isset($_POST['reset'])) {
try {
$data = json_encode($_POST, JSON_PRETTY_PRINT);
$file = "data.txt";
if ( file_put_contents ($file, $data) ) {
$msg = "File successfully saved.";
} else {
$msg = "Error saving file";
}
} catch (Exception $e) {
$msg = "Error saving file:" .$nl.$nl . $e->getMessage() . $nl.$nl . $e-getTrace();
}
}
?>
<!doctype html>
<html lang="en_US">
<head>
<meta charset='utf-8'>
<title>Example: Save File</title>
</head>
<body>
<?php if (isset($msg)){ echo '< style="color:#100">'.$msg.'</p>'; } ?>
<form name="form1" method="post" enctype="multipart/form-data">
<input type="text" placeholder="memory" name="memory" value="mem">
<input type="text" placeholder="desc" name="desc" value="something">
<input type="text" placeholder="comm" name="comm" value="more data">
<input type="text" placeholder="reset" name="reset" value="reset">
<input type="Submit" Name = "Submit1" value="Create">
</form>
</body>
</html>
Furthermore, submitting a form you should have the enctype attribute set on the form tag. If you are uploading a file <input type="file"> then it must be set to multipart/form-data. This allows for the binary sending of data via the HTTP Post.
<form enctype="multipart/form-data" action="..." id="....">
Additionally, as MDN points out in its documentation, you may add an attribute to the <input> or button elements.:
"... or n the formenctype attribute of the <input> or <button> elements."
In all cases you should be specifying the enctype of the form including during asynchronous requests using XMLHttpRequest.
I have a problem that i just quite do not understand at all. I have this uploading script that always return Notice: Undefined index: uploadPDF in xxxxx
I've made sure that the form has the enctype="multipart/form-data" <form action="" method="POST" enctype="multipart/form-data">
The field also has the same name that i ask for in the code <input name="uploadPDF" size="100" type="file" title=""/>
When i try to echo $_POST['uploadPDF'] i actually get the filename in question. But when i try to var_dump the following $_FILES['uploadPDF']['name'] i get the undefined index error.
I really cant see what the problems is. I'm running on a inhouse IIS server.
Debug information:
This is the "debug" i try to do:
echo $_POST['uploadPDF']."<br />";
$filename = $_FILES['uploadPDF']['name'];
var_dump($filename);
echo "<br />";
var_dump($_FILES);
This is the output i get:
TEST PDF PORTAL V3.pdf
Notice: Undefined index: uploadPDF in C:\inetpub\myfolder\V4\admin\addRoutine.php on line 29
NULL
array(0) { }
When you upload file, you should use
$_FILES['file_name'] not $_POST['file_name'] that is because, the file information is stored in the $_FILES arrays, since you have named your input type to 'file'
So, I would suggest
Changing
echo $_POST['uploadPDF'];
to
echo $_FILES['uploadPDF'];
Your form as you wrote it has no action specified.
( <form action="" method="POST" enctype="multipart/form-data"> )
You need the asign "path_to_yourform.php" as your form action.
You better write it like this:
echo $_POST['uploadPDF']."<br />";
$filename = $_FILES['uploadPDF']['name'];
echo var_dump($filename)."<br />";
Well, this is quite embarrassing, one of the other guys working on this had left a <form action="" method="post"> in one of the included files in the project. Since this form tag was before my form tag $_FILES did not catch the index because of the missing enctype in the first form tag!
I have a html form that allows image uploads, but the image uploaded now fails the "is_uploaded_file" check for some reason.
So why does the upload fail the is_uploaded_file check?
HTML:
<form enctype="multipart/form-data" id="RecipeAddForm" method="post"
action="/recipes/add" accept-charset="utf-8">
<!--- Omitted Markup -->
<input type="file" name="data[Recipe][image]" value="" id="RecipeImage" />
<!--- Omitted Markup -->
</form>
PHP:
// returns false
echo is_uploaded_file($file['tmp_name'])?'true':'false';
I did a dump on the $file or $_FILES array:
Array
(
[name] => add or remove.jpg
[type] => image/jpeg
[tmp_name] => E:\\xampp\\tmp\\phpB9CB.tmp
[error] => 0
[size] => 71869
)
File size is not too large, and the error was 0. So why does it fail the is_uploaded_file check?
Might be a problem with windows, since it's case sensitive and will not match if the path is different. Try using realpath($file['tmp_name'])
try with
if (is_uploaded_file($_FILES['data[Recipe][image]']['tmp_name']))
remember $_FILES is reserve PHP superglobal variable ..so always write in capital
u can retrieve the correct path of file using
$filename = basename($_FILES['userfile']['name']);
NOTE: why u using array in the name attribute ( name="data[Recipe][image]" ) ?
if there is no specific reason then alwayz make simple code
<input type="file" name="RecipeImage" value="" id="RecipeImage" />
and check simply
if (is_uploaded_file($_FILES['RecipeImage']['tmp_name']))
Remember KISS
After you have used the uploaded image (move_uploaded_file) the function is_uploaded_file always returns false.