base64 image upload validation - php

I'm making a feature on my website that a user uploads an image either by loading it from file or by using their computer's built-in webcam.
I take a picture with either my webcam or I load it from file
I store the base64 in an input which is submitted to the server along with other information.
The server validates the base64 (looks for hacks)
The image is stored on the server
I understand the validation method I used:
Takes a lot of processing speed on the server (encoding and decoding)
Has bugs / not reliable
Is probably not secure enough
Is there any more secure, "server-friendly", and reliable way of validating the base64??
(I couldn't find any promising methods in other posts.)
It fails when I face the camera at certain places (somehow the base64 is affected by certain pictures)
Thanks so much for any help!
-- dragonfire
upload.php script:
<?php
$uploaded_file_b64 = htmlspecialchars($_POST['b64_img_url']); // string containing base64 of uploaded image
$FileName = "the_unique_uploaded_file_name.png";
$file_path = "/uploads/" . $FileName;
$file_relative_path = "../uploads/" . $FileName; // BUG: need to use relative path rather than absolute since absolute path doesn't work. Why???
//Must get actual base64 out of string by splicing it
$uploaded_file_actual_b64 = explode("base64,",$uploaded_file_b64);
//We need to get the second value from the array returned from explode() since there are two commas before the actual base64
$uploaded_file_actual_b64 = $uploaded_file_actual_b64[1];
// First try to decode then re-encode the base64. If works then perfect!
if ($uploaded_file_actual_b64 == base64_encode(base64_decode($uploaded_file_actual_b64))) {
// It worked!
echo "Valid base64!";
}
else {
// It failed! THIS IS WHERE IT ALWAYS ERRORS!! WHY???
echo "Not base64!";
}
// Try creating an image from the base64. If works then perfect!
$is_image = imagecreatefromstring(base64_decode($uploaded_file_actual_b64));
//doing this will help confirm it's an image, but it is still possible to inject php or js into
//the body of the image, but as long as we don't execute the image on the server
//then we should be fine
if ($is_image != false) {
echo "Valid image!";
} else {
echo "Not an image!";
}
// If we get up to here, then nothing has been tampered with!
echo "Secure!";
// Store the image on the server
if (file_put_contents($file_relative_path, base64_decode($uploaded_file_actual_b64))) {
echo "Upload success!";
} else {
echo "Upload failed!";
}
?>
Client side code:
<form method="post" action="upload.php" enctype="multipart/form-data">
<input type="text" id="b64_img_url" name="b64_img_url" style="display: none;"/>
<input type="submit" class="btn btn-success" value="Submit" />
<div id="btn_cam_capture" onclick="capture_webcam();">Capture</div>
<canvas id="camera-stream-canvas"></canvas>
<img id="img-drop-preview"/>
<script>
var canvas = document.getElementById("camera-stream-canvas");
function capture_webcam() {
// Executed when user takes shot.
// Previews the image by converting the canvas to a base64 image.
document.getElementById("img-drop-preview").src = canvas.toDataURL();
// The input which stores the base64
document.getElementById("b64_img_url").value = canvas.toDataURL();
}
</script>
</form>

Related

PHP Post data not received

i'm currently working on a small script for my Homepage but i ran into a problem.
I Try to upload an Image, but it seems like the POST data from the form is not being received. What did i do wrong?
I already changed the post_max_size and everything in the php.ini.
These are the Errors i get:
"Notice: Undefined index: image in ...." & "Notice: Undefined index:
submit in ...."
<form method="POST" action="/eye/sites/handling/post.php" enctype="multipart/form-data">
<div class="fileUpload">
<span><i class="fa fa-folder-o" aria-hidden="true"></i> Bild wählen</span>
<input type="file" class="upload" name="image"/>
</div>
<input type="submit" value="Upload It!" name="submit"/>
</form>
<?php session_start();
error_reporting(E_ALL);
if (isset($_SESSION["login_stat"])) {
date_default_timezone_set('Europe/Berlin');
$config = "$_SERVER[DOCUMENT_ROOT]/eye/more/config.xml";
$xml = simplexml_load_file($config);
$picWidth = $xml->pic->width;
$picHeight = $xml->pic->height;
$fulldate = date('dmYHis');
if(isset($_POST["submit"])) {
if (file_exists($_FILES['image']['tmp_name']) || is_uploaded_file($_FILES['image']['tmp_name'])) {
$typeCheck = $_FILES['image']['type'];
if ($typeCheck != "image/jpeg") {
$error = "Not a .jpg";
header('location: /eye/sites/post.php?stat=bad&error='.$error);
exit;
}
$file = $_SERVER['DOCUMENT_ROOT']."/uploads/".$fulldate.".jpg";
$type = "image/jpeg";
move_uploaded_file($_FILES['image']['tmp_name'], $file);
$file_thmb = $_SERVER['DOCUMENT_ROOT']."/uploads/!1A_thmb/".$fulldate.".jpg";
include "resize-class.php";
$resizeObj = new resize($file);
$resizeObj->resizeImage($picWidth, $picHeight, 'crop');
$resizeObj->saveImage($file_thmb, 100);
// header('location: /eye/sites/post.php?stat=good');
} else{
// header('location: /eye/sites/post.php?stat=bad&error=No File');
}
} else{
// header('location: /eye/sites/post.php?stat=bad&error=No Data');
echo $_SERVER['CONTENT_TYPE'];
echo "<br>";
echo $_FILES['image']['tmp_name'];
echo "<br>";
echo $_POST['submit'];
echo "<br>";
}
} else {
header('location: /eye/index.php?stat=in');
}
?>
Edit:
The problem is definitely about my Localhost.
This whole thing is working fine on my Webspace, but on my localhost it's not working.
BUT: I'm not getting errors anymore, when is click on Submit it goes to the php file that should save the image, but nothing is happening. I just see a white Page.
But like i said, it runs perfectly on my webspace..
If this is running on your local machine, do a quick check to make sure your "php.ini" file is configured to allow file uploads.
php.ini
file_uploads = On
The codes look fine. Check if your form action is posting to the correct path and if I may suggest using a simpler approach to test your file upload function before making it more complex. Use the following to start testing.
if (isset($_POST["submit"])) {
if (file_exists($_FILES['image']['tmp_name']) || is_uploaded_file($_FILES['image']['tmp_name'])) {
echo "Upload is working!";
}
}
Keep us updated on your findings.
Perhaps this general information will help someone, as it helped me: a submitted form will only include fields that have defined 'name' attributes. 'id' is not enough.
The idea is that 'id' identifies an element in the DOM for use by JavaScript (either as a global variable or for use in document.getElementById(ID)), but 'name' identifies those elements whose names and values will be sent to the destination ('action') page.
So it makes sense that there are two different identifying attributes, used in two different ways.

Send image to php script using Form

hi i want to save image to mysql using php script and form html but in this code i see that the image is not sent to php can you help me please i am beginer in php.
Form.html
<form action="upload_image.php" method="post" enctype="multipart/form-data">
<p>
<input type="file" name="photo" />
<input type="submit" value="Submit" name="submit"/>
</p>
</form>
<b>
Afficher la premiere image de la base de donnes
</b>
php script :
<?php
echo ini_get( 'file_uploads' );
if($_SERVER['REQUEST_METHOD']=='POST'){
$con = mysqli_connect("localhost","root","","othmane");
if ($con->connect_errno) {
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
$img = $_POST['photo'];
if($img!=null){
$sql = "INSERT INTO images (image) VALUES (?)";
$stmt = mysqli_prepare($con,$sql);
mysqli_stmt_bind_param($stmt,"s",$img);
mysqli_stmt_execute($stmt);
$check = mysqli_stmt_affected_rows($stmt);
if($check == 1){
echo "Image Uploaded Successfully";
}else{
echo "Error Uploading Image";
}
}else{
echo "image not found";
}
mysqli_close($con);
}else{
echo "Error";
}
?>
Why is the image not sent to script ? i got always image not found in php.
The right way to access to file element by POST method is not $img = $_POST['photo']. You should use $_FILE var, for example $img = $_FILE['photo']['name'] to get the name of file.
There are some different info you can get from $_FILE var:
$_FILES['photo']['name']
The original name of the file on the client machine.
$_FILES['photo']['type']
The mime type of the file, if the browser provided this information. An example would be "image/gif". This mime type is however not checked on the PHP side and therefore don't take its value for granted.
$_FILES['photo']['size']
The size, in bytes, of the uploaded file.
$_FILES['photo']['tmp_name']
The temporary filename of the file in which the uploaded file was stored on the server.
$_FILES['photo']['error']
The error code associated with this file upload.
Look here: http://php.net/manual/en/features.file-upload.post-method.php
Pay attention: If you need to store the image in DB you need to convert file in binary data and store in DB as BLOB type.
Look here: http://dev.mysql.com/doc/refman/5.0/en/blob.html
As alternative, a good way is to store the file in a folder on your host and save the path in a DB.

How to i post image id to php along with $_FILE

index.html with form tag
<input type='file' name='picture' id='".$row['sfname']."'onchange='javascript:ajaxFileUpload(this);'/>`
ajax code
function ajaxFileUpload(upload_field)
{
// Checking file type
var re_text = /\.jpg|\.gif|\.jpeg/i;
var filename = upload_field.value;
if (filename.search(re_text) == -1) {
alert("File should be either jpg or gif or jpeg");
upload_field.form.reset();
return false;
}
document.getElementById('picture_preview').innerHTML = '<div><img src="ajax-loader.gif" border="0" /></div>';`
upload_field.form.action = 'upload-picture.php';
upload_field.form.target = 'upload_iframe';
upload_field.form.submit();
upload_field.form.action = '';
upload_field.form.target = '';
return true;
}
upload.php
<?php
?>
I want $row['sfname'] in index.html to be accessed along with $_FILE variable here but how can I get the script to store the image in given folder so that I can store the path in the respective user record.
I have tested the upload.php by uploading the files successfully to the file system, now I want the file path to be stored in the sql table. For that I need the user first name the same I get it from the same
My question is; How do I access the input tag ID using the above ajax code to upload.php?
Why not simply put $row['sfname'] as a value of a hidden field as your JavaScript is submitting the whole form?
<input type='hidden' name='sfname' value='" . $row['sfname'] . "'>

How to check if image was submitted with other form data

I have an user registration form and uploading image with other form elements is optional there. So sometimes users may not upload image along with other data.
Now the problem is even though the user has not uploaded image, the following code always echos that the file was uploaded
Could you please kindly tell me how to check if the image was submitted by the user and make it echo/display "not uploaded" if not uploaded ?
Thanks in Advance :)
In my Controller File
extract($_POST); // <<This is to retrieve all form data at once
if(isset($_FILES['userfile'])){
echo"file uploaded";
} else{
echo "Not Uploaded";
}
This is in my View File
<input type="file" class="" name="userfile" size="20" />
Per PHP documentation:
If no file is selected for upload in your form, PHP will return $_FILES['userfile']['size'] as 0, and $_FILES['userfile']['tmp_name'] as none.
source: http://www.php.net/manual/en/features.file-upload.post-method.php
So your conditional can change to:
if(isset($_FILES['userfile']) && $_FILES['userfile']['size'] > 0){
echo"file uploaded";
} else echo "Not Uploaded" ;
You can combine both checks:
if (count($_POST) and !empty($_FILES['userfile'])) {
// uploaded
}
else {
// either is missing
}
Note that you should not use extract($_POST);. You can't control which local variables get overwritten from the outside with that. (If nothing else investigate EXTR_PREFIX.)

Problem with uploading multiple files PHP

On my site I have a page where users can upload files to go with the news post they're adding. I allow them to upload one image and one sound file. They don't have to add files if they don't want to, or they can just add one if they want. Problem I'm having is that my script only works if the user selects both files. If they choose none, or only one, then the script spits out 'Invalid File' as it can't find a file where one hasn't been selected.
I tried using:
if (isset($_FILES['filetoupload1'])) {
if (($_FILES["filetoupload1"]["type"] == "image/gif")
|| ($_FILES["filetoupload1"]["type"] == "image/jpeg")
|| ($_FILES["filetoupload1"]["type"] == "image/pjpeg")
|| ($_FILES["filetoupload1"]["type"] == "image/png")
|| ($_FILES["filetoupload1"]["type"] == "image/jpg")
) {
if ($_FILES["filetoupload1"]["error"] > 0) {
echo "Return Code: " . $_FILES["filetoupload1"]["error"] . "<br />";
} else {
if (file_exists("media/" . $_FILES["filetoupload1"]["name"])) {
echo $_FILES["filetoupload1"]["name"] . " already exists. ";
}
move_uploaded_file(
$_FILES["filetoupload1"]["tmp_name"],
"media/" . $_FILES["filetoupload1"]["name"]
);
}
} else {
echo "Invalid file";
}
}
if (isset($_FILES['filetoupload2'])) {
if ($_FILES["filetoupload2"]["type"] == "audio/mp3") {
if ($_FILES["filetoupload2"]["error"] > 0) {
echo "Return Code: " . $_FILES["filetoupload2"]["error"] . "<br />";
} else {
if (file_exists("media/" . $_FILES["filetoupload2"]["name"])) {
echo $_FILES["filetoupload2"]["name"] . " already exists. ";
}
move_uploaded_file(
$_FILES["filetoupload2"]["tmp_name"],
"media/" . $_FILES["filetoupload2"]["name"]
);
}
} else {
echo "Invalid file";
}
}
and then
if((isset($_FILES['filetoupload1'])) && (isset($_FILES['filetoupload2']))) { }
before both first and second upload scripts if the user had selected both image and audio file. In other words it did this:
if filetoupload1 isset then run upload script that filters images.
if filetoupload2 isset then run upload script that filters audio.
if filetoupload1 AND filetoupload2 isset then run both upload scripts.
I have it set like that. The above should allow for all combinations of file uploads. right? but it doesnt work so..
Now I have no idea what to do. Here's the upload script for the audio, the image one is pretty much the same:
Can someone tell me what I'm doing wrong please!
"I get the error: Invalid file"
This is correct, since your code just does this.
Do not check if the file is set but if i.e. $_FILES["filetoupload1"]["type"] is not empty.
Your script makes your server vulnerable to a malicious user being able stomp on any file the webserver has access to:
$_FILES[...]['name'] - user supplied
$_FILES[...]['type'] - user supplied
You're trusting that the client has supplied the proper MIME type for the file, but nothing stops someone from forging a request and uploading "virus.exe" and setting the mime type to 'image/jpeg'. As well, since the remote filename is under user control, it can be subverted with malicious data. Consider:
$_FILES['picture']['type'] = 'image/gif'
$_FILES['picture']['name'] = 'remote_server_control.php'
Completely legitimate according to your script, because the mime type is "right", and yet you've now put a user-supplied PHP script on your server and with that they can take total control of your site and/or server.
Never EVER trust the data in the $_FILES array. Always determine MIME types via server-side utilities. If the script is only supposed to handle images, then use getimagesize(). As well, never use user-supplied filenames. Use something determined server-side to give the file a name, like a databasde auto_increment ID number. Even though your code doesn't allow for overwriting existing files, it's trivial to just come up with a new name and boom... new version of the remote takeover script.
I suggest to you to add a hidden text, this hidden will check witch upload fields are active, you make this check with javascript:
<html lang="en">
<head>
<meta charset="utf-8">
<style>
</style>
<script type="text/javascript">
function uploadForm()
{
var size = 0;
var x = document.forms["myForm"]["upload1"].value.length;
var y = document.forms["myForm"]["upload2"].value.length;
if (x > 0)
{
size = 3;
}
if (y > 0)
{
size += 2;
}
return size;
}
</script>
</head>
<body>
<form name="myForm" action="" method="GET" onsubmit="chose.value = uploadForm()">
<input type="file" name="upload1"><br>
<input type="file" name="upload2"><br>
<input type="hidden" name="chose" value=""><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
Now, when you receive the form, you have to check the value of chose filed, if its 2, that is mean the image field is not empty, 3 audio filed is not empty, 5 both not empty:
<?php
switch($_GET["chose"])
{
case 2:
//
break;
case 3;
//
break;
case 5:
//
break;
default:
// here the user doesn't use any field
}
?>

Categories