Dateidownload mittels "header" und "echo"

FBIagent

Erfahrenes Mitglied
Guten Tag,

ich habe mir ein Script geschrieben, bei dem der Dateidownload nicht über den direkten
Link der datei läuft, sondern ich setze den header und gebe den Inhalt der Datei mittels
"echo" aus. Erst hatte ich es so probiert:
PHP:
if ( file_exists( 'blabla.ext' ) === true ) {
    echo @file_get_contents( 'blabla.ext' );
}

Das hatte allerdings den Nachteil, dass die zum download bereitgestellte Datei
vollständig in den Arbeitsspeicher geladen wurde. Dazu habe ich auch schon abhilfe
geschaffen, indem ich immer nur eine kleinere menge auf einmal aus der Datei lese.
PHP:
                if ( file_exists( './usr/' . $File ) === true ) {
                    $FileHandle = @fopen( './usr/' . $File, 'r' );

                    if ( $FileHandle ) {
                        header( 'Content-Type: application/octet-stream' );
                        header( 'Content-Length: ' . ( filesize( './usr/' . $File ) ) );
                        header( 'Content-Disposition: attachment; filename="' . $fileSplit[ count( $fileSplit ) - 1 ] . '"' );
                        header( 'Content-Transfer-Encoding: binary' );

                        while ( true ) {
                            $Buffer = '';
                            $Byte = null;

                            for ( $i = 0;$i < 131072;++ $i ) {
                                $Byte = @fgetc( $FileHandle  );

                                if ( $Byte === false ) {
                                    break;
                                }

                                $Buffer .= $Byte;
                            }

                            echo $Buffer;

                            if ( $Byte === false || connection_aborted() !== 0 ) {
                                break;
                            }

                            sleep( 1 );
                        }
                    } else {
                        $Logger->Log( 'Download.php: Unavaiable file(./usr/' . $File . ')! User: ' . $_SESSION[ 'authed_usr' ] );
                        echo '<font size="4">File not avaiable!</font>';
                    }
                } else {
                    $Logger->Log( 'Download.php: Unavaiable file(./usr/' . $File . ')! User: ' . $_SESSION[ 'authed_usr' ] );
                    echo '<font size="4">File not avaiable!</font>';
                }

Mit dieser Lösung gibt es nur noch ein Problem, welches ich nicht lösen konnte.
Die Schleife, die den $Buffer füllt,
PHP:
for ( $i = 0;$i < 131072;++ $i ) {
, Konsumiert zuviel CPU-Zeit, sprich die auslastung
ist bei schon nur einem Benutzer beispielsweise bei 10%.
Dann habe ich versucht usleep zu benutzen:
PHP:
usleep( 1000 ); // 1 ms

usleep aber scheint immer gleich lahm zu sein und ich habe nur eine downloadrate
von nichteinmal einem KByte. Wie auf php.net beschrieben, soll usleep seit PHP 5.0.0
auch auf windows systemem richtig funktionieren. Installiert habe ich Apache 2.2.8 mit
PHP 5.2.5. Nach dem was ich ausprobiert habe scheint usleep doch nicht zu
funktionieren(WinXP Pro x64). Gibt es eine andere möglichkeit die Scriptausführung
zu drosseln, sodas die Downloads sogut wie keine performance klauen?

Best wishes
FBIagent
 
Zuletzt bearbeitet:
Wird da denn nicht auch alles in den Arbeitsspeicher geladen?

Ich möchte schon bei meinem Zweiten Ansatz bleiben, da ich so auch die Downloadrate
pro Benutzer drosseln kann und das Script beenden wenn connection_aborted() wärend ich
die Datei sende. Das Script soll sowohl für kleine als auch große Dateien gut performen(ich
gehe jetzt mal davon aus das readfile auch seine Zeit braucht bei einer 500MByte Datei).
Gibts keine alternative zu usleep() auf Windows?

Best wishes
FBIagent
 
Zuletzt bearbeitet:
Hi,

Wird da denn nicht auch alles in den Arbeitsspeicher geladen?

Doch, stimmt.

Wenn Dein Problem nur die for-Schleife ist:
Dass das lahm ist, wenn Du die Datei zeichenweise liest, ist eigentlich klar. Versuch's doch mal blockweise mit fread.
Ich glaube, in den User Contributed Notes zu readfile hatten auch einige Routinen mit fread gepostet.

LG
 
Lese doch bitte noch einmal genau was ich geschrieben habe...
Die "for" schleife, so wie sie da oben steht, performt sehr gut.

Das einzigste Problem was ich hier habe ist, dass "usleep" nicht zu
funktionieren scheint wie erwartet. Die Schleife läuft perfekt, nur das
ich 10% CPU auslastung pro Benutzer habe, wenn ich keine
Wartefunktion einbaue, die die Schleife bremst.

Ich wusste garnicht, dass da in den User Comments Beispiele für nen Datei Download sind.
Naja ändert aber auch wieder nichts daran, dass fread mir die 10% COU auslastung nicht erspart.

Gibt es eine andere Wartefunktion die ich anstatt "usleep" benutzen kann?
Klar sleep aber die kann ich ja nicht benutzen, muss schon mindestens runter auf Millisekunden.

Best wishes
FBIagent
 
Zuletzt bearbeitet:
Zurück