PHP Sessions and .htaccess

I have a section of a website that is password protected for members only and I use PHP sessions to keep the connection alive between pages. While logged in they have access to a series of internal links to a subdirectory of html files that pop into a new window… however this directory it is not protected. … unless you know the exact URL, you pretty much cant find it… but I am concerned that people are copying the link and sending it to other people who are not subscribers.

Is it possible to setup some sort of .htaccess on a certain directory, in which the user would be prompted for a username and password unless they were already logged in? Meaning is it possible to pass a PHP session username and password to a .htaccess-protected directory? If they are logged in already they see the page/directory, if they are not logged in they get the .htaccess prompt.

Is there a way to do this or can someone recommend a better method of handling this?

it propably seems simple…but if you just turn the html files that need protection into php then problem solved right? or are you trying to keep the server load-free by having these ones as html?

no they are Microsoft Publisher files so they need to be .htm. Unless someone knows more about Publisher than me

An important point to note here is that PHP is server-side, as you may well know, meaning it can access any file available on the domain we’re looking at without regard for the HTTP-Authentication.

PHP cannot pass HTTP-Authentication credentials from outside the server, i.e. from the client-side, back to the server. As the server will expect the HTTP-Authentication info to come from an HTTP header (say, a GET header), from the requesting client, this hindrance eliminates any way I know of to solve this problem directly.

Two ways I can think of to solve this:

A) Have PHP alter the .htaccess file in the HTTP-Authenticated folder (‘secure’ folder) before a PHP-session-Authenticated user tries to access the secure folder. You may have to do something along the lines of:


IF USER LOGGED IN:
  OPEN .htaccess FILE
  REMOVE AUTHENTICATION LINE //usually "require valid-user"
ELSE:
  OPEN .htaccess FILE
  RESTORE .htaccess FILE'S ORIGINAL CONTENTS WITH THE AUTHENTICATION LINE INTACT

This is a simple one methinks. It’s sloppy and insecure, however, as the secure folder is available to the public every time a PHP-session-Authenticated user is logged in.

B) Let PHP open the HTML files and output their contents to the client. You may have to change your internal links so that the they point to the new script instead of the HTML files themselves.

For example, instead of a link to /secure/1.html you can have a link to fileget.php?file=/secure/1.html

fileget.php can then:


<?php
  //check if user is authenticated
  if(!is_user_logged_in()) {
      //boot the sucka, or do what you do here :)
  }

  //open the file and read its contents
  $fileName = $_GET['file'];

  $file = fopen( $fileName, 'r' );
  $fileContents = '';
  while( !feof( $file ) ) {
     $fileContents .= fread($theFile, 1024 * 1024);
  }
  fclose($file);


  //output the file contents
  echo $fileContents;
?>

Obviously you got to worry about CSS and Javascript linked files in here. If your HTML files have absolute links to these guys, then I think you’re fine. With relative links you may have to do some regex work in your fileget.php to handle that.

Note: You will likely have to do some verification on the $file URL parameter you’re getting, as the user can do a ‘URL hijack’ to open any of your files that PHP has access to!!!

Well, that;s what I could come up with, so I hope that helps.
If you’re interested in the A) solution at all, I have a PHP script that does just that on my local machine so I can pass that to you.

Peace,
/m

Thanks, does anyone have any other suggestions?

http://php.net/features.http-auth

What if you create a php controller file, and you pass the html requested to it via url so the pop up would request the php file with the html file in the query.

The php file can check for valid session so it’s easy to protect it.

And then to protect the html files from direct access - just use .htaccess to deny it.

wonshikee, like mashour posted above? Would this work for .PDF’s?

method b sounds like the best way to go - it would work with any type of file - use the php script to access the download file instead of linking to it directly.

You could move the files above the web root to prevent direct linking as well.

ok I think I finally have my head wrapped around this. everything is going off the root directory and I am going to use PHP to open the HTML and PDF’s.

One question – The pdf is opening as encoded text in the browser instead of as as PDF all encoded. Here is the PHP script:


  $fileName = "protected/test.pdf";

  $file = fopen( $fileName, 'r' );

  $fileContents = '';

  while( !feof( $file ) ) {

     $fileContents .= fread($file, 1024 * 1024);

  }

  fclose($file);

  echo $fileContents;

Here is what it is outputting the PDF as:

��o�6���$e�h�@��H5J���<��.A�&]y�hW��’ �K���V׫ �s�Mg2 Z�?%h^�4OCTv��Y�J���f��8韃�Q^��oq�eT��O�%%��o���_�Tx�����PC; �z�6��3�900�Je endstream endobj 446 0 obj <<>/Size 395/Type/XRef>>stream x�bbf`b``Ń3� ���ţ�A���9 endstream endobj 396 0 obj <> endobj 397 0 obj <<>/ViewerPreferences<>/Metadata 26 0 R/PieceInfo<<>>>/Pages 25 0 R/PageLayout/OneColumn/StructTreeRoot 28 0 R/Type/Catalog/LastModified(��i�d:�;�m�C)/PageLabels 23 0 R>> endobj 398 0 �!7so&�>N6 ���쥙�8�E�a��C5��K"����!�����@�x8��Sb�c�a�XgL�abxe}�ӕ�G"ͅEH��C� a���\��7_�R�H7�&�7��Ѩm�7*Hj��6�ijN��b#& etc., etc., etc…

The garbled pdf may be caused because by default PHP sends the content with an HTTP header for HTML. You may need to use:

header(“Content-type: application/pdf”);

There seem to be other considerations when sending pdfs, but I haven’t worked with them in PHP or HTTP so I don’t know them all.

Hope that helps.

You can use [fphp]readfile[/fphp], instead of all those operations.

I have a download service where I want only my members to be able to download the files.

I have a PHP file download.php that is given the information for the file location indirectly. So instead of doing download.php?id=/media/videos/1/2.avi I would pass it though seperate variables type=3&group=1&id=2.

A further layer is using htaccess to hide this whole process, so I can make a link to download/3/1/2. htaccess will translate this to downloads.php?type=3&group=1&id=2.

In the PHP file itself, you can do checking that the user has the correct permissions, then if they do output the file using headers.

Content-type header will fix your output problem.

// $fileName = "protected/test.html";
$fileName = "protected/test.pdf";

$pieces = explode('.', $fileName);

if($pieces[1]  == "pdf"){
header("Content-type: application/pdf");
}

readfile($fileName);

To hide my files, what server directory is best to store them in?

below the web root if you can / or is it above… I always get that confused.

But basically you have something like a “/public_html/” or “/www/” folder, if you move the files to a new folder called “/files/” or something, the only way those files can be accessed is by download.php, they can’t be browsed directly because they are not published publically. Use the absolute path from the server.

cool, i figured as much-- but there are always best pratices and stuff that I always mess up so i figured I’d ask

I can’t get this to work, I moved the files to a secure directory outside the www root. I am getting a blank page, no error, no page.

I called my virtual dedicated host and got the absolute path, but this looks like a relative path, no?

 $fileName = "/var/www/vhosts/website.com/protected/test.pdf";

$pieces = explode('.', $fileName);

if($pieces[1]  == "pdf"){
header("Content-type: application/pdf");
}

readfile($fileName);

that path is an absolute path for sure. I trust you changed website.com with your domain name?

try and break up your code with some output to try and work out what is happening. For example:


echo 'this file was loaded properly';

$fileName = "/var/www/vhosts/website.com/protected/test.pdf";

$pieces = explode('.', $fileName);

print_r($pieces);

if($pieces[1]  == "pdf")
{
  header("Content-type: application/pdf");  
  readfile($fileName); // check the manual to see what readfile returns in the event of an error... maybe you could use if (readfile...) else 'an error';
} else {
  echo 'piece 1 is not pdf';
}

then work backwords - you might get a header already sent error because theres output, but you might see why the file is not being read. BTW, how are you accessing the file if it is below the web root? testing locally or including in a publically accessible file?