PHP Image Hashing in directory and database - php

I am still having trouble hashing my pictures when I upload them . I have this code :
$target_dir = "images/uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);
hash_file('sha256', $target_file );
// Check if image file is a actual image or fake image
if(isset($_POST["change"])) {
move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file);
$sql = "UPDATE users SET userPic = '".$_FILES['fileToUpload']['name']."' WHERE username = '" . $username . "'";
$check = $conn->query($sql);
if($check !== false) {
echo "<a href = profile.php> Profile pciture has been changed </a>" .
$check["mime"] . ".";
$uploadOk = 1;
} else {
echo "File is not an image.";
$uploadOk = 0;
}
} else {
echo"did not change";
}
and I am getting this error :
Warning: hash_file(images/uploads/english_royal_family_tree.jpg): failed to open stream: No such file or directory
I have been trying for more than a week . No one is really helping and people just keep on voting down my question and aren't giving any help . Can someone please help me ?

Firstly, hash_file() is expecting a file to already exist and you're trying use that method before the file gets uploaded; that's why your code failed and threw you that error.
What you need to do is to see if that file exists and then hash it.
If this is really want you want to do, then you can base yourself on the following and remember to store the renamed file while retaining its original extension; there are links at the end of the answer.
Note: As I mentioned in comments, you need to hash the file and not the whole destination folder and the file. That would be impossible to retrieve.
Echo the variable for what was assigned to hash_file(). You will also get your hash name (only) shown minus its extension.
Check for errors and make sure the folder has been granted proper permissions.
<?php
// check for errors
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$file_name = $_FILES['fileToUpload']['name'];
$sent_file = move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file);
if (file_exists("images/uploads/" . $_FILES["fileToUpload"]["name"]))
{
echo $the_file = $_FILES["fileToUpload"]["name"] . " exists.";
// its new location and hashing the filename only.
$var = hash_file('sha256', $the_file );
echo $var;
// store your renamed file here in your database
// using the assigned $var variable.
}
Also check for errors on the query with mysqli_error($conn).
However, you're going to end up with problems here to show that image, since now and for example in using "file.jpg" will produce the following hash:
cf80cd8aed482d5d1527d7dc72fceff84e6326592848447d2dc0b0e87dfc9a90
I don't know how you plan on showing the image(s), but it will no longer keep the .jpg extension.
In order to retain the image's file extension, you basically need to rename the uploaded file(s).
Here are a few good references on Stack (that I've had success with in the past) that you can look at and implement it in your code. :
How to rename uploaded file before saving it into a directory?
Rename uploaded file (php)
There is indeed no better way to learn, IMHO.
Edit:
This is an excerpt from a script I wrote recently. Base yourself on the following.
Note: You shouldn't use hashing methods such as anything from the SHA family or MD5 as the file name, since those produce the same hash and has no uniqueness to them.
Important: If people upload from a mobile device, most of them have "image.jpg" as the default name, so it needs to be renamed and given a unique method.
Using the date and time is one way. You can also add uniqid() to it by assigning a variable to it and append to the new file name, or a combination of MD5 and uniqid() is a good bet.
You will need to do a few modifications to it of course. The $year variable is something I used but you can get rid of those instances and replace them with your own.
$year = date("Y");
$pdf_file = $_FILES['fileToUpload']["name"];
$uploaded_date = date("Y-m-d_h-i-s_A"); // this could be another unique method.
$target_dir = "../upload_folder/" . $year . "/";
$ext = explode('.',$_FILES['fileToUpload']['name']);
$extension = $ext[1];
$newname = $ext[0].'_'.$uploaded_date;
$full_local_path = $target_dir.$newname.'.'.$extension;
$new_full_name = $newname.'.'.$extension;
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $full_local_path)) {
echo "The file ". $newname . " has been uploaded.";
echo "<hr>";
$file_link = "/upload_folder/$year/$new_full_name";
// other code such as saving to a database...
}

Related

Codeigniter 4: Uploading files with move_uploaded_file

I just started moving CodeIgniter 3 project to CodeIgniter 4.
Everything works fine except file upload.
I would like to keep the user uploaded files in /writable/uploads. Below is the code I use to move the uploaded file to desired location.
$target_dir = '/writable/uploads/recordings/';
$target_file = $target_dir . basename($_FILES["gfile"]["name"]);
$FileType = pathinfo($target_file,PATHINFO_EXTENSION);
if($FileType != "mp3") {
$vmuploadOk = 1;
}
else
$vmuploadOk = 1;
if ($vmuploadOk == 1) {
$greetfile = $id . "g" . basename($_FILES["gfile"]["name"]);
$target_filenew = $target_dir . $greetfile;
move_uploaded_file($_FILES["gfile"]["tmp_name"], $target_filenew);
}
I assume that it is because CI4 keeps writable folder outside public folder.
You are not using CodeIgniter's built in functions. Everything shown in your code are PHP functions. If you want to leverage built in CI functions, then look through the documentation as linked by #Boominathan Elango.
To get the file from the request:
$file = $this->request->getFile('here_goes_input_name');
As specified here
To move the file using CI function:
$file->move(WRITEPATH.'uploads', $newName);
As specified here
This worked for me and I hope it will also work for you. In codeigniter 4 please use this to upload your files and move it in your controller.
if($imagefile = $this->request->getFiles())
{
if($img = $imagefile['gfile'])
{
if ($img->isValid() && ! $img->hasMoved())
{
$newName = $img->getRandomName(); //This is if you want to change the file name to encrypted name
$img->move(WRITEPATH.'uploads', $newName);
// You can continue here to write a code to save the name to database
// db_connect() or model format
}
}
}
OR
if($img = $this->request->getFile('gfile'))
{
if ($img->isValid() && ! $img->hasMoved())
{
$newName = $img->getRandomName();
$img->move(ROOTPATH . 'public/uploads/images/users', $newName);
// You can continue here to write a code to save the name to database
// db_connect() or model format
}
}
Then in your html input field
<input type="file" name="gfile">
I hope this works else call my attention

Using move_uploaded_file To Rename File BEFORE Being Placed In uploads/ Folder

I've seen questions similar to this but no one seems to have the problem I do.
I've set up a process to check to see if the filename already exists in a MySQL table, and if it does, it puts a timestamp between the filename and the extension (E.G. Test.PDF becomes Test-19:25:36 if it's a duplicate), thus negating any database conflicts.
My issue is that the while the database is updated correctly, the duplicate file isn't uploaded with the timestamp in the name. Instead, it uses the duplicate name and just overwrites the original and creates a ghost "filename" listing in the database.
I've seen you can use move_uploaded_file to rename files in the servers memory before they're uploaded, but I've tried multiple ways and can't get it to rename the file in memory BEFORE attempting to write it to the "/uploads" folder. Here's the upload code:
<?php
include_once 'dbconnect.php';
//check if form is submitted
if (isset($_POST['submit'])) {
// START OF PRE-EXISTING FILE CHECK
$filename = $_FILES['file1']['name'];
$dupeCheck = "SELECT * FROM tbl_files WHERE filename = '$filename'";
if ($output = mysqli_query($con, $dupeCheck)) {
if (mysqli_num_rows($output) > 0) {
$fileArray = pathinfo($filename);
$timeStamp = "-" . date("H:i:s");
$filename = $fileArray['filename'] . $timeStamp . "." . $fileArray['extension'];
}
}
// END OF PRE-EXISTING FILE CHECK
if($filename != '')
{
$trueCheck = true;
if ($trueCheck == true) {
$sql = 'select max(id) as id from tbl_files';
$result = mysqli_query($con, $sql);
//set target directory
$path = 'uploads/';
$created = #date('Y-m-d H-i-s');
$moveTargetVar = "uploads/" . $filename;
move_uploaded_file($_FILES['file1']['tmp_name'], $moveTargetVar);
// insert file details into database
$sql = "INSERT INTO tbl_files(filename, created) VALUES('$filename', '$created')";
mysqli_query($con, $sql);
header("Location: index.php?st=success");
}
else
{
header("Location: index.php?st=error");
}
}
else
header("Location: index.php");
}
?>
Any advice on how to rename a file before it's written to the uploads folder?
I'd suggest not using : to separate your time stamp, because that will cause issue with file name restrictions. Try doing something like:
$timeStamp = "-" . date("H-i-s");
Solved by replacing move_uploaded_file($_FILES['file1']['tmp_name'], $moveTargetVar); with move_uploaded_file($_FILES['file1']['tmp_name'],$path . $filename);
Deprecated $moveTargetVar = "uploads/" . $filename;

PHP - Simple script for image compression with pngquant

:) i found this 1 line of code in another post which successfully compresses the image using pngquant. the thing is, it outputs the optimised image with a different name (obviously to preserve the original).
im trying to find a way to:
a) add a minimum quality parameter of 60
b) use an if/else statement to to allow the user to choose to overwrite the existing file or output a new optimised image (of a user specified name)
thank you! ntlri - not to long read it
<?php system('pngquant --quality=85 image.png'); ?>
so what i have tried is the following.. for some reason the single quotes need to be double quotes to parse the variables correctly..
<?php
$min_quality = 60; $max_quality = 85;
$keep_original = 'dont_keep';
if ($keep_original == 'keep') {
$image_name = 'image.png';
$path_to_image = 'images/' . $image_name;
$new_file = 'image2.png';
$path_to_new_image = 'images/' . $new_file;
// don't know how to output to specified $new_file name
system("pngquant --quality=$min_quality-$max_quality $path_to_image");
} else {
$image_name = 'image.png';
$path_to_image = 'images/' . $image_name;
// don't know if you can overwrite file by same name as additional parameter
system("pngquant --quality=$min_quality-$max_quality $path_to_image");
// dont't know how you get the name of the new optimised image
$optimised_image = 'images/' . $whatever_the_optimised_image_is_called;
rename($optimised_image, $image_name);
unlink($optimised_image);
}
?>
from the docs of this program :
The output filename is the same as the input name except that\n\ it
ends in \"-fs8.png\", \"-or8.png\" or your custom extension
so , for this question:
// don't know how to output to specified $new_file name
system("pngquant --quality=$min_quality-$max_quality $path_to_image");
to choose a new name, assume you are compress image name.png :
--ext=_x.png
this will create new image called name_x.png
so , your $new_file would be just a suffix ,
$new_file = '_x.png'; // to choose new file name name_x.png
// don't know if you can overwrite file by same name as additional
parameter
as mentioned in the program docs , the new file name will be suffixed by either -fs8.png or -or8.png , so you may rename the file which will produced with this suffix , OR simply set the --ext option to : .png and this will append to the original file
--ext=.png
for more details, check the repository
i spoke to pornel whos the chappie that developed pngquant. its actually a lot simpler than all that i wrote that before...
! important - it is very important to use escapeshellarg() else people can take over your server by uploading a file with a special filename apparently.
$image_name = 'image.png';
$target_file = 'images/' . $image_name;
$existing_image = 'image.png'; // image already on server if applicable
$keep = 'keep';
$target_escaped = escapeshellarg($target_file);
if ($keep == 'keep') {
// process/change output file to image_compressed.png keeping both images
system("pngquant --force --quality=70 $target_escaped --ext=_compressed.png");
$remove_ext = substr($newFileName, 0 , (strrpos($newFileName, ".")));
// $new_image is just the name (image_compressed.png) if you need it
$new_image = $remove_ext . '_compressed.png';
// remove old file if different name
if ($existing_image != $newFileName) {
$removeOld = '../images/' . $existing_image;
unlink($removeOld);
} // comment out if you want to keep existing file
} else {
// overwrite if file has the same name
system("pngquant --force --quality=70 $target_escaped --ext=.png");
// remove old file if different name
if ($existing_image != $newFileName) {
$removeOld = '../images/' . $existing_image;
unlink($removeOld);
}
$new_image = $newFileName;
}
to override same name use this command
pngquant.exe --ext=.png --force input.png
so the output name will remain input.png

Image won't change when replaced

I have a piece of code to upload a picture and save it in a folder and the path in a databaseand show it on the webpage. Funny enough, upon uploading the picture for the first time, the image will show on the webpage and with change when I upload a new picture. But when I close the page, reopen it another day and decide to change the picture, the one of the webpage won't change even if i refresh the page but the one in the folder will change.
Here's my code
<?php
$sql2 = "SELECT Picture_HD FROM detailss WHERE Idn_nom = '$Indnum'";
require('connect.php');
$addr = "";
$addr = mysqli_query($conn, $sql2);
if ($addr) {
$locat = $addr->fetch_row();
$locat = (string)$locat[0];
} else {
$locat = "Pictures/default1.png";
}
mysqli_close($conn);
echo "<div id = 'Img'>";
echo "<img src = '" . $locat . "' alt = 'Passport picture/Headshot' style = 'width:80px; height:80px;'/>";
echo "</div>";
?>
Your browser is caching the image.
If you want to prevent the browser to cache the image just add a random parameter at the end of the url.
echo "<img src = '" . $locat . "?t=" . time() . "' alt = 'Passport picture/Headshot' style = 'width:80px; height:80px;'/>";
If your image is changing in your folder but you are seeing the old one on the webpage it's likely a caching issue, clear your browser cache (ctrl+f5 plus this is kinda broken so doesn't always work - so best to go into browser settings to do it, or open a private window after ctrl+f5) and if not the clear server level cache.
The best way to do this is to delete the existing image right before uploading the new one with the same file name
// define variables used for file name from session variable username the directory and extension by exploding the file name from the post method from a form with a metadata type
//set new file name to username from session variable
$filename = $_SESSION['username']
// set directory of files
$dir = "img/";
// set extension variable to file extension after posted from form
$ext=strtolower(end(explode('.',$_FILES['importimg']['name'])));
// new file upload name with existing extension
$upload_file = $dir . $filename . "." . $ext;
// delete file
// find all files with the same name any extension using variable defined above etc .txt, .php, .gif, .jpg, etc. then delete it
foreach (glob("img/$filename.*") as $deletefile) {
// unlink is used to delete the file and delete the cache of the file
unlink($deletefile);
}
// upload image
// upload file with type posted from metadata in form and upload it as your new file name using upload_file variable
if (move_uploaded_file($_FILES['importimg']['tmp_name'], $upload_file)) {
// successful upload of file add code for msg or sql query etc name to users table and redirect to profile page
echo "Successfully uploaded your file.";
} else {
// upload error show message
echo "There was an error uploading your file.";
}
Enjoy

PHP Delete file

I am trying to develop a user page for a forum and I'm kinda struggling with the image upload.
The problem is that I would like to limit the user to only be able to upload one single image, but be able to change it anytime. so basically, I would like to either overwrite the existing file either delete the old picture and add a new one instead.
At this point I have a piece of code that adds a timestamp at the end of the file (which I don't really need actually).
CODE:
if(isset($_POST['upload']))
{
$extension=strstr($_FILES['uploadedfile']['name'], ".");
$filename = "_/userfiles/userpics/".basename($_FILES['uploadedfile']['name'],
$extension);
$target = "_/userfiles/userpics/".basename($_FILES['uploadedfile']['name']);
$valid = true;
if(file_exists($target))
{
$filename = $filename . time();
$target = $filename . $extension;
}
if($valid)
{
// move the file into the folder of our choise
move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target);
$img_sql = "INSERT INTO sp_userimage (imageid, path, id) value ('', '".$target."', '".$_SESSION['userid']."')";
$img_result = mysql_query($img_sql);
echo "upload sucessfull";
}
Make use of unlink() in PHP Manual.
if(file_exists($target))
{
unlink($target); // deletes file
//$filename = $filename . time();
//$target = $filename . $extension;
}
I think this might be a bit better suited for you. You might have to edit it a tad.
if($valid)
{
// Check if user has a file.
$img_check = mysql_query("SELECT * FROM sp_userimage WHERE id = " . (int) $_SESION['user_id']);
if( mysql_num_rows($img_check) > 0 ){
$row = mysql_fetch_object($img_check);
// Delete the file.
unlink($row->path);
}
// move the file into the folder of our choise
move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target);
$img_sql = "INSERT INTO sp_userimage (imageid, path, id) value ('', '".$target."', '".$_SESSION['userid']."')";
$img_result = mysql_query($img_sql);
echo "upload sucessfull";
}
It might be easier to normalize the image type (e.g. only jpegs) and then name the file as the userid. For example:
$target = 'userpics' . DIRECTORY_SEPARATOR . $_SESSION['userid'];
move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target);
This will simply overwrite the old picture with the new one. Given that this type of filename is deterministic, you also don't need to store the filename in the database.
Use unlink() function
read more here PHP unlink
okay ,if u want to delete the file for that particular user only.
then store the filename vs user in some MapTable in db.
mysql_query("CREATE TABLE t_usr_file_map(
usr_id INT NOT NULL ,
file_name VARCHAR(100),
)")
or die(mysql_error());
and at the time of reupload , fetch the filename from the table for that user , unlink it and reupload the fresh one again.
OR,
or u can use PHP file_rename function at the time of upload. rename filename to the userid
rename ( string $oldname , string $newname [, resource $context ] )
and u can always do unlink based on user-id
Its very simple by unlink()
as:
unlink(dirname(__FILE__) . "/../../public_files/" . $filename);
if (file_exists($path))
{
$filename= rand(1,99).$filename;
unlink($oldfile);
}
move_uploaded_file($_FILES['file']['tmp_name'],$filename);

Categories