PHP image upload and write to database - php

I'm quite new to PHP and trying to upload an image to the server and then write it to the database using a form and php using the code and form below but it doesnt seem to be working for, if I take all of the photo content out the form works perfectly well with the other variables and content such as writing the out the article title and content, would anyone be able to tell me where I'm going wrong at all? thanks in advance guys.
<?php
session_start();
include_once('../php/connection.php');
if (isset($_SESSION['logged_in'])) {
if (isset($_POST['title'], $_POST['content'], $_FILES['photo1'])) {
$title = $_POST['title'];
$content = nl2br($_POST ['content']);
$photo1=($_FILES['photo1']);
$target = "../lifestlye";
$target = $target . basename( $_FILES['photo1']);
$query =$pdo->prepare('INSERT INTO article (article_title, article_content, photo_1) VALUES (?,?,?)');
$query->bindValue(1, $title);
$query->bindValue(2, $content);
$query->bindValue(3, $photo1);
$query->execute();
move_uploaded_file($_FILES['photo1'], $target);
{
}
header('Location: index.php');
}
?>
<form action="add.php" method="post" autocomplete="off"/>
<dl class="field four columns centered">
<dd><label for="title">Article Title</label></dd>
<dt class="text"><input type="text" name="title" id="title"/>
</dt>
</dl>
<dl class="field nine columns centered">
<dd><label for="content">Content</label></dd>
<dt class="textarea">
<textarea name="content" id="message"></textarea></dt>
</dl>
<p class="blacktext">Photo</p>
<input type="file" name="photo1">
<input type="submit" id="add article"/>
</form>

Try this code:
<?php
session_start();
include_once('../php/connection.php');
if (isset($_SESSION['logged_in'])) {
if (isset($_POST['title'], $_POST['content'], $_FILES['photo1'])) {
$title = $_POST['title'];
$content = nl2br($_POST['content']);
$name = $_FILES['photo1']['name'];
$tmp_name = $_FILES['photo1']['tmp_name'];
$target = '../lifestlye/'.$name;
if (move_uploaded_file($tmp_name,$target)) {
$stmt = $pdo->prepare('INSERT INTO article (article_title, article_content, photo_1) VALUES (?,?,?)');
$stmt->execute(array($title,$content,$name));
header('Location: index.php');
exit();
}
}
}

You are making it way too simple. You need to read the manual page: http://www.php.net/manual/en/features.file-upload.post-method.php
First, add this to your form as parameter: enctype="multipart/form-data"
Then, understand that $_FILES['photo1'] will be an array, and $_FILES['photo1']['tmp_name'] will contain a temporary filename, which is the uploaded file. You can then move the file to a new location, or read it and put it into the database as a BLOB (but why do you want to keep binary data in a database?)

You should use absolute paths for moving the file. If you want to do something in the current dir, use __DIR__ or dirname(__FILE__) depending on your php version. The first one is to preferred if it's available.
You should do error checking - read up on $_FILES array on php.net manual for what to look out for.
Check the return value of move_uploaded_file, errors, notices - there might also be a problem with writing permissions (the target directory/file has to be writable by the webserver)
You should consider generating a filename, otherwise if 2 ppl upload a file with the same name, the second one will override the first one. Then starts the fun about race conditions and the impossibility of php itself to do an atomic lock (using mysql get lock is the best I've come up so far, as semaphores and file locking suck in a web context with php)
You should add some security checking, e.g. str_replace("\0", "", $filename) for avoding nul poisoning (and depending on your system and filesystem there are probably other things you should filter/check)
This is just a tip, but really: Don't do anything with user input, especially file upload, in the open (e.g. publicly available web address) if you haven't got enough experience in regards to php/security. Otherwise you will see your server crashed, taken over, ... in a very short time. PHP is already very insecure as it is, adding in mysql and file upload doesn't really make it better. There is no guarantuee that the filename you get from $_FILES is safe - an attacker could send ANY filename (i can easily do with a few lines of script myself, and I'm not a real hacker).
Also, basename does not filter filenames, it just gives you whatever is before the last '.'.
Edit: + everything Palantir wrote, to make it work (sorry, there were so many things on this that I skipped some)

Related

Getting the system date created of a file using PHP

EDIT
I have this PHP code now:
$name = isset($_POST['image_file']) ? $_POST['image_file'] : '';
$date_added = date ("F d Y H:i:s.", filectime(basename($_FILES["image_file"]["tmp_name"])));
$path = "../uploads/".basename($_FILES["image_file"]["name"]);
$patient_id = $_POST['patient_id'];
$remark = $_POST['remark'];
//$date_added = $_POST['date_added'];
$ext = pathinfo($path, PATHINFO_EXTENSION);
...
And the result of any file (except images) is: January 01 1970 01:00:00.
And when I try to upload an image it send me to an empty page where no errors are shown and the image isn't uploaded into folder.
END EDIT
I need to add scanned images into patient file using this form:
<form enctype="multipart/form-data" id="myForm" name="myForm" action="add_scan.php" method="post">
<div class="box-body" id="toggleDiv">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label style="float:left">File Description</label>
<input type="text" class="form-control" id="remark" name="remark"/>
<label style="float:left">Upload File</label>
<input type="file" class="form-control" id="image_file" name="image_file"/>
<input type="hidden" class="form-control" id="patient_id" name="patient_id" value="<?php echo $patient_id ?>"/>
</div><!-- /.form-group -->
<button type="submit" class="btn btn-warning" id="add_scan" name="add_scan">Add File</button>
</form>
Usually, my client add a date but sometimes he forgot in what date the image is taken. So I need to access the system date of the image.
I tried the following:
Add_scan.php page:
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
require_once('../include/global.php');
//session_start();
$user = $_SESSION['username'];
$id_logged = $_SESSION['login_id'];
if(isset($_POST['add_scan']))
{
try
{
$name = isset($_POST['image_file']) ? $_POST['image_file'] : '';
$path = "../uploads/".basename($_FILES["image_file"]["name"]);
$date_added = date ("Y-m-d", filectime(basename($_FILES["image_file"]["name"])));
$patient_id = $_POST['patient_id'];
$remark = $_POST['remark'];
//$date_added = $_POST['date_added'];
$ext = pathinfo($path, PATHINFO_EXTENSION);
move_uploaded_file($_FILES["image_file"]["tmp_name"], $path.$name);
$sqlUpd = "INSERT INTO scan_image(id_logged, patient_id, image_file, remark, date_added)
VALUES(:id_logged, :patient_id, :image_file, :remark, :date_added)";
$stmt = $conn->prepare($sqlUpd);
$stmt->bindValue(':id_logged', $id_logged);
$stmt->bindValue(':patient_id', $patient_id);
$stmt->bindValue(':image_file', $path);
$stmt->bindValue(':remark', $remark);
$stmt->bindValue(':date_added', $date_added);
$stmt->execute();
header("Location: patients.php?patient=".$patient_id);
}
catch(PDOException $e)
{
echo $e->getMessage();
}
?>
Where I used this line: $date_added = date ("Y-m-d", basename($_FILES["image_file"]["name"])); to access the date according to PHP PDO documentations in this link.
But nothing added and I only see a blank page of my add_scan.php code and it is not redirected to patient.php page.
SOLUTION:
Because you're uploading a file the date on the system is going to be the upload date. Your solution if it is an image file is to read the image file meta-data, which is a bit of a pain because there are multiple types of meta data for each type of image file and finding the one you want is not in itself efficient.
I think Imagick PHP plugin does this but I can't vouch for the quality or worth of this/these functions.
To clarify further:
When you upload a file from a computer to a server, the server will hold NO filesystem information about the file on the computer.
Meta Data is data about something, and typically data about a file (such as its created date) is not stored within the file itself as a standard, but in the operatng system that stores the file contents.
The server which recieves your uploaded file can not tell you when the file was saved on to the computer it came from, or anything else filesystem related because the server has only been given the file contents data, not the file systems metadata about storage and modification (etc).
If this information is available from within a file, it is stored in what is called "MetaData" inside the file itself, and to reach these bits of metadata you need to use something like Imagick for images .
Alternatively, if you simply want the date the file was added to this system you can read that in this Stack Answer.
NOTES:
You want filectime.
After you header add an exit to cease execution.
You have a $_POST and a $_FILES value with the same name, you are using $_POST['upload_file'] and $_FILES['upload_file'] I'm not sure if this will break your script but the POST values of this will be empty unless you have another field in your form with the same name which is clearly bad practise.
Your require and/or include do not need to be in brackets.
It is also bad practise for pathinfo to be given a relative path, you should as much as possible give PHP functions absolute paths, using $_SERVER['DOCUMENT_ROOT'] or other magical constants.
Remove basename in filectime, it's unneed.
it looks like $path.$name should infact be $path.$name.$ext when using move_uploaded_file
Your problem (from your comment) is that you are looking for the time of a string that is not the file. Replace $_FILES["image_file"]["name"] in you filectime call to instead be ['tmp_name'] because this is the location address of where the uploaded file is (temporarily) stored.
The name array value in $_FILES simply tells you the name of the file from the place it was uploaded from.
BUT This time will simply only tell you the uploaded time.
Your Error log should have shown you that your filectime is tying to get the data from a non-file entity.
filemtime reports the files modification time, not its creation time (this is not available on most operating systems).
That's not the PDO documentation.
The file uploaded is a copy of the data held in the original file - so the mtime you see on the copy will always be about 'now'.
The user can see the modification time on their local machine. If they can't provide this information then the only option would be to take a backup of the files, restore it on your server (using an appropriate method which does not change the mtime, e.g. untar as root) then load the files directly from there rather than uploading over the web.

How to get the path of a selected file in input type="file" using php?

I want to get the path of a selected file and store it in the database for future use.
I have the following code but it does not work.
$path = $_FILES['txtImage']['tmp_name'];
$sql = "INSERT INTO tblquestions (q_category, q_question, q_image, q_correct, q_answer2, q_answer3, q_answer4) VALUES ('$_POST[txtCategory]','$_POST[txtQuestion]','$path','$_POST[txtCorrect]','$_POST[txtChoice2]','$_POST[txtChoice3]','$_POST[txtChoice4]')";
txtImage is the name of my input type="file" and $path is the code i am using but it does not work. IT just returns blank.
Anyone who can help me or lead me to a different, hopefully easier method? Thank you in advance. :)
PHP will store submitted files in a temporary directory, which you shouldn't be storing in the database as it'll be volatile.
Use PHP's move_uploaded_file function to move the file to where you'd like in your file system, and then store that path in your database.
Docs: http://php.net/manual/en/function.move-uploaded-file.php
$tmp_path = $_FILES['txtImage']['tmp_name'];
$dest_path = path_where_in_your_server_you_want_this_image_to_be_moved.$_FILES['textImage']['name']; (eg: 'images/'.$_FILES['name'])
if(move_uploaded_file($tmp_path,$dest_path)){ //this will move the file from tmp location in server to the destination you provide in the second parameter
$sql = "INSERT INTO tblquestions (q_category, q_question, q_image, q_correct, q_answer2, q_answer3, q_answer4) VALUES ('$_POST[txtCategory]','$_POST[txtQuestion]','$dest_path','$_POST[txtCorrect]','$_POST[txtChoice2]','$_POST[txtChoice3]','$_POST[txtChoice4]')";
}else{
echo "Image could not be uploaded"
}
Also keep in mind that there can be permission issues (with the directory that you want the image to be uploaded to) while uploading the file.
Good Luck!
Have you set your form enctype correctly on the HTML side so that it is correctly able to work as it should.
Secondly, TMP is just a temporary location, you MUST move that file to a server readble directory using PHP function move_uploaded_file
Read about enctypes, in this answer or on w3 schools.
<form name="YourForm" method="post" enctype="multipart/form-data" action="">

How to add domain in front of file_get_contents in PHP code

I'm new here and had a PHP Coder to some mods to 2 files of mine which were suppose to be able to let the user be able to link directly to the file converted from DOC to IMG on http://NFOPic.com
Here is the Code Edited (you can see edited parts with 'DrTech76') -:
get_image.php
<?php
require_once 'include/db.php';
$file_name = $_GET['f'];
if ( empty( $file_name ) || !file_exists( 'uploads/' . $file_name ))
{
die( 'File not found...' );
}
$sql = "SELECT original_file_name FROM nfo_images WHERE file_name = '" . $file_name . "'";
$rs = mysql_query( $sql );
$file = mysql_fetch_assoc( $rs );
$original_file_name = explode( '.', $file['original_file_name'] );
//just get rid of the last, then put back together
array_pop( $original_file_name );
$original_file_name = implode( '.', $original_file_name );
header("Content-Type: image/png");
//start edit 10.07.2014 DrTech76, flow the direct image link through here to keep the actuall location unknown
if(!isset($_REQUEST["dl"]))
{//it's not a request through a direct link, so process as file download, as it was originally
header("Content-Disposition: attachment; filename=\"" . $original_file_name . ".png\"");
}
//end edit 10.07.2014 DrTech76, flow the direct image link through here to keep the actuall location unknown
echo file_get_contents( 'uploads/' . $file_name );
?>
The other File Edited is the index.php (added input area, should have been text area IMO with a 'select to copy' to copy contents to clipboard) (THIS IS ONLY THE AREA EDITED I'VE ADDED, or else will be too long)
<div id="uploaded_image_div" align="center">
<b>Left Click on the Below Image to Save it to your PC...</b><br /><br />
<div id="title" style="font-weight:bold;"></div>
<br />
<img border="0" src="" />
<br />
<?php
//start edit 10.07.2014 DrTech76, direct link containers, styling is done through css/style.css
?>
<div id="direct_link">
<label for="link">Direct link to this image</label><br />
<input id="link" readonly onfocus="$(this).select()" />
</div>
<?php
//end edit 10.07.2014 DrTech76, direct link containers, styling is done through css/style.css
?>
<br />
<br />
Can someone please help me fix this error, as you can see from the NFOPic.com index page the actual domain name is not showing up - though I need it so if I upload this to another domain (a new domain picked out when BETA is released) it will work with any domain, instead of just putting http://nfopic.com/ in front of the code - THANKS IN ADVANCE GUYS!
So, there are quite some things to do with this script.
1) Get rid of the XSS and the SQL injection vulnerability:
Right now, you are checking if the file exists, which isn't completely wrong, but doesn't do the job for you:
$file_name = $_GET['f'];
if ( empty( $file_name ) || !file_exists( 'uploads/' . $file_name ))
{
die( 'File not found...' );
}
Since Peter already told you, that you are allowing people to download your SQL Server access data by inserting http://nfopic.com/get_image.php?f=../include/db.php into the browser, I'll just assume you understood the basic problem.
file_exists just checks if the file is available on the server, which is true for your include/db.php file. So the Interpreter jumps over the IF and continues with the execution. Since you are already using the DB, we are going to use it, to determine if the file really exists. We'll get to that in a sec.
mysql_query isn't safe at all (SQL injection)! You'll have to use PDO or MySQLi for SQL queries (I'm using PDO for demonstation):
$prep = $db->prepare("SELECT original_file_name FROM nfo_images WHERE file_name = ?");
$prep->execute(array($file_name));
$res = $prep->fetchAll();
if(count($res) == 0){
die( 'File not found...' );
}
$original_file_name = explode('.', $res[0]["original_file_name"]);
// ... and what else you want to do with the file name
You can read more about it here: http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers
Now we should have closed both vulnerabilities by using this way (Assuming the upload doesn't allow wrong interacting with the DB -> you need to check the generate_image.php).
2) Your problem with adding the Domain:
I didn't quite get what your problem was with that, so feel free to comment and ask further questions, if I am not answering the right way.
- You can get the current domain, by calling $_SERVER['SERVER_NAME']. This should output something like: nfopic.com (I don't know where you would want to add that though).
- If you meant that the domain name in the input field is wrong, you can change that in your js/nfo.js file. There is the line:
$('#uploaded_image_div #link').val('http://nfopic.com/get_image.php?f=' + validate[1]);
The http://nfopic.com/get_image.php?f= part is hardcoded, so you would have to insert it any other way.
- If you meant to add the domain name to the imagename, which the user can download, You would have to redirect your image with a .htaccess file, so you can request the real image name image_234234.png.
3) The rest of the homepage:
Since there are so many vulnerabilities and mistakes in this part of the website, there have to be some in generate_image.php. The check for the filetypes (txt, nfo and diz) are done in JS. The problem with that is, that you can work around them and upload any other filetype, if there isn't some check in PHP too. This leads us to another vulnerability -> a SHELL script could be uploaded (simple PHP file) and your files could be modified from an attacker.
FINALLY:
The whole homepage might be insecure. There are definitely some modifications that need to be done.
And again, if I didn't answer your starting question, feel free to ask further questions.

IF statement not working in self-referencing form

I'm trying to use an if statement in PHP to create a directory to upload files into. I'm using a form that references itself, so that I can create another folder and upload another set of files to a different folder with a different name, or another set of files to the same folder if I so choose, once the first has completed. The problem is that the if statement I'm using doesn't seem to work. When I submit the form, it created the folder a second time whether the folder already exists or not.
What is going on with my if statement?
<?php
$dirname = $_REQUEST['dirname'];
$taken = $_REQUEST['taken'];
$location = $_REQUEST['location'];
$subject = $_REQUEST['subject'];
$urldirectory = $_REQUEST['urldirectory'];
function makeDirectory($dirname) {
mkdir(trim($dirname, 0777));
mkdir(trim($dirname.'/thumbs', 0777));
}
if (file_exists($dirname)) {
echo "the directory exists and it is called: " . trim($dirname);
} else {
makeDirectory($dirname);
}
//........... code omitted from here for brevity............
?>
<form enctype="multipart/form-data" method="post" action="upload2.php">
<input type="submit" name="submit" value="Upload" />
There are some problems in the way how you handle directory creation and checking:
You check if $dirname exists and if it doesn't you create trim($dirname, 0777).
trim expects a string as second parameter, but you pass an integer (i.e. 0777). My guess is, you want to pass 0777 to mkdir, not to trim.
I don't know about the second point, but the first point definitely can lead to file_exists($dirname) failing on two consecutive form submissions with the same form values. I suggest to sanitize request values as early as possible, i.e. to use
$dirname = trim($_REQUEST['dirname']);
and use $dirname from there on without the need for any further trimming

uploading img to server using move_uploaded_file() help

So im here trying to learn more php and... trying to add an image that a user would upload(an avatar) to the server via move_uploaded_file...oh and im on WAMP right now fyi.
the book im reading ...long story short, the example shown doesnt work. Ive Googled around and literally copy pasted a few relavant examples ive found and still....well to be clear, be it that i wrote it or from the net, i can upload the image name (along with other values) to tables on the db i have set up but the image itself doesn't move to the directory I've set up for it.
I've stripped all my apps code to a simple table and simple php to make sure nothing was conflicting etc, and still nada.
here is my html:
<form method="post" action="testUpload.php" enctype="multipart/form-data">
<input type="hidden" name="MAX_FILE_SIZE" value="32768" >
<table summary="guitarwars lesson" width="500">
<tr>
<td>load picture:</td>
<td><input type="file" name="screenshot" id="screenshot" ></td>
</tr>
<tr>
<td><input type="submit" name="submit" action="submit"></td>
</tr>
</table>
</form>
here is my php:
<?php
$screenshot = $_FILES['screenshot']['name'];
//$destination = "images/user_avatars/$screenshot";
$insertValues = "INSERT INTO testdb(screenshot) VALUES ('$screenshot')";
//---declare connection.
$connect2db = mysqli_connect('127.0.0.1','root','pass','dbname');
if(!$connect2db){
die("Sorry but theres a connection to database error" . mysqli_error);
} else {
//pg intro mssg
echo ' <span style="font-size:25px; color:green;"> --- Link Established with Database ---.<span/><br/><br/>';
}
// put into db.
if(!empty($screenshot)) {
$insertData = mysqli_query($connect2db, $insertValues);
echo 'data submitted. thank you';
move_uploaded_file ($_FILES['screenshot']['tmp_name'],"images/user_avatars/{$screenshot}");
echo 'IMAGE UPLOAD COMPLETE';
}
mysqli_close($connect2db);
?>
now i dont get an error...i actually get the echo "image upload complete" part...
and like i said, with the app code, i get multiple values AND the image name going through and being saved onto the db, but the image itself being moved from temp to my location is a no go.
any tips links, etc i gladly appreciate.
Thank you in advance.
If that's code from your book, then throw the book out and burn it as fast as you can.
a) You're wide open to SQL injection attacks. Any decent PHP tutorial that shows how to deal with databases should START with sql injection attack mitigation strategies.
b) Your connection-failed error uses mysqli_error, which is an undefined constant. You probably want mysqli_error(), which is a function call
c) The code assumes the upload completed successfully. Uploads can/will fail at the drop of a hat, so NOT checking for errors is the fast road to hair-pulling. At minimum the script should have something like
if ($_FILES['screenshot']['error'] !== UPLOAD_ERR_OK) {
die("Upload failed with error code " . $_FILES['screenshot']['error']);
}
Those error codes are defined here.
d) Your code is using the user-supplied filename to store the file onto the sever. Nothing says that a malicious user can't hack the filename to include path information, so your code is actually allowing that nasty user to scribble on ANY file on your server which the webserver process has write access to. This is BAD
e) Your code also assumes the file move succeeded, without checking for errors. It should have at mininum
$status = move_uploaded_file(...);
if (!$status) {
die("Move failed!");
}
or something similar.
f) Your code assumes that all the database queries succeeded. Even if your query string is 100% perfectly formed (yours aren't, see (a) above), queries can fail for any number of other reasons. At bare mininum you should have:
$result = mysql_query(...) or die(mysqli_error());
As a start you could add
if(!move_uploaded_file(...))
die('error');
if you replace
move_uploaded_file ($_FILES['screenshot']['tmp_name'],"images/user_avatars/{$screenshot}");
echo 'IMAGE UPLOAD COMPLETE';
with
if (move_uploaded_file ($_FILES['screenshot']['tmp_name'],"images/user_avatars/{$screenshot}")) {
echo 'IMAGE UPLOAD COMPLETE';
}
you would then get the echo if it was successful
Try to supply the absolute path:
move_uploaded_file ($_FILES['screenshot']['tmp_name'],"/path/to/images/user_avatars/{$screenshot}");

Categories