3

So I need a little help with a php script I am writing that loads a PDF in a new tab through a PHP script. I am doing it this way to make sure that the PDF can only be accessed if the user is logged in and has a link to it, otherwise the .htaccess in the parent directory to the PDF blocks access.
I am able to read from the PDF using the code below:

$file = '../path-to-file.pdf';
$filename = 'filename.pdf';
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
@readfile($file);

The result of this is then passed into an AJAX function shown below which generates a new tab and throws the response onto it:

$.ajax({
    url: '../includes/function.projects.php?view-media=' + item,
        success: function(data) {
            $(window.open().document.body).html(data);
        }
    })

This all works smoothly, it's only when the new tab opens, because I am writing the response straight to the documents HTML, I am getting a screen full of text like this:

%PDF-1.5 %���� 2 0 obj << /Linearized 1 /L 17007 /H [ 687 126 ] /O 6 /E 16732 /N 1 /T 16731 >>

So my question is quite simply this; Has anyone tried managed to do this before? If so, are there any libraries I should be using/headers I'm missing etc

I have already seen this question here but I cannot get the answers people are listing to work so I am out of ideas.

Any help would be greatly appreciated, Thanks in advance!

6
  • 3
    This is only a guess, though I have done similar things to secure images. I don't think you can simply pass the data like that through window.open.document.body because you're not sending any headers with it. Why not just pop open a window with your function.projects.php?view-media=' + item as the url and do a security check at the top of it? Commented Jun 11, 2018 at 20:31
  • hm... though look at this: stackoverflow.com/questions/10516463/… Commented Jun 11, 2018 at 20:35
  • Thats a good idea! I already have a function written to check the session so that would be nice and easy to implement. Another way I have just started to look into was to load a pre-built page that passes the url of the PDF through a GET variable and then a JS library takes over to grab it and load the PDF onto the page...I like your idea better though :) Commented Jun 11, 2018 at 20:36
  • Good luck! Check out that other link though - perhaps all you need is to convert it to binary and prepend your string with data:application/pdf;base64, and your current plan will work. Commented Jun 11, 2018 at 20:38
  • 1
    Yup will do mate, I'll keep tinkering and then as soon as I have something that works smoothly I'll add it as an answer Commented Jun 11, 2018 at 20:40

1 Answer 1

3

Right so I have a solution. If someone can come up with a better way of doing this, please let me know but for now this works perfectly! I found a JS library called PDFObject which can be used to make a cross-browser solution for easily embedding PDFs into a html document. With this, I can pass in a PDF link on the server along with a target div for it to embed into (which in my case I have setup inside of a modal so we stay on the same page).

Because we are staying on the same page, I can block access to the entire page using a function I had written previously in the project which redirects the user to the index if they don't have the right access level. Something along the lines of this would work:

function checkSession() {
    if(empty($_SESSION)) {
        header("Location: /?cheeky_monkey");
    }
}

If the user tried to access the PDF directly, then this code in the htaccess blocks them. It only allows access if being targeted through the application:

SetEnvIf Referer "localhost" is_local_referer
<FilesMatch "\.pdf$">
    Require env is_local_referer
</FilesMatch>

With that out the way, all that needs to happen is to throw a URL at the script tag to load when a PDF is clicked on, accomplished through this sequence of code:

  1. First we need to grab the URL for the PDF (you might be able to skip this step)

To begin with, this javascript is called whenever someone clicks to view a PDF (this call is simply nested as an onclick attribute):

function viewMedia(projectID, type, item) {
    $.ajax({
        url: '../includes/function.projects.php?cid=' + projectID + '&type=' + type + '&view-media=' + item,
        success: function(data) {
            $('.pdf-script').html('<script>PDFObject.embed("' + data + '", "#the-pdf");</script>');
            $('#viewMediaModal').modal('toggle');
        }
    })
}

This is the code that is ran on the php page.

public function viewMedia($item) {
    $mediaItems = unserialize($this->media);
    $file = '/path/to/pdf/' . $mediaItems[$item]['file'];
    echo $file;
}

An example of the returned data from this function:

/path/to/pdf/example-pdf.pdf
  1. Using this to load the PDF

Once we have the correct URL for the PDF and the AJAX returns as successful, the data received back can be used to re-generate the javascript, this time with the new PDF link:

success: function(data) {
    $('.pdf-script').html('<script>PDFObject.embed("' + data + '", "#the-pdf");</script>');
    $('#viewMediaModal').modal('toggle');
}

This is what the structure of that modal body looks like:

<div class="modal-body">
    <div id="the-pdf"></div>
    <div class="pdf-script" style="display: none;">
        <script>PDFObject.embed('', '#the-pdf');</script>
    </div>
</div>
  1. The result

The result of the above code sequence toggles a modal that look like the below:

enter image description here

And if the user tries to access the file directly:

enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

Wow - that's really great. Thanks for sharing this.
No worries! :))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.