[PHP] File in delen doorgeven

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Xandrios
  • Registratie: Februari 2001
  • Laatst online: 16:24
Goedenavond :)

Ik ben momenteel bezig met een download script, je kent ze wel: Zorgen dat men niet kan hotlinken, aantal downloads bijhouden etc etc. Gaat prima, maar ik loop tegen een probleempje op:

Op dit moment gebruik ik de volgende code om het bestand naar de bezoeker te sturen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
// open the file in a binary mode
$totaal_path = "$file_path/$bestand_name";
$fp = fopen($totaal_path, 'r');

// send the right headers
header("content-type: application/octet-stream");
header("Content-Length: ".filesize($totaal_path));
header("Content-Disposition: attachment; filename=$bestand_name"); 

// dump the picture and stop the script
fpassthru($fp);
exit;

En ja...dit werkt perfect. Maar het heeft ook een groot nadeel: Hij laad het complete bestand in het geheugen. En bij meerdere simultane downloads (Van grote files, bijv. 100MB) gaat dat dus niet goed. Het hele RAM geheugen loopt vol.

Toen bedacht ik hetvolgende:
PHP:
1
2
3
4
5
// send the right headers
header("content-type: application/octet-stream");
header("Content-Length: ".filesize($totaal_path));
header("Content-Disposition: attachment; filename=test.test"); 
header("Location: www.***.com/$bestand_naam");

Mijn idee was dus om een andere filenaam mee te geven dan de naam op schijf. Zodat als iemand de url direct zou benaderen (met de bestandsnaam dat gegeven wordt) , het bestand niet bestaat.
Helaas werkt dit niet: Hij pakt de originele bestandsnaam. Die header ("Location is dus echt een soort van redirect, en dit truucje werkt niet.

Dus...dan zal er (denk ik) een soort van stream gemaakt moeten worden. Kleine stukjes inlezen, en outputten. Hiervoor probeerde ik de volgende code:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
$handle = fopen("test.test", "r");
$contents = "";
do {
   $data = fread($handle, 8192);
   if (strlen($data) == 0) {
        echo "break";
       break;
   }
   fpassthru($data);
   
} while (true);
fclose($handle);

Maar dit geeft een "break", oftewel: hij laadt sowieso al geen data in. Maar het path is goed...dus ik snap het probleem niet.

Iemand die me kan vertellen of bovenstaande manier te gebruiken is? En/of wat ik fout doe, waarom hij denkt dat de file geen data bevat?
Ik denk dat het ook handig is om het aantal bytes dat hij opent te verhogen, naar bijvoorbeeld een aantal MB. Want op deze manier zal hij mischien wel vreselijk veel processor kracht kosten.

Of zit ik helemaal verkeerd te denken, en kan dit simpeler?

Bedankt _o_

Acties:
  • 0 Henk 'm!

Verwijderd

Als ik dit doe met een testfile en een echo dan laat hij het gewoon zien.
test.php
PHP:
1
2
3
4
5
6
7
8
9
$handle = fopen("test.abc", "r"); 
do { 
    $data = fread($handle, 1); 
    if (strlen($data) == 0) { 
        break; 
    }
    echo $data."<br>";
} while (true); 
fclose($handle);

test.abc
code:
1
abcdefghijklmnopqrstuvwxyz


Ik zal verder even testen in hoeverren dit werkt, het idee werkt met een textfile. Ik ben nog even vedder testen met losse files.

[edit]
Als ik met headers ga werken en een fpassthu dan krijg ik de melding:
"Supplied argument is not a valid File-Handle resource in c:apachehtdocstest.php on line 12"

Ik had opeens een idee, als je de headers juist doorgeeft dan kan je het eens proberen met een echo ipv fpassthru. Dit gebruik ik zelf ook voor het laten zien van mijn avatar, mijn hosting heeft namelijk fpassthru geblocked :(

De onderstaande code werkt bij mij (overigens niet zwaar getest, enkel met de abcfile), maar probeer het voor de grap.
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
header("content-type: application/octet-stream"); 
header("Content-Length: ".filesize("test.abc\"\"")); 
header("Content-Disposition: attachment; filename=test.abc"); 

$handle = fopen("test.abc", "r"); 
do { 
    $data = fread($handle, 1); 
    if (strlen($data) == 0) { 
        break; 
    } else {
        echo($data);
    }
} while (true); 
fclose($handle);

[ Voor 67% gewijzigd door Verwijderd op 03-01-2004 04:42 ]


Acties:
  • 0 Henk 'm!

  • Xandrios
  • Registratie: Februari 2001
  • Laatst online: 16:24
Bedankt voor je reply !


Jou versie werkt inderdaad wel, blijkbaar zat er dan toch een foutje in mijn stukje code. Alhoewel ik hem zo niet zie zitten...

Maargoed, dat werkt inderdaad met echo. Sterker nog, onder IE werkt het helemaal prima :)

Onder Mozilla daarintegen, daar plakt mozilla de extensie .php achter de file. Geen idee waarom, maar het gebeurd. Allerlei headers geprobeerd, mocht niet baten :(

Toen maar even gaan zoeken, het schijnt een bug van Mozilla te zijn ( :? ), maar dat lijkt me sterk. In de vele releases van Mozilla die ondertussen zijn uitgekomen zou dat dan vast en zeker gefixed zijn.

Iemand die hier mischien een workaround voor weet? Of een header die dit probleem kan oplossen ?
Ik neem tenminste aan dat dit probleem vaker voorkomt?

Acties:
  • 0 Henk 'm!

  • Erkens
  • Registratie: December 2001
  • Niet online

Erkens

Fotograaf

fpassthru kan je enkel gebruiken in combinatie met een file resource en niet met een string zoals je hier gebruikt hebt :P
workaround voor je extensie bugje:

http://server/downloadscript.php/filename.ext

met pathinfo dus :P

Acties:
  • 0 Henk 'm!

  • Xandrios
  • Registratie: Februari 2001
  • Laatst online: 16:24
Erkens schreef op 03 januari 2004 @ 15:42:
fpassthru kan je enkel gebruiken in combinatie met een file resource en niet met een string zoals je hier gebruikt hebt :P
workaround voor je extensie bugje:

http://server/downloadscript.php/filename.ext

met pathinfo dus :P
Whaha :D
die slash doet het hem idd, het werkt nu iig prima :)

Ik heb de fread een grootte van 1MB meegegeven. Ik ging er dus vanuit dat hij eerst 1MB zou inlezen, als deze gedownload was, de volgende MB etc etc

Of hij het precies zo doet weet ik niet...maar feit is dat de proc. belasting direct al naar 3-6% stijgt bij 1 enkele transfer. Bij meerdere transfers gaat hij verder omhoog. Dat gaat dus niet lekker.

Is er een manier om te zien hoeveel cpu en mem zo'n download gebruikt? Onder een redhat machine that is.
Ik kan namelijk niet echt zien wat de preciese todracht is van deze traagheid...