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.
Related
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?)
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.
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);
I have searched far and wide on this one, but haven't really found a solution.
Got a client that wants music on their site (yea yea, I know..). The flash player grabs the single file called song.mp3 and plays it.
Well, I am trying to get functionality as to be able to have the client upload their own new song if they ever want to change it.
So basically, the script needs to allow them to upload the file, THEN overwrite the old file with the new one. Basically, making sure the filename of song.mp3 stays intact.
I am thinking I will need to use PHP to
1) upload the file
2) delete the original song.mp3
3) rename the new file upload to song.mp3
Does that seem right? Or is there a simpler way of doing this? Thanks in advance!
EDIT: I impimented UPLOADIFY and am able to use
'onAllComplete' : function(event,data) {
alert(data.filesUploaded + ' files uploaded successfully!');
}
I am just not sure how to point THAT to a PHP file....
'onAllComplete' : function() {
'aphpfile.php'
}
???? lol
a standard form will suffice for the upload just remember to include the mime in the form. then you can use $_FILES[''] to reference the file.
then you can check for the filename provided and see if it exists in the file system using file_exists() check for the file name OR if you don't need to keep the old file, you can use perform the file move and overwrite the old one with the new from the temporary directory
<?PHP
// this assumes that the upload form calls the form file field "myupload"
$name = $_FILES['myupload']['name'];
$type = $_FILES['myupload']['type'];
$size = $_FILES['myupload']['size'];
$tmp = $_FILES['myupload']['tmp_name'];
$error = $_FILES['myupload']['error'];
$savepath = '/yourserverpath/';
$filelocation = $svaepath.$name.".".$type;
// This won't upload if there was an error or if the file exists, hence the check
if (!file_exists($filelocation) && $error == 0) {
// echo "The file $filename exists";
// This will overwrite even if the file exists
move_uploaded_file($tmp, $filelocation);
}
// OR just leave out the "file_exists()" and check for the error,
// an if statement either way
?>
try this piece of code for upload and replace file
if(file_exists($newfilename)){
unlink($newfilename);
}
move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $newfilename);
I'm currently building a very low level CMS for friend's artist web page that will allow her to upload, edit, and delete images along with designating categories for them and posting news posts about shows and so on.
I'm sure there is a very easy solution to this problem of mine but my inexperience in programming has me left at a loss; so here goes.
The Problem
The problem occurs on a page where the user can delete an image that has been uploaded. Here is the snippet of code where the problem occurs:
// Assign selection to variables in memory...
$img_id = $data["img_name"];
// First, collect the file path to the image being deleted...
$rs = mysql_query("SELECT img_path FROM img_uploads WHERE img_id = '$img_id'") or die(mysql_error());
list($img_path) = mysql_fetch_row($rs);
// Then delete that row from the DB...
mysql_query("DELETE FROM img_uploads WHERE img_id = '$img_id'") or die(mysql_error());
// Now, using the file path collected earlier, delete that file from the server.
unlink($img_path);
// Quickly make sure that the file has been deleted by checking if it exists... if it still exists return error.
if(file_exists($filename)) {
$err[] = "ERROR - There was an error deleting the file! Please try again.";
$_SESSION["errors"] = $err;
header("Location: img_del.php?doDel=failed");
exit();
}
// Scan the directory now that a file has been deleted to see if the dir is empty. If so, delete it. (No use in having empty folders!)
$file_types = array("gif","jpg","png"); // file types to scan for...
$path_parts = pathinfo($img_path); // get the directory from the file path...
$dir = $path_parts["dirname"] . "/"; // assign it to a new variable...
$handle = opendir($dir);
$scan = scandir($dir); // now, scan that directory...
$image_found = FALSE;
for($i=0; $i<count($scan); $i++) {
if ($scan[$i] != '.' && $scan[$i] != '..' && in_array(end(explode('.', $scan[$i])), $file_types)) {
$image_found = TRUE;
}
}
closedir($handle);
if(!$image_found) {
rmdir($dir);
}
I first delete the DB row containing image info, then delete the file from the server. this works fine, however, I also want to check if the directory is left empty after deleting that file. I check if the directory is empty using a loop and if no file is found, I run mkdir(). For some reason it keeps returning an error saying that the directory is not empty
I've searched the web and this site for a solution but I've yet to find one. I'm sure it's out there but I'm having trouble finding it which why I came here. What should I do?
Thanks in advance for any help submitted!
NOTE
I have also checked for hidden files and folders but no luck...
Here is a link to an image that pretty much sums up my problem in a nutshell
Are you sure PHP has permission to delete the file? Since you say you've checked for hidden files, this seems to be the only remaining option. CHMOD 0777 when in doubt (I'd never recommend this usually, but if you're deleting it anyway...), and make sure the folder has the proper owner to let php delete it.