2010-06-09 11 views
6

Mam plik php, który działa jako strażnik dla wszystkich plików, które chcę, aby ludzie pobierać, którzy mają wystarczającą ilość uprawnień.Jak zezwolić użytkownikom z wymaganymi uprawnieniami na pobranie pliku przez php?

Kod używam wrzucić plik do użytkownika jest

header('Content-Description: File Transfer'); 
header('Content-Type: application/octet-stream'); 
header("Content-disposition: attachment; filename=\"".$public_filename."\""); 
header("Content-Transfer-Encoding: Binary"); 
header('Expires: 0'); 
header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
header('Pragma: public'); 
header("Content-length: ".$f_filesize); 
readfile($file_path); 

Większość plików są dość duże .... 400mb-10GB.

Jaki byłby dobry sposób, aby to zrobić i zachować prawdziwe lokalizacje + nazwy plików w tajemnicy, więc ludzie nie mogą po prostu link do plików bezpośrednio, ale MUSZĄ się połączyć przez mój download.php? File = ID gatekeeper?

Dzięki

EDIT: Im nie pytając, jak to zrobić uwierzytelnianie użytkownika, wszystko, co jest zrobione. Po prostu pytam, czy mój sposób robienia tego jest dobrym pomysłem na dużą skalę. Wygląda na to, że może to spowodować problemy z pamięcią, jeśli będę nadal czytał pliki o pojemności 10 GB.

Odpowiedz

9

OK, posiadanie php wysyłanie plików około 400Mb-10Gb nie jest dobre. Musisz w jakiś sposób pozwolić na to, aby serwer, z którego korzystasz, faktycznie obsługuje pliki.

To naprawdę sprowadza się do tego, jak bardzo jest to bezpieczne. Najprostszym rozwiązaniem, które przychodzi na myśl (ale dalekim od najbezpieczniejszego), jest używanie dowiązań symbolicznych z długimi losowymi nazwami, które łączą się z oryginalnym plikiem. Po pewnym czasie dowiązania symboliczne wygasają i są usuwane. Każdy użytkownik otrzymuje swój link symboliczny (lub "token") do pliku, który pobiera. Nie jestem pewien, jak to się dzieje w środowisku Windows, ale na unixie jest to dość proste.

Oto niektóre pseudo kod:

if($user->isAllowedToDownload($file)){ 
    $token = md5($user->name . $file->name . time() . $someGoodRandomValue); 
    symlink($file, $download_path . $token); 
    header("Location: $download_url$token"); 
} 

Następnie trzeba crona, który czyści się stare linki symboliczne. Musisz również upewnić się, że serwer WWW jest ustawiony tak, aby podążał za dowiązaniami symbolicznymi, najlepiej tylko dla tego folderu, w którym tworzone są te tokeny pobierania.

Tak więc, gdy użytkownik może poprosić o numer domain.com/download?file=bigfile.mp4, w przestrzeni publicznej serwera sieciowego zostanie utworzone dowiązanie symboliczne, które wskazuje na prawdziwy plik poza serwerem internetowym. Użytkownik zostaje przekierowany na numer domain.com/getFile/ab739babec890103bdbca72, co z kolei powoduje, że serwer obsługuje plik. Teraz bardzo trudno jest użytkownikom zgadywać, jaki jest adres URL pliku, i to jest "bezpieczeństwo".

+0

Myślę, że możesz nawet rozłączyć plik (tutaj, link) po kilku sekundach, będę pracował dla bieżącego pobierania. Tak jak możesz utworzyć plik, otwórz go, usuń, a następnie przeczytaj. – Aif

+0

Nie wiedziałem tego, fajnie! Musisz sprawdzić, jak to działa w przypadku przerwania i wznawiania pobierania przez użytkowników. (Z plikami tak dużymi, że możemy założyć, że pobieranie zostanie przerwane?). – 0scar

+1

Możesz także przechowywać tokena w ciasteczkach i mieć reguły przepisywania, które przekształcą plik cookie w ścieżkę do pliku. Możesz uzyskać ładne adresy URL z oryginalnymi nazwami plików i pokazać skrypt PHP, jeśli plik cookie nie jest ustawiony lub dowiązanie symboliczne już nie istnieje. – Ski

1

Będziesz chciał jakoś je uwierzytelnić (formularz HTML, HTTP basic auth, cokolwiek), a następnie ustawić flagę session, którą twój skrypt download.php może sprawdzić. Pamiętaj, że to nie przeszkadza użytkownikom w pobieraniu pliku, a następnie samodzielnej dystrybucji.

Powinieneś skonfigurować swój serwer tak, aby prawdziwe pliki nie były bezpośrednio dostępne.

Nie spowoduje to problemów z pamięcią jako takich. readfile nie odczytuje pliku do pamięci. Jednak użycie PHP spowoduje utworzenie narzutów w postaci. Możesz anulować część tego opóźnienia, korzystając z numeru X-Sendfile.

2

Już to robisz - nazwa $public_filename jest tym, co chcesz wywołać, częścią pliku readfile ($ file_path) jest plik - jego lokalizacja nie jest upubliczniona. Po tym czasie może znajdować się nad katalogiem głównym dokumentu.

+0

rozumiem .. ale co Im zmierzasz jest. ... czy jest dobrym pomysłem, aby php odczytywał 10 GB plików do użytkowników? –

1
  1. Umieść pliki w miejscu niedostępnym przez HTTP.
  2. Utwórz tabelę bazy danych z identyfikatorami plików ze ścieżkami plików.
  3. Łącze do plików poprzez identyfikator pliku (jak wspomniano powyżej, download.php? FileID = 0000).
  4. ???
  5. Zysk.

Jako osoba, która zrobiła to wcześniej (wiele lat temu), należy wziąć pod uwagę wpływ pamięci na serwer. Funkcja readfile nie była wtedy dostępna, więc możliwe jest, że nie będziesz musiał robić nic specjalnego ze względu na kwestie pamięci.

1

Twoja metoda spowoduje problemy z pamięcią, jednak możliwe jest odczytywanie i wyprowadzanie pliku w porcjach. Będziesz musiał użyć funkcji flush() po każdym fragmencie pliku. Możesz również wznowić pobieranie, aby działał z nieco większym nakładem pracy. Nadal jest to podejście głodne procesora.

Łatwiejszym i lepszym rozwiązaniem jest użycie tagu nagłówkowego "x-sendfile" obsługiwanego przez apache i lighttpd poprzez ich moduły. Wszystko, co musisz zrobić, to podać nazwę pliku w nagłówku, podobny do tego:

header('X-Sendfile: filename-on-your-file-system'); 

Link dla lighttpd:

http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file

Powiązane problemy