Delete a specific image out of a folder - php

I have a website that allows users to upload photos to my folder. When the page refreshes, it will show all images inside that folder.
I used scandir instead of glob function to read the images. I check the file type extension to see if it is in allowed format (jpg, jpeg, gif, png) Then I use a loop to display them. Each image has a "delete" link next to it.
When the user presses the "delete" link, I want to remove the specific image in the folder. I know the function unlink() is able to delete the image, but I couldn't do this because I don't know how to pass that specific image name to delete.php. Somebody told me to use AJAX, which I haven't learned yet. If it is necessary, I will go learn it immediately. So please tell me if there are any ways to solve this instead of AJAX. Thank you so much!
$dir = 'images/';
$file_type_allowed = array('jpg','jpeg','png','gif');
$dir_contents = scandir($dir);
foreach($dir_contents as $file){
$file_type = explode('.',$file);
$file_type = strtolower(end($file_type));
if($file !== '.' && $file !== '..' && in_array($file_type, $file_type_allowed) == true){
echo '<img src="', $dir, '/', $file, '" alt="', $file, '" />';
echo 'Delete';
}

You could just pass the argument in the URL, and access it via the $_GET superglobal. This will reload the page however. Ajax will allow the user to click the "Delete" link and not have the page reload.
Anyway, if you make your delete link something like
echo 'Delete';
And then in delete.php access the file needing to be deleted as
$file = urldecode($_GET['file']);
// verify the file exists, and that the user should have access
unlink($file);
You need to be very careful however, and make sure you check the file location prior to deleting. Otherwise a malicious user could just enter "delete.php?file=delete.php", and break your site. So you need to check what directory they are deleting from, and that the file type is an image.

Related

Replace save files if from same User

I have a directory called resale_certificates where I save files to but encrypt the name using parts of their email and codes assigned to them.
NOTE: The encryption is the same every time but unique to each user!
When they upload image.png it will save the file to theirEncrypt.png
If they upload another image.png it will replace theirEncrypt.png
However when they upload image.jpg now there will be theirEncrypt.jpg and theirEncrypt.png in the resale_certificates directory.
What is the best way to handle this? I'm looking for advice and open to changing how I'm saving it or tricks I could do to prevent this!
Thank You!
Well, you could use an image library to transform their uploaded image to whatever format you want, i.e. if they upload a .JPG you can use image libraries like Imagick or GD to output a .PNG file and upload those.
However, if you don't mind either the .JPG or .PNG ( or .GIF for that matter) you can scan the directory with PHP to look for all files ( can be really intensive though! ) to look for files with the name given.
For example:
<?php
foreach( scandir('/path/to/resale_certificates/') as $file ){
if( $file != '.' && $file != '..'){
// explode so we remove the last extension path ( not type safe ! )
$arguments = explode('.', $file);
// store the last part
$ext = end($arguments);
// pop the extension from the $arguments array so we are left
// with whatever was left
array_pop($arguments);
// concatenate the $arguments into a single string again
$filename = implode('.', $arguments);
// now we can check the filename again
if( $filename == $theirEncrypt){
unlink('/path/to/resale_certificates/' . $filename . '.' . $ext);
}
}
}
edit:
the $file is a string from the $files array returned by the scandir(); function. The single and double dot are a ways to navigate to the current (.) and the parent (..) directory and are therefore symlinks. Another option would be to check if the $file is actually a file. You could replace the comparison line with a is_file('/path/to/resale_certificates/' . $file) to check if it's a file or a symlink ( like the . and the .. ) but it's even more intensive then to check string comparison. In your usecase it is not neccesary.
On a related note, this is quite intensive, depending on the number of clients and certificates you have, you could, as an alternative, store the filename to storage (i.e. database or something similiar) and just unlink the file find there, this would save you to iterate over each file and simply unlink the file directly.
If you know a name of previously uploaded image then you can do the following before saving a new image:
<?php
$previousImageName = 'theirEncrypt.png';
unlink(APP_DIR . "/resale_certificates/" . $previousImageName);

Uploading a profile picture and displaying it

I want users to be able to upload a profile picture (which can be .jpg or .png) and I also want this to be displayed on their profile. I have written some code, based on sources I found here, on Stackoverflow and Google. However, it does not seem to work and I can't find my mistake.
This is the html
<form action="account_settings.php" method="POST">
<input type="file" name="profilePicture"><br><br>
<input type="submit" value="Change!">
</form>
This is how to uploaded file will be processed.
<?php
include ('inc/header.inc.php');
if(isset($_FILES["profilePicture"]["tmp_name"]) && isset($_FILES["profilePicture"]["name"])) {
$ext = pathinfo($_FILES['profilePicture']['name'], PATHINFO_EXTENSION);
$name = $_SESSION['user_login'];
$tmp_name = $_FILES["profilePicture"]["tmp_name"];
if($ext == 'png' || $ext == 'jpg') {
if (isset($tmp_name)) {
if(!empty($tmp_name)) {
$location = '../profielfotos/';
$full_name = $name.'.'.$ext;
if(move_uploaded_file($tmp_name, $location.$full_name)) {
echo 'Photo uploaded!';
}
Down here are just some else statements with error reports.
The code below is used to display the image. I have tested it by putting an image in the profile pictures folder and it did display the image. However, there is still a problem. People are allowed to upload .jpg or .png, how can I make the website display the picture (find the profile picture with the right extension).
I have put this code inside the src attribute of the <img>tag.
<?php if ($handle = opendir('profielfotos/')) {
$file = mysql_real_escape_string($_GET['u']);
echo 'profielfotos/'.$file.'.png';
}
closedir($handle);
I hope someone can help, thanks in advance!
ps. this is my first post ever on stack overflow :-D!
Since you are not storing any info about the file uploaded, you just have check which file exists, using he file_exists() method. See here:
http://php.net/manual/en/function.file-exists.php
So your code will become something like this (Not tested):
<?php if ($handle = opendir('profielfotos/')) {
$file = mysql_real_escape_string($_GET['u']);
if (file_exists('profielfotos/'.$file.'.png')) {
echo 'profielfotos/'.$file.'.png';
} else if (file_exists('profielfotos/'.$file.'.jpg')) {
echo 'profielfotos/'.$file.'.jpg';
}
}
closedir($handle);
You need to add the following to your form:
<form action="account_settings.php" method="POST" enctype="multipart/form-data">
Otherwise it won't allow a file upload as it expects only text.
This is totally insecure. Files uploaded by a user shall never ever be stored within the root of the web server.
Instead, put the files somewhere outside of the doc root.
Write a handler, which takes control of he files
check the mime type by checking the content, not the extension
have arbitrary names, not the name from the upload, that might interfer (imagine 5 people uploading a "profile.png")
let the handler deliver the image by an id ("...imagloader?file=4711"),
name of the file (and extension and location) is stored in a database (with the user record?)

How to view images from protected folder with php?

I have a password protected directory (with .htaccess) on my website containing *.jpg files. I dont want that anyone can directly access these .jpgs - but I want to allow a php script to display the *.jpg files. Is something like that possible?
For those who wonder why I want this:
I have a register form where a user can upload a picture and before finishing the registration he can check if the correct picture was uploaded. For the moment, I save the uploaded picture in a temporary directory and if he finishes it, I move the picture to the password protected directory. However, I dont like that in each registration there is a short time of period where the picture is public (e.g. through a search engine). Even worse, when someone does upload a picture but not complete the registration, then the picture will remain forever in the temp directory, unless I delete somehow. But if I set up a cron-job to delete all images in the temporary directory during a specific time, then it would be possible that someones picture will be deleteted if he registers at a unfavourable moment.
h2ooooooo already answered my question in the comments section.
This is the code how it works, in my code I have to replace
<img src='link/to/protectet/picture.jpg'>
with
<img src='image.php'>
and the image.php consist only of
<?
header('Content-Type: image/jpeg');
readfile('link/to/protectet/picture.jpg');
?>
that worked. Thanks.
I am not sure, whether this is what you want to achieve, but I understand that:
There is a group of picture files that are stored in .htaccess password protected folder and only registered and authenticated users can download files directly in that folder.
For a newly registering user there is a timespan, when a session, that uploaded the image is allowed to download the image, but no other session, whether authenticated or not, is allowed to do so.
In order to do so you could probably:
As you need to distinguish temporary images from valid images: storing the former in /temp folder is actually a good idea, as temporary files will never mix up with valid files.
For every session that is trying to register, you could probably name your uploaded image file using session_id() (i.e. $name = session_id() . '.jpg'). Then a simple script (similar to: php, file download) could provide stored image related to current session. This script can be source address for an <img> tag on registration form.
As for abandoned images in /temp - a cron job could get rid of them indeed. By calling mtime() for each file - you can easily omit files that were created too recently - and so they are probably still in use.
The accepted answer by h2ooooooo is great. But, what prevents someone from typing in the url address for image.php and being served the image? (In fact, this is what I tried, and I was unfortunately able to fetch the image even though it's in a password-protected folder.)
It seems we need a way of determining that the request is coming from a page on the same website, or maybe establishing a session variable prior to this call, and checking its existence before serving the image. There are good suggestions for that here: How to check if a request if coming from the same server or different server?
I ended up doing the following (<img src="getUploadFile.php?fname=my.jpg">):
<?
function requestedByTheSameDomain() {
$myDomain = $_SERVER['SCRIPT_URI'];
$requestsSource = $_SERVER['HTTP_REFERER'];
return parse_url($myDomain, PHP_URL_HOST) === parse_url($requestsSource, PHP_URL_HOST);
}
if(requestedByTheSameDomain()) {
$inputArr = array();
if($_SERVER["REQUEST_METHOD"] == 'POST') {
$inputArr = $_POST;
}
else {
$inputArr = $_GET;
}
$fname = $inputArr['fname'];
$path_info = pathinfo($fname);
$ext = $path_info['extension'];
if (in_array($ext, array('jpg','png','gif','jpeg','bmp','tif','tiff'))) {
$type = 'image';
$subType = $ext;
if($ext == 'jpg') $subType = 'jpeg';
if($ext == 'tif') $subType = 'tiff';
if($ext == 'svg') $subType = 'svg+xml';
}
else if(in_array($ext, array('mpg','ogg'))) {
$type = 'audio';
$subType = $ext;
}
else if($ext == 'mp4'){
$type = 'video';
$subType = $ext;
}
else if($ext == 'pdf') {
$type = 'application';
$subType = $ext;
}
header("Content-Type: $type/$subType");
readfile("images/$fname");
}
?>
All that remains is to disable right-click and/or serve it a background-image to render Save-Image-As difficult.

PHP Deleting images

I have an admin system which adds profile pages dynamically - and part of that adds images to a directory. When I add the images they all have the name format like 12_1.jpg, 12_2.jpg, 32_1.jpg, 32_9.jpg where the number before the underscore is the id $cid and the number after the underscore is the image number.
I'm trying to find a way to list the images on the edit-images.php page with an option to delete them (maybe a link next to the image name, or another way that is better).
Here is the code to find the images I need to have the option of deleting:
if ($handle = opendir('../images/company')) {
while (false !== ($entry = readdir($handle))) {
if (substr(basename($entry), 0, 2) == $cid) {
echo $entry . "<br>";
}
}
closedir($handle);
}
How would I go about deleting specified images from here? Any help would be appreciated.
In php you use the unlink function to delete files. Just echo a link to a page that calls a function do to that and pass the image name. Only be sure to check the user input before actually perform deletion.
Why are you scanning the directory for the file? You can check if the file exists and delete it instead. For example:
$files = glob("../images/company/$cid_*.jpg");
foreach($files as $file) {
if(file_exists($file)) unlink($file);
}
This will unlink all files in ../images/company with the name starting with 123_ for example and ending in .jpg (you can provide more extensions by using GLOB_BRACE parameter)

move_uploaded_file() won't replace existing image

I'm using the script below, so user can upload their profile picture. The first time an image is uploaded (when the image doesn't exist at the location) it works great. However, if the image is already exist at the path (if the user tries to change the profile picture) the new image won't replace the old one. I do get success for the query.
Any help would be very appreciated!
Thanks
<?php
ini_set('display_errors',1);
error_reporting(E_ALL);
require_once('db.php');
$name = $_POST['name'];
$dir = '../uploadImages/';
$file = basename($_FILES['image']['name']);
$uploadfile = $dir . $file;
if(move_uploaded_file($_FILES['image']['tmp_name'], $uploadfile))
{
$path = $name;
$path .= 'Image.png';
$query = mysql_query("UPDATE users SET imagePath='$path' WHERE username='$name'");
if ($query)
{
echo 'success';
}
else
{
echo 'error';
}
}
else
{
echo mysql_error();
}
?>
A better way would be un-linking the file if it exists
if(file_exists('your-filename.ext')) {
chmod('your-filename.ext',0755); //Change the file permissions if allowed
unlink('your-filename.ext'); //remove the file
}
move_uploaded_files($_FILES['image']['tmp_name'], 'your-filename.ext');
If move_uploaded_file fails, it returns false. In that case, no SQL is executed at all, so mysql_error, which is echoed in the else branch, indeed won't output an error.
if move_uploaded_file fails, it issues a warning, that will become visible depending on your PHP settings. However, this problem doesn't have anything to do with MySQL.
If you try to explicitly delete the target file first, if it exists. Check with file_exists and then with unlink to delete the file. If unlink fails, it's probably a permissions issue than won't allow you to delete or overwrite the file.
No, your logic is wrong.. take a look at the URL of your profile image, either here, in facebook or twitter..do you see they use a fixed predictable name ? They don't, and there is a very good reason for that, you need unique, unpredictable filenames.
Try this:
$file = hash('sha256', openssl_random_pseudo_bytes(8)) . 'yourallowedextension';
Then query the name of the old picture from your database, after that, upload the new pic, if that succeeds, update the user's profile picture in the database and unlink() the old file using the information previously obtained if any.
Ensure that you are not allowing to upload php files or any other nasty stuff, for that you can use php fileinfo extension.
$file=$_FILES['image']['name'];
$path="your/location/".$file;
if(file_exists($path))
{
chmod($path,0755);
unlink($path);
}
Then move the file using move_uploaded_file().
If you do this, the new image will be replaced:
$sourcePath = $_FILES['image']['tmp_name'];
list($width,$height)=getimagesize($sourcePath);
$uploadedImage = imagecreatefromjpg($sourcePath);
$newImage=imagecreatetruecolor($newWidth,$newHeight);
imagecopyresampled($newImage,$uploadedImage,0,0,0,0,$newWidth,$newHeight,$width,$height);
imagejpeg($newImage, $destinationPath,100);

Categories