PHP网站禁止PDF文件直接访问的实现方案问询
Hey there, let's fix that direct PDF URL access issue you're dealing with. Since your PHP site already uses account-based login, we can tie into that existing authentication system to lock down PDF access. Here are three reliable methods you can implement:
1. Use a PHP Proxy Script (Most Common & Flexible)
This is the go-to approach because it fully leverages your existing login checks. The idea is to move your PDF files outside the web root directory (so they can't be accessed directly via URL) and use a PHP script to serve them only to logged-in users.
Steps:
- Move your PDF storage folder to a location not accessible via the web, e.g.,
/var/www/private_pdfs/(instead of/var/www/html/pdf/which is public). - Create a PHP script (e.g.,
view_pdf.php) that handles the request:- First, validate that the user is logged in using your site's existing session logic (check for a valid user ID in
$_SESSION, for example). - If the user is authenticated, fetch the requested PDF file, set the correct HTTP headers, and output the file content.
- If not authenticated, redirect to your login page or return a 403 Forbidden error.
- First, validate that the user is logged in using your site's existing session logic (check for a valid user ID in
Example Code:
<?php // Start session (make sure this matches your site's session setup) session_start(); // Check if user is logged in (adjust this to your site's auth check) if (!isset($_SESSION['user_id']) || empty($_SESSION['user_id'])) { header("Location: login.php"); exit; } // Define path to private PDF storage $private_dir = '/var/www/private_pdfs/'; $filename = $_GET['file'] ?? ''; // Sanitize filename to prevent directory traversal attacks $safe_filename = basename($filename); $file_path = $private_dir . $safe_filename; // Check if file exists and is a valid PDF if (!file_exists($file_path) || mime_content_type($file_path) !== 'application/pdf') { header("HTTP/1.1 404 Not Found"); exit; } // Set headers to display PDF in browser/iframe header("Content-Type: application/pdf"); header("Content-Disposition: inline; filename=\"$safe_filename\""); header("Content-Length: " . filesize($file_path)); // Output the file (use readfile for better memory handling with large PDFs) readfile($file_path); exit;
Update Your Iframe:
Change your iframe source to point to the proxy script instead of the direct PDF URL:
<iframe src="view_pdf.php?file=test.pdf" width="100%" height="600px"></iframe>
2. Restrict Access via Web Server Configuration (Apache/Nginx)
If you prefer to handle access at the server level, you can configure Apache or Nginx to redirect all PDF requests to your auth-checking script, or block direct access entirely unless the request comes from your authenticated users.
For Apache (using .htaccess):
Add this to a .htaccess file in your public PDF directory (though moving files outside web root is still safer):
RewriteEngine On # Redirect all PDF requests to view_pdf.php RewriteRule ^(.*\.pdf)$ view_pdf.php?file=$1 [L]
For Nginx:
Add this to your server block configuration:
location ~* \.pdf$ { # Redirect PDF requests to the proxy script rewrite ^/(.*\.pdf)$ /view_pdf.php?file=$1 last; }
Note: This still relies on your view_pdf.php script to handle authentication checks—this config just ensures no direct PDF URLs work.
3. Generate Time-Limited, Signed URLs
For an extra layer of security (especially if you want to restrict access to specific users or timeframes), generate signed, expiring URLs for PDFs. This way, even if someone gets the URL, it will stop working after a set time or if the signature is tampered with.
Basic Implementation:
- When a user requests to view a PDF, generate a URL with an expiration timestamp and a HMAC signature (using a secret key only your server knows).
- In
view_pdf.php, verify the signature matches the provided parameters and that the timestamp hasn't expired, along with checking the user's login status.
Example Signature Generation:
<?php $secret_key = 'your_strong_secret_key_here'; $filename = 'test.pdf'; $expires = time() + 3600; // 1 hour from now // Create signature $signature = hash_hmac('sha256', $filename . $expires, $secret_key); // Generate the URL $pdf_url = "view_pdf.php?file=$filename&expires=$expires&signature=$signature";
Verification in view_pdf.php:
Add this after the login check:
$expected_signature = hash_hmac('sha256', $_GET['file'] . $_GET['expires'], $secret_key); if ($_GET['signature'] !== $expected_signature || $_GET['expires'] < time()) { header("HTTP/1.1 403 Forbidden"); exit; }
Important Additional Checks
- File Upload Validation: When users upload PDFs, always verify the file is actually a PDF (check MIME type, file extension, and optionally scan the file content) to prevent malicious uploads.
- Directory Traversal Protection: Always sanitize filenames (like using
basename()in the proxy script) to stop attackers from accessing files outside your intended storage directory. - Memory Handling: Use
readfile()instead offile_get_contents()for large PDFs to avoid memory issues.
内容的提问来源于stack exchange,提问作者Howard Yang

