ThisCalculator

Everyday

Restrict Direct Video Access with PHP: What You Can’t Hide

Updated · Standard formula, shown below

Restrict Direct Video Access with PHP: What You Can't Hide

This guide shows you how to stop people from hotlinking or directly downloading your video files via a raw URL, using PHP as a gatekeeper. You’ll learn to serve videos only after a PHP script checks the user’s session or permissions, and you’ll also understand the hard limits of this approach—what you can and cannot hide from a determined user. No prior PHP experience is needed, but basic familiarity with file paths and web servers helps.

What You’ll Need

  • A web server with PHP installed (Apache, Nginx, or IIS).
  • Access to your server’s file system (to place files outside the web root).
  • A basic text editor to write PHP code.
  • An existing video file (e.g., MP4) you want to protect.
  • Optional: a database or session system if you need per-user access control.

Step-by-Step

  1. Place your video outside the web root. The web root is the folder your server publicly serves (often public_html or htdocs). Move your video to a directory above it, like /home/user/videos/ on Linux or C:\secure_videos\ on Windows. This way, the video URL is not directly accessible at all.
  2. Create a PHP script that acts as a gatekeeper. Name it something like stream.php and place it in your web root. This script will check if the user is allowed to see the video, and if so, stream it to the browser.
  3. Start the script with a session check. Use session_start() and verify that the user is logged in or has a valid token. For example:
    <?php
    session_start();
    if (!isset($_SESSION['user_id'])) {
        http_response_code(403);
        die('Access denied');
    }
    ?>
        
  4. Get the video filename from a query parameter. Use $_GET['file'] to know which video to serve. Be careful: validate the input to avoid path traversal attacks. Only allow alphanumeric characters, dash, and underscore, and map it to a real file path.
    $allowed = preg_replace('/[^a-zA-Z0-9_-]/', '', $_GET['file']);
    $video_path = '/home/user/videos/' . $allowed . '.mp4';
        
  5. Check that the file exists and is readable. Use file_exists() and is_readable(). If not, return a 404 error.
  6. Set the correct HTTP headers. Before sending the file, tell the browser what kind of file it is and how to handle it. For a video, use Content-Type: video/mp4 and Content-Length for the file size. Also set Content-Disposition: inline to play in the browser, or attachment to force download (but you usually want inline).
  7. Stream the file in chunks. Use readfile() for small files, but for large videos, it’s better to read and output in chunks to avoid memory issues. A simple loop with fread() works:
    $handle = fopen($video_path, 'rb');
    while (!feof($handle)) {
        echo fread($handle, 8192);
        ob_flush();
        flush();
    }
    fclose($handle);
        
  8. Handle HTTP Range requests for seeking. Browsers and video players send Range headers to seek to a specific part of the video. If you ignore this, users can’t skip ahead. Implement basic range support by checking $_SERVER['HTTP_RANGE'] and sending 206 Partial Content with the appropriate byte range. This is complex but essential for a good user experience.
  9. Update your video links. In your HTML, instead of linking directly to the video file, link to your PHP script like <video src="stream.php?file=myvideo">.

Common Mistakes

  • Forgetting to move the video outside the web root. If the video remains in a public folder, anyone can guess or find the URL and bypass your PHP script entirely.
  • Not validating the file parameter. This can lead to directory traversal attacks, allowing users to read arbitrary files on your server.
  • Ignoring HTTP Range requests. Without them, video seeking may fail or cause the entire file to download every time, which is slow and wastes bandwidth.
  • Using readfile() on huge files. This can exhaust PHP’s memory limit. Always stream in chunks for large videos.

Tips

  • Use a token or signed URL for temporary access. Generate a link with an expiry timestamp and a hash, then validate it in your PHP script. This prevents users from sharing permanent links.
  • Set a Content-Disposition header to ‘inline’ to encourage playback rather than download.
  • Consider using a CDN or a dedicated video hosting service if you need scale and robust security features like DRM. PHP alone is not designed for high-traffic video streaming.
  • Cache the file’s last-modified time and send Last-Modified and ETag headers to improve caching and reduce server load.

Troubleshooting

Video doesn’t play at all: Check that your PHP script outputs the correct Content-Type header and that the file path is correct. Also, ensure you are not outputting any extra whitespace or characters before the video data.

Seeking doesn’t work: Your script probably doesn’t handle Range requests. Implement basic range support as described in step 8. Test with a tool like curl to see the headers.

Users can still access the video directly: Double-check that the video file is truly outside the web root. Try accessing the direct URL in a browser—if it loads, move the file.

PHP memory exhausted: Use chunked streaming instead of readfile(). Increase memory limit as a temporary fix, but streaming is the right solution.

403 errors for logged-in users: Your session check may be failing. Ensure session_start() is called before any output, and that the session variable is being set correctly during login.

Frequently Asked Questions

Can I completely hide the video file from the user?

No. The user’s browser must receive the video data to play it, so a determined user can always capture the stream or inspect network traffic to extract the file. PHP can only make it harder, not impossible.

Does this prevent hotlinking from other websites?

Yes, if your PHP script checks the HTTP Referer header, you can block requests from other domains. However, Referer can be spoofed, so it’s not a strong security measure.

Is this method suitable for a large video library?

It can work, but PHP is not optimized for high-concurrency video streaming. For large-scale or commercial use, consider a dedicated streaming server or CDN with token authentication.

Can I use this for audio files too?

Yes, the same technique works for any file type, just change the Content-Type header accordingly (e.g., audio/mpeg for MP3).

What about DRM (Digital Rights Management)?

PHP cannot provide DRM. DRM requires specialized technologies like Widevine or FairPlay, which are typically integrated into video players and streaming platforms. PHP only controls access, not encryption.

Do I need to worry about the video being downloaded from the browser’s cache?

Yes, browsers may cache the video. You can set Cache-Control: no-store to discourage caching, but it’s not foolproof. A determined user can still save the file from the network tab.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.