1

I was wondering if someone could help me on how to approach this problem. For example lets say I have a index.php page where in which a user must login to gain access to home.php where in which they can click a link to a pdf document which opens up in their browser.

HTML link

<a href="example.pdf">example</a>

How can I stop a user who isn't logged in from searching for the pdf document and opening it without logging in. i.e www.exampledomain.com/example.pdf

I would like to know how to block access to the directory, I am not sure if i need to change the way in which I link the pdf to the page or if need to change or add something else.

marcus
  • 63
  • 1
  • 9
  • You simply __cannot__. – u_mulder Oct 13 '19 at 08:52
  • @u_mulder What do you mean, are you saying that it is impossible. is any other way/method which I can achieve the same result – marcus Oct 13 '19 at 09:05
  • @MasoudKeshavarz It's not a duplicate as that thread explains how to block/allow access to page content, while i am asking how to block/allow access to a directory. – marcus Oct 13 '19 at 09:06
  • If you say so. Maybe this link could help you: https://stackoverflow.com/questions/6455678/can-i-restrict-web-folder-access-to-only-logged-in-users-of-my-website – Masoud Keshavarz Oct 13 '19 at 09:09
  • @MasoudKeshavarz that doesn't help me as i don't want to add a download page/link for the file. – marcus Oct 13 '19 at 09:13

2 Answers2

0

Regarding directory I am not sure about so will not say that it is impossible. But if the files are static or may be dynamic, and you can store it in the database as blob and code it access to logged in users only.

Regarding directory access there may be some htaccess tricks that I am not aware about.

  • Yea I was trying to use htaccess but I was stuck on trying to verify from php if the user was logged in. I know I can use a blob in a database but I was trying to use the file system if i could but if it is impossible i will just use a blob. – marcus Oct 13 '19 at 09:36
0

As I understand it, what you want to do is stop the situation where a link to a PDF is accessed by an unauthenticated user. This is typically done by serving the PDF file via a script.

The PDF files should be stored in a directory outside the public web root, however if you do this, make sure your script doesn't take an unsanitized path from user input and use it to load the PDF file.

Your script should ideally take a parameter such as ?file_id=123. The script would first check the user has a valid session, and then the file_id would be used to look up the PDF file and stream it to the user. Here's a description of how to stream a file using PHP: https://stackoverflow.com/a/16847068/366965

Here is one way it can be done in PHP:

<?php

if (!empty($_GET) && !isset($_GET['pdf'])) {
    echo "No PDF";
} else {

    $pdfId = $_GET['pdf'];

    // Here you should retrieve the filename by pdfId
    //$pdfFilePath = sprintf("../pdf/%s.pdf", $retrievedFileName);
    $pdfFilePath = "../pdf/dummy.pdf";

    if (file_exists($pdfFilePath)) {
        header('Content-Description: File Transfer');
        header("Content-type: application/octet-stream");
        header("Content-disposition: attachment;filename=" . basename($pdfFilePath));
        header('Content-Length: ' . filesize($pdfFilePath));
        readfile($pdfFilePath);
        exit;
    } else {
        echo "File did not exist";
    }
}

An extension to this is to use mod_rewrite (or similar) to redirect requests to .pdf to your script - see https://stackoverflow.com/a/10453158/366965 for details.

This is one way it can be done in an .htaccess file:

<IfModule mod_rewrite.c>
   Options +FollowSymLinks
   Options +Indexes
   RewriteEngine On

   # only if not an actual file exist
   RewriteCond %{REQUEST_FILENAME} !-f

   # only if not an actual directory exist
   RewriteCond %{REQUEST_FILENAME} !-d

   RewriteRule (.+)\.pdf index.php?pdf=$1 [NC,L]
</IfModule>

I added a demo project which achieves what you want: https://github.com/joe-niland/docker-apache-php-pdf

Joe Niland
  • 885
  • 1
  • 14
  • 31
  • Thank you so much I have added the stream for the user, but I am not sure how I access a file outside public_html, I tried to put the pdf document in a folder within a public_html then add a htaccess file which blocks directory access, but when the file downloads it says its corrupted. – marcus Oct 13 '19 at 12:49
  • Can you post your .htaccess in your question? Did you add the required headers before outputting the file data? If you open the downloaded file in a text editor, what are the contents? – Joe Niland Oct 13 '19 at 13:01
  • here is the paste bin, the formatting of code in comments was not working. https://pastebin.com/zspv4r7M – marcus Oct 13 '19 at 13:19
  • there's no link. You can just edit your question to add these. – Joe Niland Oct 13 '19 at 13:26
  • https://pastebin.com/Lg6kz1p9 try this link, it wont let me edit the comment, because it has disappeared, i think because i edited too much. – marcus Oct 13 '19 at 13:29
  • Hey Joe, I tried your code on my website, but I got the same problem where it says it is corrupted, so I download the file from your github to test on localhost to see if that works but I still get a message saying the file is corrupted. – marcus Oct 14 '19 at 04:42
  • Don't Worry Joe i fixed it, i had to add flush() and ob_clean() before i read the pdf, but now it works thank you so much for your help!! – marcus Oct 14 '19 at 05:10
  • You're welcome. So it sounds like you had some output already, before outputting the PDF contents. ob_clean() will discard the previous output. – Joe Niland Oct 14 '19 at 05:20