5

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.

Adam
  • 25,960
  • 22
  • 158
  • 247
  • You could use robots.txt to shield of crawlers from that directory. And you might want to check into deeplinking, might help you a bit. – Martijn Feb 08 '14 at 15:24
  • 5
    PHP doesn't care about your `htaccess` configurations and will contact the file system directly unless you're trying to get files from another server. – h2ooooooo Feb 08 '14 at 15:30
  • @h2ooooooo If I include the picture the user is propted to enter username and passwort for my protected directory. So php. does care about my htaccess, or did I miss your point? – Adam Feb 08 '14 at 15:32
  • Is your php file in the protected folder?? – user2737037 Feb 08 '14 at 15:35
  • *there is a short time of period where the picture is public (e.g. through a search engine)* what search engine are you referring to? – Kuba Wyrostek Feb 08 '14 at 15:37
  • @user2737037 no, the registration form is outside the proteced directory. – Adam Feb 08 '14 at 15:37
  • Your cron-job to delete all images in the temporary directory can leave intact files that were created within designated session timespan (i.e. last 20 minutes). – Kuba Wyrostek Feb 08 '14 at 15:38
  • @KubaWyrostek I just mean that it possible for everyone to see the picture. Since no one has the link to picture I tried to say that it still can be found. I did not had any specific search engine in mind – Adam Feb 08 '14 at 15:39
  • Do you use sessions (i mean `start_session()` etc)? – Kuba Wyrostek Feb 08 '14 at 15:40
  • @KubaWyrostek yes I do use sessions – Adam Feb 08 '14 at 15:42
  • 2
    @Adam How are you "including the picture"? The correct way would be to spurt out an image header and use `readfile()` to show it. Are you just printing out ``? If so, it has nothing to do with PHP. The browser reads the `img` tag, and requests the image automatically. – h2ooooooo Feb 08 '14 at 15:50
  • PHP operates at the file system. It isn't bound by webserver-level restrictions and can access files anywhere on the file system that the webserver's user account can reach. – Marc B Feb 08 '14 at 15:53

3 Answers3

11

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.

Adam
  • 25,960
  • 22
  • 158
  • 247
0

I am not sure, whether this is what you want to achieve, but I understand that:

  1. 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.

  2. 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:

  1. 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.

  2. 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.

  3. 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.

Community
  • 1
  • 1
Kuba Wyrostek
  • 6,163
  • 1
  • 22
  • 40
0

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.

  • You are right that one should think about how to prevent other people from also getting the image, but this was not in the scope of the OP. – Adam Dec 15 '17 at 12:27