Webbsida: blockera tillgång till vissa filer

Permalänk
Medlem

Webbsida: blockera tillgång till vissa filer

Har nyss lärt mig php och mySQL vilket gjort det möjligt att skapa en inloggningsfunktion på min hemsida. Nu är det så att jag skulle vilja publicera en del material på hemsidan som enbart är tillgängligt för den som är inloggad. Det är enkelt att se till att länkarna till materialet enbart syns om man faktiskt är inloggad. Det är ju då inte möjligt att klicka på någon länk och man kan därför inte heller ladda ned någon fil (t.ex. en pdf-fil).

Men om jag känner till pdf-filens fullständiga sökväg kan jag ju bara skriva in den i adressfältet så kommer jag ändå att komma åt den. Självklart spelar det då ingen roll om jag är inloggad på hemsidan eller inte. Finns det någon möjlighet att låsa en mapp på en webbserver så att enda sättet att komma åt filerna är att faktiskt vara inloggad på hemsidan?

Jag antar att .htaccess kan göra något sådant men då måste man väl logga in varje gång man vill ladda ned en fil? Jag vill på något sätt kontrollera: är användaren inloggad, om ja -> full access till mappen med filerna.

Permalänk
Medlem

Skulle nog föreslå att du hindrar alla från att se filerna, sen gör du en ny fil (download.php eller nåt) som först kollar så att användaren är inloggad, sen med hjälp av fopen()/fread() och header('Content-Type: application/download') (inte säker på att det är rätt header, kolla upp det) läser av filen och sedan skickar den till användaren.

Skickades från m.sweclockers.com

Permalänk
Medlem

Det låter ju som en bra idé. Har inte använt fopen() förr men jag antar att det borde gå att lära sig rätt så lätt. Men en följdfråga:

Hur låser jag en mapp för samtliga användare? Blir den inte låst även för min nedladdningssida (download.php)?

Permalänk
Skrivet av wolfpine:

Det låter ju som en bra idé. Har inte använt fopen() förr men jag antar att det borde gå att lära sig rätt så lätt. Men en följdfråga:

Hur låser jag en mapp för samtliga användare? Blir den inte låst även för min nedladdningssida (download.php)?

Lås den i webbserverns konfigurationsfil.
Om din webbserver är Apache kan du lägga en fil som heter .htaccess i samma mapp med detta innehåll:

<Files *> Order Allow,Deny Deny from All </Files> php_value engine off

Detta kommer göra så att om nån försöker besöka filen på direkt adressen (/download/fil.gif) så skickar webbservern ett "403 access denied".
php_value engine off stänger av alla PHP-skript så inga php skript i den mappen kommer kunna köras (dom kommer visas som klartext).

För att komma åt filer i /download/ mappen så får du göra ett skript som alla dina medlemmar går via.

if(!member) redirect loginpage; fopen("/download/fil.gif"); skicka header osv

Permalänk
Medlem

Testade nu med den lösningen och det verkar fungera bra! Gjorde en .htaccess-fil i den mappen med test.pdf. Därefter skapade jag bara en test.php med väldigt lite kod:

<?php $pdf = 'doc/protected/test.pdf'; header('Content-type: application/pdf'); header('Content-Disposition: attachment; filename="'.$pdf.'"'); readfile($pdf); ?>

Detta får nedladdningsfönstret att öppnas. Jag är helt ny vad gäller dessa "header". Går det att ändra dem på något sätt så att filen öppnas i en ny flik och presenteras i webbläsaren. Alltså precis på samma sätt som om jag hade gjort en vanlig

<a href='doc/protected/test.pdf' target='_blank'>TEST</a>?

Permalänk
Skrivet av wolfpine:

Testade nu med den lösningen och det verkar fungera bra! Gjorde en .htaccess-fil i den mappen med test.pdf. Därefter skapade jag bara en test.php med väldigt lite kod:

<?php $pdf = 'doc/protected/test.pdf'; header('Content-type: application/pdf'); header('Content-Disposition: attachment; filename="'.$pdf.'"'); readfile($pdf); ?>

Detta får nedladdningsfönstret att öppnas. Jag är helt ny vad gäller dessa "header". Går det att ändra dem på något sätt så att filen öppnas i en ny flik och presenteras i webbläsaren. Alltså precis på samma sätt som om jag hade gjort en vanlig

<a href='doc/protected/test.pdf' target='_blank'>TEST</a>?

Du skulle kunna skicka GET-parametrar till test.php.
Så länken blir t ex:

<a href="test.php?file=doc/protected/test.pdf" target="_blank">File</a>

Men då måste du även verifiera sökvägen så dom inte kan vandra utanför doc/protected.

Dessutom ska inte Content-Disposition ha filename med citattecken. (även om en del webbläsare accepterar det)

Content-Disposition: attachment; filename=test.pdf

Permalänk
Medlem

Testade nu att i vanliga sidan med länken skriva:

<a href="test.php?file=doc/protected/test.pdf" target="_blank">File</a>

Och sedan i test.php:

<?php $pdf = $_POST['file']; header('Content-type: application/pdf'); header('Content-Disposition: attachment; filename=' . $pdf); readfile($pdf); ?>

Men det fungerade på samma sätt som förr, alltså att nedladdningsfönstret öppnades. Men jag kanske kan nöja mig med det. Jag vet ändå inte riktigt vad du menar med "verifiera sökvägen" och det kanske är för avancerat för mig :P.

Permalänk
Skrivet av wolfpine:

Testade nu att i vanliga sidan med länken skriva:

<a href="test.php?file=doc/protected/test.pdf" target="_blank">File</a>

Och sedan i test.php:

<?php $pdf = $_POST['file']; header('Content-type: application/pdf'); header('Content-Disposition: attachment; filename=' . $pdf); readfile($pdf); ?>

Men det fungerade på samma sätt som förr, alltså att nedladdningsfönstret öppnades. Men jag kanske kan nöja mig med det. Jag vet ändå inte riktigt vad du menar med "verifiera sökvägen" och det kanske är för avancerat för mig :P.

Ändra $_POST till $_GET så kommer det funka, men du måste verifiera sökvägen före, annars kommer dom kunna komma åt vilken fil som helst.
Med det menar jag att om dom ändrar länken till test.php?file=/index.php så kommer dom åt index.php i klartext och har du något lösenord där så är du körd.

Permalänk
Medlem

Provade att ändra POST till GET men det gav samma resultat. Men egentligen är det inte så jätteviktigt, man får ju ändå möjlighet att ladda ned filen eller välja att öppna den i sin installerade pdf-viewer. Nu har jag iaf en sådan funktion på sidan som jag önskade.

Men jag förstår fortfarande inte exakt vad du menar med att verifiera sökvägen. Jag provade att lägga till en annan länk:
<a href="test.php?file=index.php" target="_blank">File</a> och precis som du sade så kunde jag då spara ner hela min index.php med all kod osv. Inte bra

Men hur går jag förbi det här på smidigast sätt? Kan jag göra något i test.php som kollar att man verkligen försöker öppna efter en pdf fil eller dylikt?

Tackar så jättemycket för hjälpen, det har varit mycket lärorikt

Permalänk
Skrivet av wolfpine:

Provade att ändra POST till GET men det gav samma resultat. Men egentligen är det inte så jätteviktigt, man får ju ändå möjlighet att ladda ned filen eller välja att öppna den i sin installerade pdf-viewer. Nu har jag iaf en sådan funktion på sidan som jag önskade.

Men jag förstår fortfarande inte exakt vad du menar med att verifiera sökvägen. Jag provade att lägga till en annan länk:
<a href="test.php?file=index.php" target="_blank">File</a> och precis som du sade så kunde jag då spara ner hela min index.php med all kod osv. Inte bra

Men hur går jag förbi det här på smidigast sätt? Kan jag göra något i test.php som kollar att man verkligen försöker öppna efter en pdf fil eller dylikt?

Tackar så jättemycket för hjälpen, det har varit mycket lärorikt

Ja, det är i test.php du verifierar att den som besöker är en medlem och att h*n är i rätt mapp.

Exempel:

<?php // Länken blir nu <a href="test.php?file=dokument.pdf" target="_blank">fil</a> $basepath = "doc/protected"; // För att göra urlen "finare" $file = preg_replace("/[^a-zA-Z0-9._ -]/", "", str_replace(" ", "_", $_GET['file'])); // Ändrar " " till "_" och tillåter bara a-z A-Z 0-9 . _ och - i filnamn // Verifiera att personen är en medlem här $member = true; if(!$member) die('You are not a member.'); // Skicka headers header("Content-Type: application/pdf"); // Om du vill att filen ska laddas ner direkt kan du använda application/octet-stream //header("Content-Length: 1337"); // Om du vet hur stor filen är i bytes så går det att ange här så får webbläsarna rätt storlek för deras "progress bar" header("Content-Disposition: attachment; filename=".$file); // Hämta filen readfile($basepath.'/'.$file); ?>

Om du har några filer med mellanrum i namnet så måste du ta bort det (eller byta ut mot _) för att det här skriptet ska fungera.

Permalänk
Medlem

om server har linux så är det ju bara att ändra chmod

*edit*
nvm jag läste inte längre än topic

Visa signatur

| ASUS P8Z77-V DELUXE | Intel Core i7 2700K @ 4.7Ghz | 16GB Corsair Vengeance 1600Mhz @ 8-8-8-24 |
| ATi Radeon HD 6950@6970 (900|1350Mhz @ 1.14v) | Corsair Force GT 120GB | Corsair HX 650W |
| Nvidia's GT300 yields are less than 2% | Min ArmA2 YouTube Kanal |

Permalänk
Medlem

Tackar Lullebulle för mycket utförliga och bra svar :). Detta kommer passa perfekt!

Permalänk
Medlem

Haha, nu när jag trodde allt skulle fungera så har det blivit ett annat knäppt fel. När jag klickar på länken till test.pdf så öppnas den i webbläsaren och en massa konstiga tecken skrivs ut. Hela webbläsaren fylls med dessa tecken. Har även provat på en annan dator.

Om jag istället provar att länka till index.php så fungerar mitt skript som säger att filen inte existerar.

Antar att jag kanske glömt någon header som krävs för att få någon slags decoding att fungera?

Länk:

<a href="test.php?file=test.pdf" target="_blank">File</a><br> <a href="test.php?file=test2.pdf" target="_blank">Fil2</a><br> <a href="test.php?file=index.php" target="_blank">INDEX</a>

test.php:

<?php session_start(); $basepath = 'doc/protected/'; $file = preg_replace("/[^a-zA-Z0-9._ -]/", "", str_replace(" ", "_", $_GET['file'])); // Ändrar " " till "_" och tillåter bara a-z A-Z 0-9 . _ och - i filnamn // Verifiera att man är inloggad if(!$_SESSION['auth']) { die('Du måste logga in för att ladda ned filer.'); } $pdf = $basepath . $file; // Kontrollera att filen existerar. if(!file_exists($pdf)) { die("Tyvärr finns inte denna fil tillgänglig."); } // Skicka headers header('Content-Type: application/pdf'); header('Content-Disposition: attachment; filename=' . $file); // Hämta filen readfile($pdf); ?>

Alltså: test.pdf och test2.pdf öppnas i webbläsaren med enbart en massa konstiga tecken, det skrivs ut i form av text. Alltså inte som om det vore en pdf. index.php ger felmeddelande.

Detta felmeddelande ser för övrigt ut såhär: Tyvärr finns inte denna fil tillgänglig. Kan det ha något att göra med problemet jag har med pdf-filen?

Permalänk
Skrivet av wolfpine:

Haha, nu när jag trodde allt skulle fungera så har det blivit ett annat knäppt fel. När jag klickar på länken till test.pdf så öppnas den i webbläsaren och en massa konstiga tecken skrivs ut. Hela webbläsaren fylls med dessa tecken. Har även provat på en annan dator.

Om jag istället provar att länka till index.php så fungerar mitt skript som säger att filen inte existerar.

Antar att jag kanske glömt någon header som krävs för att få någon slags decoding att fungera?

Länk:

<a href="test.php?file=test.pdf" target="_blank">File</a><br> <a href="test.php?file=test2.pdf" target="_blank">Fil2</a><br> <a href="test.php?file=index.php" target="_blank">INDEX</a>

test.php:

<?php session_start(); $basepath = 'doc/protected/'; $file = preg_replace("/[^a-zA-Z0-9._ -]/", "", str_replace(" ", "_", $_GET['file'])); // Ändrar " " till "_" och tillåter bara a-z A-Z 0-9 . _ och - i filnamn // Verifiera att man är inloggad if(!$_SESSION['auth']) { die('Du måste logga in för att ladda ned filer.'); } $pdf = $basepath . $file; // Kontrollera att filen existerar. if(!file_exists($pdf)) { die("Tyvärr finns inte denna fil tillgänglig."); } // Skicka headers header('Content-Type: application/pdf'); header('Content-Disposition: attachment; filename=' . $file); // Hämta filen readfile($pdf); ?>

Alltså: test.pdf och test2.pdf öppnas i webbläsaren med enbart en massa konstiga tecken, det skrivs ut i form av text. Alltså inte som om det vore en pdf. index.php ger felmeddelande.

Detta felmeddelande ser för övrigt ut såhär: Tyvärr finns inte denna fil tillgänglig. Kan det ha något att göra med problemet jag har med pdf-filen?

Specialtecken (å ä ö m.fl) blir i fel kodning om du bara visar i text, för att komma runt detta kan du använda html special koder (eller specificera kodningen i <head>-taggen).

Koden funkar utmärkt för mig.
http://dev.korkad.nu/0/pdf/

<?php if(!isset($_GET['file'])) die('<a href="?file=test.pdf&log=ja" target="_blank">test.pdf</a><br><a href="?file=test.pdf" target="_blank">test.pdf utan login</a><br><a href="?file=random.pdf&log=ja" target="_blank">random.pdf utan login</a>'); $basepath = 'doc/protected/'; $file = preg_replace("/[^a-zA-Z0-9._ -]/", "", str_replace(" ", "_", $_GET['file'])); // Ändrar " " till "_" och tillåter bara a-z A-Z 0-9 . _ och - i filnamn // Verifiera att man är inloggad if(!isset($_GET['log'])) { die('Du måste logga in för att ladda ned filer.'); } $pdf = $basepath . $file; // Kontrollera att filen existerar. if(!file_exists($pdf)) { die("Tyvärr finns inte denna fil tillgänglig."); } // Skicka headers header('Content-Type: application/pdf'); header('Content-Disposition: attachment; filename=' . $file); // Hämta filen readfile($pdf); ?>

Permalänk
Legendarisk
Skrivet av wolfpine:

Detta felmeddelande ser för övrigt ut såhär: Tyvärr finns inte denna fil tillgänglig. Kan det ha något att göra med problemet jag har med pdf-filen?

Du måste spara källfilen (ditt PHP-script) med samma teckentabell som du / din server meddelar klienten att den ska använda. Vad du har där är UTF-8 tolkat som ISO 8859-1. Alternativt så ersätter du de tecken som skiljer sig åt med html entities, men det är inte helt rätt eftersom att du i grunden fortfarande inte har åtgärdat problemet med blandade teckentabeller.

Skickades från m.sweclockers.com

Visa signatur

Abstractions all the way down.

Permalänk
Medlem

Jag fattar verkligen inte vad det är för fel :P. Av någon anledning var just test.php inte sparad i UTF-8. Nu ändrade jag det vilket gjorde att felmeddelandet för fallet "denna fil existerar ej" presenteras korrekt.

Men det är fortfarande fullt med konstiga tecken som presenteras i webbläsaren om jag försöker öppna pdf-filen. Dessa tecken ser visserligen annorlunda ut nu när jag ändrade kodningen men pdf-filen öppnas inte.

Min kod ser ju ut exakt som din.

 <?php session_start(); $basepath = 'doc/protected/'; $file = preg_replace("/[^a-zA-Z0-9._ -]/", "", str_replace(" ", "_", $_GET['file'])); // Ändrar " " till "_" och tillåter bara a-z A-Z 0-9 . _ och - i filnamn // Verifiera att man är inloggad if(!$_SESSION['auth']) { die('Du måste logga in för att ladda ned filer.'); } $pdf = $basepath . $file; // Kontrollera att filen existerar. if(!file_exists($pdf)) { die("Tyvärr finns inte denna fil tillgänglig."); } // Skicka headers header('Content-Type: application/pdf'); header('Content-Disposition: attachment; filename=' . $file); // Hämta filen readfile($pdf); ?>

Permalänk
Medlem

Har suttit i flera timmar nu utan att hitta någon med samma problem som mig. Jag har gjort det enklaste php-skriptet nu som borde fungera:

 <?php $basepath = 'doc/protected/'; $file = 'test2.pdf'; $pdf = $basepath . $file; // Skicka headers header('Content-Type: application/pdf'); header('Content-Disposition: attachment; filename=' . $file); // Hämta filen readfile($pdf); ?>

Filen är sparad i UTF-8. När jag kör detta skript (på olika datorer) så ser jag bara följande:

Det värsta är att det fungerade ju igår när jag körde ett enkelt skript men tydligen inte längre. Kan jag på något sätt ha kommit åt någon konstig inställning på servern? Jag har ju inte varit in och ändrat något men det kanske finns nåt som ändras automatiskt.

Permalänk
Medlem

Testa skriva header ('Content-type: application/pdf; charset=utf-8'); istället

Skickades från m.sweclockers.com

Permalänk
Medlem

Det har jag tyvärr redan testat utan resultat. Men det känns så konstigt att webbläsaren själv försöker tolka informationen som finns i dokumentet. Borde den inte "förstå" att den ska öppna t.ex. Word eller PDF-viewer för att läsa dessa dokument?

Permalänk
Medlem

Efter mycket om och men så har jag äntligen fått till det. Jag sparade själva php-filen i ANSI-format vilket gjorde att det nu fungerar som det är tänkt. Det blir dock fula tecken då vissa av mina felmeddelanden innehåller åäö men det får jag leva med. Här är den slutliga koden som fungerar:

<?php session_start(); $basepath = 'doc/protected/'; $filename = preg_replace("/[^a-zA-Z0-9._ -]/", "", str_replace(" ", "_", $_GET['file'])); $file = $basepath . $filename; // Verify login if (!$_SESSION['auth']) { die('Du måste logga in för att ladda ned denna fil.'); } // Control that the file exists if (!file_exists($file)) { die('Denna fil finns inte att ladda ned'); } // Decide what MIME-type is active $known_mime_types=array( "pdf" => "application/pdf", "txt" => "text/plain", "html" => "text/html", "htm" => "text/html", "exe" => "application/octet-stream", "zip" => "application/zip", "doc" => "application/msword", "xls" => "application/vnd.ms-excel", "ppt" => "application/vnd.ms-powerpoint", "gif" => "image/gif", "png" => "image/png", "jpeg"=> "image/jpg", "jpg" => "image/jpg", "php" => "text/plain" ); $file_extension = strtolower(substr(strrchr($file,"."),1)); if(array_key_exists($file_extension, $known_mime_types)) { $mime_type=$known_mime_types[$file_extension]; } else { $mime_type="application/force-download"; } // For Internet Explorer if (ini_get('zlib.output_compression')) { ini_set('zlib.output_compression', 'Off'); } // Send Headers header('Content-Type: ' . $mime_type); header('Content-Disposition: attachment; filename="' . $filename . '"'); header('Content-Transfer-Encoding: binary'); header("Cache-Control: must-revalidate"); header("Content-Description: File Transfer"); header('Content-Length: ' . filesize($file)); header('Expires: 0'); header('Pragma: public'); readfile($file); ?>

Permalänk
Skrivet av wolfpine:

Efter mycket om och men så har jag äntligen fått till det. Jag sparade själva php-filen i ANSI-format vilket gjorde att det nu fungerar som det är tänkt. Det blir dock fula tecken då vissa av mina felmeddelanden innehåller åäö men det får jag leva med. Här är den slutliga koden som fungerar:

<?php session_start(); $basepath = 'doc/protected/'; $filename = preg_replace("/[^a-zA-Z0-9._ -]/", "", str_replace(" ", "_", $_GET['file'])); $file = $basepath . $filename; // Verify login if (!$_SESSION['auth']) { die('Du måste logga in för att ladda ned denna fil.'); } // Control that the file exists if (!file_exists($file)) { die('Denna fil finns inte att ladda ned'); } // Decide what MIME-type is active $known_mime_types=array( "pdf" => "application/pdf", "txt" => "text/plain", "html" => "text/html", "htm" => "text/html", "exe" => "application/octet-stream", "zip" => "application/zip", "doc" => "application/msword", "xls" => "application/vnd.ms-excel", "ppt" => "application/vnd.ms-powerpoint", "gif" => "image/gif", "png" => "image/png", "jpeg"=> "image/jpg", "jpg" => "image/jpg", "php" => "text/plain" ); $file_extension = strtolower(substr(strrchr($file,"."),1)); if(array_key_exists($file_extension, $known_mime_types)) { $mime_type=$known_mime_types[$file_extension]; } else { $mime_type="application/force-download"; } // For Internet Explorer if (ini_get('zlib.output_compression')) { ini_set('zlib.output_compression', 'Off'); } // Send Headers header('Content-Type: ' . $mime_type); header('Content-Disposition: attachment; filename="' . $filename . '"'); header('Content-Transfer-Encoding: binary'); header("Cache-Control: must-revalidate"); header("Content-Description: File Transfer"); header('Content-Length: ' . filesize($file)); header('Expires: 0'); header('Pragma: public'); readfile($file); ?>

Använd html specialkoderna, finns länkade i några inlägg ovanför.