Du kan ju med hälp av en .htaccess rewrite se till att alla anrop till dessa filer går genom ett PHP-skript. Sedan kan du skicka filen genom att skicka lite headers och sedan anropa readfile, som skickar innehållet i en angiven fil. Dessa två filer ska alltså ligga i samma katalog där de uppladdade filerna ligger.
Lite sunkig exempelkod som jag har använt:
.htaccess:
RewriteEngine on
RewriteRule ^.*\.(jpg|jpe|jpeg|png|gif|mp3)$ getimg.php?path=$0 [NC]
getimg.php
<?PHP
function error($detail){
header('content-type: text/html');
die(htmlspecialchars($_GET['path']) . "<br>$detail");
}
function dumpfile($imgpath, $filename, $ext){
$mime = "";
switch(strtolower($ext)){
case 'jpg':
case 'jpeg':
case 'jpe':
$mime = 'image/jpeg'; break;
case 'gif':
$mime = 'image/gif'; break;
case 'png':
$mime = 'image/png'; break;
case 'mp3':
$mime = 'audio/mpeg'; break;
default:
//error("Invalid file type");
error("404 File Not Found");
}
if (!file_exists($imgpath))
error("404 File Not Found");
header("Content-Type: ${mime}");
header("Content-Disposition: inline; filename=${filename}.${ext}");
// Add header lines to control the client caching here.
readfile($imgpath);
}
$imgpath = $_GET['path'];
// Parse the enclosed filename
preg_match('/^' . // Start of expr
'([^\\/].*\\/)?' . // 1 Directory (Must be further validated for ..)
'([^\\/]+)\\.' . // 2 Filename body
'([^\\/^.]{2,4})' . // 3 File ext
'$/i' // End of expr
, $imgpath, $matches);
$dir = $matches[1];
$filename = $matches[2];
$ext = $matches[3];
if (false!==strpos($dir, '..')){
error("Invalid path");
}
if ('getimg.php' == $imgpath){
error("403 Forbidden");
}
$allowed = true; // Figure out whether the user is allowed to see the file
if($allowed){
dumpfile($imgpath, $filename, $ext);
}else{
error("403 Forbidden");
}
(Koden ovan är något redigerad för att vara presentabel för allämnheten. Jag ber om ursäkt för eventuella syntaxfel pga redigering.)
Det finns mycket som kan gå fel, t ex:
Felmeddelanden från PHP kommer skickas innan filen och korrumpera innehållet. Lista ut något sätt att hantera detta, eller se till att sriptet aldrig gör några fel. ;)
Du vill inte att tecken ska skrivas ut efter att filen har skickats. Utelämna därför PHP-sluttaggen ?> sä slipper du att det skickas en extra radbrytning av misstag.
Säkerhet: Se till att en man inte kan komma åt andra filer genom att (t ex) anropa skriptet direkt med getimg.php?path=../databasepassword.php eller något. Jag tror att min validering ovan åstadkommer detta, men jag är öppen för förslag om motsatsen.
Säkerhet: Se till att man inte kan ange ett fint filnamn som skrivs ut i felmeddelandet om att filen inte hittas och tillåter skriptkörning, typ:
http://example.com/files/\<script%20src="http://ondsida.se/usch.js">.jpg
Jag tror att htmlspecialchars skyddar mot denna attack, men jag är öppen för förslag om motsatsen.
Säkerhet: Se till att skriptet för att ladda upp filer har skydd som gör att .htaccess och getimg.php inte kan skrivas över. (Dock bör ett sådant filter bara tillåta att ett litet urval av filtyper kan laddas upp, och .php bör ändå inte ingå i den gruppen, men ändå.)
Säkerhet: Notera att det reguljära uttrycket i .htaccess-filen bara matchar vissa filtyper, och t ex en PDF-fil skulle inte gå genom skriptet alls. Du kanske istället borde använda ett uttryck som matchar allt utom getfile.php (för att undvika att regeln skapar en oändlig loop.
Som sagt, om du ska använda en lösning i det här stuket så får du hålla tungan rätt i mun eftersom det är mycket som kan gå fel. :)
Ett bättre system kanske skulle hålla reda på alla filer i en databas och bara tillåta hämtning av filer som finns listade i databasen. Jag gissar dock att du sälv laddar upp filer via FTP, som inloggade användare kan komma åt.

