PHP - Autentikáció után fájl letöltés

PHP - Autentikáció után fájl letöltés
2022-09-07T21:11:33+02:00
2022-09-09T21:09:33+02:00
2022-12-07T03:30:34+01:00
Wowbagger78
Sziasztok!

Felhasználónév és jelszó bekérése és ellenőrzése után szeretném engedni, hogy egy adott fájlt letöltsön a felhasználó a gépére.

Van egy password.php nevű fájlom:

<?php $dir="http://demoweb.hu/secretfolder/"; //A könyvtár, fájlnév nélkül $param=$_SERVER['QUERY_STRING']; if (strstr($param,"ProgramSetup")) { $login = "testuser"; $password = "SeCret"; $filename = "ProgramSetup.exe"; $path=$dir.$filename; } if (!isset($_SERVER['PHP_AUTH_USER'])) { header("WWW-Authenticate: Basic realm="Private Area""); header("HTTP/1.0 401 Unauthorized"); echo "Nincs jogosultsága letölteni a fájlt."; exit; } else { if (($_SERVER['PHP_AUTH_USER'] == $login) && ($_SERVER['PHP_AUTH_PW'] == $password)) { echo "Felhasználó név: {$_SERVER['PHP_AUTH_USER']}<BR>"; echo "Jelszó: {$_SERVER['PHP_AUTH_PW']}<BR>"; echo "Letöltendő fájl: {$path}<BR>"; echo "Ide jönne a letöltő kód a Mentés másként ablakkal."; } else { header("WWW-Authenticate: Basic realm="Private Area""); header("HTTP/1.0 401 Unauthorized"); echo "Nincs jogosultsága letölteni a fájlt."; exit; } } ?>
Amit így hivatkozok le html-ből:

<a href="password.php?ProgramSetup" target="_self">Letöltés</a>
Linkre kattintás után a jelszóbekérő ablak be is jön, felhasználót, jelszót ellenőrzöm (a teszt miatt van php-ben hardkódolva a login és a password, majd lesz mögötte MySQL) és, ha jó akkor a fenti kód szerint szerint kiírja, helyesen, hogy:

Felhasználó név: testuser Jelszó: SeCret Letöltendő fájl: http://demoweb.hu/secretfolder/ProgramSetup.exe Ide jönne a letöltő kód a Mentés másként ablakkal.
Helyesen megadott felhasznál/jelszó páros után hogyan tudom elindítani a fájl letöltést (http://demoweb.hu/secretfolder/ProgramSetup.exe) egy Mentés másként panel megjelenítésével?

PHP fájlban ilyesmivel próbálkoztam, de nem jött be:

print "<script language='JavaScript'>"; print "window.location='".$path."'"; print "</script>\n";
W.
Mutasd a teljes hozzászólást!
Nem azt kell csinálnod, hogy a böngészőt átirányítod a http://.../ProgramSetup.exe címre, hanem a PHP-nak meg kellene nyitnia a fájlt, felolvasni a tartalmát memóriába és azt tovább küldeni a kliensnek. Szóval valahogy így:

//... $logged_in = ...; if ($logged_in) { $filename = "path/to/your/file"; $mimetype = "mime/type"; header("Content-Type: ".$mimetype ); echo readfile($filename); } else { echo "Nincs jogosultságod a fájl letöltéséhez"; }
Ez a naiv megközelítés azt csinálja, hogy a readfile felolvassa a fájl teljes tartalmát a memóriába, majd echo-val elküldi a kliensednek. No ezzel van egy pár probléma:
1) Jól sejted, hogy ehhez a programod akár GiB-okban mérhető memóriamennyiséget is lefoglalhat, ha akkora fájlról beszélünk. És ez csak egy kliens. Szorozd ezt be annyival, ahányan egy időpillanatban kérik el tőled a fájlt.
2) Az I/O művelet lassú. Ha ilyen nagy fájlokról van szó, akkor amíg a szerver beolvassa, a kliens mondhatja azt, hogy "jó, én nem várok tovább, timeout".

Ezen a két problémán úgy tudunk segíteni, hogy nem egyszerre olvassuk be az egész fájlt, hanem beolvasunk egy apró részletet belőle, mondjuk max. párszáz KiB-ot, és azonnal küldjük az adatot a kliensnek. Ez némileg bonyolultabb megoldás, de mindenképp megéri alkalmazni:

//... $logged_in = ...; define("CHUNK_SIZE", 1024*1024); // Size (in bytes) of tiles chunk // Read a file and display its content chunk by chunk function readfile_chunked($filename, $retbytes = TRUE) { $buffer = ""; $cnt =0; // $handle = fopen($filename, "rb"); $handle = fopen($filename, "rb"); if ($handle === false) { return false; } while (!feof($handle)) { $buffer = fread($handle, CHUNK_SIZE); echo $buffer; ob_flush(); flush(); if ($retbytes) { $cnt += strlen($buffer); } } $status = fclose($handle); if ($retbytes && $status) { return $cnt; // return num. bytes delivered like readfile() does. } return $status; } if ($logged_in) { $filename = "path/to/your/file"; $mimetype = "mime/type"; header("Content-Type: ".$mimetype ); readfile_chunked($filename); } else { echo "Nincs jogosultságod a fájl letöltéséhez"; }
Persze ha lehetőséged van arra, hogy magát a webszervert (Apache, IIS, stb.) konfiguráld fel a fájl kiszolgálására, akkor érdemesebb azt az utat választani. Mint ahogy a forrásként megjelölt cikkben teszi a szerző a Lighttpd szerverrel.

Forrás: How to serve big files through PHP
Mutasd a teljes hozzászólást!

Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd