Manchmal liegen Mediendateien auf einem Server, der nicht direkt öffentlich erreichbar ist — oder der Zugriff soll auf authentifizierte Nutzer beschränkt werden. Ein PHP-Streaming-Proxy löst beide Probleme elegant.

Grundprinzip

Der Proxy öffnet die Datei (lokal oder per SSH/SCP auf einem entfernten Host), prüft Berechtigungen und streamt sie mit korrekten HTTP-Headern zum Browser. Der Nutzer sieht nur die öffentliche Proxy-URL — keine internen Pfade.

<?php
// Sicherheits-Checks zuerst
if (!isLoggedIn()) { http_response_code(403); exit; }

$file = basename($_GET["f"] ?? "");
$allowed_dir = "/var/media/audio/";
$full_path = $allowed_dir . $file;

// Path-Traversal verhindern
if (strpos(realpath($full_path), realpath($allowed_dir)) !== 0) {
    http_response_code(403); exit;
}
if (!file_exists($full_path)) { http_response_code(404); exit; }

// MIME-Typ bestimmen
$mime_map = ["mp3" => "audio/mpeg", "flac" => "audio/flac", "ogg" => "audio/ogg"];
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
$mime = $mime_map[$ext] ?? "application/octet-stream";

// Streaming-Header
header("Content-Type: $mime");
header("Content-Length: " . filesize($full_path));
header("Accept-Ranges: bytes");
header("X-Accel-Buffering: no");  // nginx buffering deaktivieren
header("Cache-Control: no-cache");

// Datei streamen
readfile($full_path);

Remote-Dateien via SSH streamen

Wenn die Mediendateien auf einem anderen Server liegen, kann PHP via popen() und SSH die Datei direkt durchleiten — ohne sie lokal zwischenzuspeichern:

$ssh_key  = "/pfad/zum/ssh-key";
$ssh_user = "media-user";
$ssh_host = "media-server";
$remote   = escapeshellarg("/media/" . $file);

$cmd = "ssh -i $ssh_key -o StrictHostKeyChecking=no "
     . "-o BatchMode=yes $ssh_user@$ssh_host cat $remote";

header("Content-Type: audio/mpeg");
header("X-Accel-Buffering: no");

$handle = popen($cmd, "r");
while (!feof($handle)) {
    echo fread($handle, 65536);
    flush();
}
pclose($handle);

Sicherheitshinweise

  • Immer basename() auf Benutzereingaben anwenden und gegen ein Whitelist-Verzeichnis prüfen
  • SSH-Key ohne Passphrase + command=-Restriction in authorized_keys nutzen (nur cat erlaubt)
  • Dateigröße für Content-Length nur setzen wenn bekannt — sonst weglassen (chunked transfer)
  • Rate-Limiting auf die Proxy-URL einrichten um Bandbreiten-Missbrauch zu verhindern