[PHP] 1 File downloadlimiet script sessions probleem.

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • ^Ripper
  • Registratie: December 2000
  • Laatst online: 20-07 16:49
Ik heb een probleem met een script dat ik heb gemaakt om maar 1 file download tegelijk toe te staan.
Mijn webhost wil namelijk niet de apache module mod_throttle.c of iets dergelijks installeren, dus moet ik zelf maar iets verzinnen.
Het probleem was namelijk dat leechers zoveel files tegelijk met zoveel threads downloaden dat de server op z'n kont ging.

Ik heb veel gezien op php.net en hier op tweakers en heb het volgende in elkaar geknutseld.

Download.php
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?php
session_start();
error_reporting(E_ALL);

// Session variable check
if (!isset($_SESSION['download_started'])){
    echo ("Downloadcheck variable not set");
    exit;
}

// Session downloadcheck
if ($_SESSION['download_started'] == 'started' ) {
    echo ("Downloadcheck: download in progress");
    exit;
}

// Filecheck en download
ignore_user_abort( true );
if (file_exists($file)){
    header("Pragma: ");
    header("Cache-Control: ");
    header("Content-type: application/octet-stream"); 
    header("Content-Transfer-Encoding: binary"); 
    header("Content-Disposition: attachment; filename=\"$file\""); 
    header("Content-length: ".filesize($file)); 
    header("Connection: close");
    ob_flush();
    flush();
    $handle = fopen($file, "rb");
    if ($handle === false) {
        return false;
    }
    while(!feof($handle) || connection_status()!=0 ) {
        echo fread($handle, (1*(1024*1024)));
        ob_flush();
        flush();
        session_start();
        $_SESSION['download_started'] = 'started';
        session_write_close();
    }
    fclose ($handle); 
    session_start();
    $_SESSION['download_started'] = 'stopped';
    session_write_close();
    exit;
}
else {
    echo ("File Not Found");
    exit;
}
echo ("End of script error");
exit;
?>

In de html is de aanroep download.php?file=blaat.zip
de html (.php eigenlijk) heeft bij alle pagina's de volgende code gevolgd door de html.
PHP:
1
2
3
4
5
6
7
<?php
session_start();
if (!isset($_SESSION['download_started'])) {
    $_SESSION['download_started'] = 'stopped';
}
@session_write_close();
?>

Nu werkt het script voor het grootste gedeelte, maar om een reden wordt de session onder fclose gedaan tijdens het downloaden terwijl hij nog in de while loop zit.
Hierdoor kunnen gewoon meerdere bestanden tegelijk worden gedownload.
Haal ik die session weg, dan is de 2e download geblockt.
Mijn php kennis is erg matig maar waar maak ik hier een denkfout?

[ Voor 18% gewijzigd door ^Ripper op 03-07-2005 13:05 ]


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Even wat opmerkingen hoor:
• Waar komt $file vandaan? Ik zie nergens dat je die vult vanuit de $_GET-array.
• Waarom start je op meerdere plaatsen op dezelfde pagina een sessie met session_start?
• Waarom sla je strings op en geen booleans in $_SESSION['download_started']?
• Waarom gebruik je niet fpassthru?
• Waarom flush je een output buffer die je nergens start?
En nog een algemene opmerking:
• Waarom gebruik je sessions? De gebruiker hoeft zijn sessiecookie maar te verwijderen, en hij kan weer meer downloaden...

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • ^Ripper
  • Registratie: December 2000
  • Laatst online: 20-07 16:49
Die $file komt van een <A HREF="download.php?file=blaat.zip">
Dat met die sessionstart is omdat ik session_write_close heb gebruikt.
Die session_write_close om de sessie data te schrijven (kick me if i'm wrong)
De strings ipv booleans = ehhh dom :P (had het eerder in booleans maar vervangen om de vout te vinden)
Ik gebruikgeen fpassthru omdat ik de output in chunks moet hebben (had klachten van host omdat het php geheugen verbruik te hoog was) zie ook de flush() obflush()
De eerste flush is om de headers naar de browsers te flushen (heb ik van php.net)
De tweede in de while loop om het geheugen van de server te sparen (anders leest ie het hele bestand in ipv kleine chunks) ook van php.net
Dat van die sessioncookies weet ik dat het makelijk te omzeilen is, maar er hangt ook een database check achter die dat weer opvangt.
Maar die code is niet relevant en heb ik ook niet in mijn code opgenomen om te testen.

Acties:
  • 0 Henk 'm!

Verwijderd

Ripper5555 schreef op zondag 03 juli 2005 @ 13:42:
Die $file komt van een <A HREF="download.php?file=blaat.zip">
Oh, dat is wel handig dan.

http://www.domein.com/download.php?file=/etc/passwd

Of misschien wil ik wel de PHP files downloaden, er staat vast wel ergens een MySQL wachtwoord, of misschien zijn er nog meer lekken? :)

Verder gaat je script niet zo best werken als de client geen cookies accepteert.

[ Voor 13% gewijzigd door Verwijderd op 03-07-2005 13:52 ]


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Ripper5555 schreef op zondag 03 juli 2005 @ 13:42:
Die $file komt van een <A HREF="download.php?file=blaat.zip">
Dan nog moet je die variabele uit de $_GET-array ophalen. Volgens mij staat op je host register_globals op on, wat nogal slecht is... Lees P&W FAQ - PHP: gebruik van superglobals even door. :) Daarnaast heeft Cheatah een goed punt over je beveiliging: die is niet al te best zo. ;)
Dat met die sessionstart is omdat ik session_write_close heb gebruikt.
Die session_write_close om de sessie data te schrijven (kick me if i'm wrong)
Laat gewoon de sessie open tot het eind van de pagina. Je hoeft niet elke keer nadat je wat in een $_SESSION-var stopt de variabelen weg te schrijven met die functie hoor. ;)
De strings ipv booleans = ehhh dom :P (had het eerder in booleans maar vervangen om de vout te vinden)
Ok, ik zou er dus in elk geval booleans van maken. :)
Ik gebruikgeen fpassthru omdat ik de output in chunks moet hebben (had klachten van host omdat het php geheugen verbruik te hoog was) zie ook de flush() obflush()
Ah, op die manier. :) Dan zou dit inderdaad wat beter kunnen zijn, al betwijfel ik of het sneller is. :)
De eerste flush is om de headers naar de browsers te flushen (heb ik van php.net)
Bij mijn weten moet je eerst een output buffer starten (met ob_start) voordat je hem kan sluiten.
De tweede in de while loop om het geheugen van de server te sparen (anders leest ie het hele bestand in ipv kleine chunks) ook van php.net
Die chunks hebben niets met output buffering te maken. De output buffer is gewoon, zoals de naam al zegt, een buffer waarin alle uitvoer die naar de browser moet worden gestuurd opgeslagen wordt.
Dat van die sessioncookies weet ik dat het makelijk te omzeilen is, maar er hangt ook een database check achter die dat weer opvangt.
Dat klinkt al beter ja. :P

[ Voor 3% gewijzigd door NMe op 03-07-2005 13:58 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • ^Ripper
  • Registratie: December 2000
  • Laatst online: 20-07 16:49
Die beveiligings risico's zijn duidelijk, in mijn huidige script worden ze dan ook via id's aangesproken en word het nakekeken met een eregi('[_a-z0-9-]+)
Ik heb ook wat code moeten veranderen om het bovenstaande zo klein mogelijk te houden.
Het ging daarom ook een beetje waarom die session na de while loop aangesproken word terwijl er gedownload word.

Het is lastig om het in woorden uit te leggen als je alles in je kop hebt zitten...

Acties:
  • 0 Henk 'm!

Verwijderd

Ripper5555 schreef op zondag 03 juli 2005 @ 14:16:

Het ging daarom ook een beetje waarom die session na de while loop aangesproken word terwijl er gedownload word.
Omdat het script klaar is met alles naar de output buffer te schrijven, en dus gewoon verder kan? Dat wil niet zeggen dat alle content al bij de client is natuurlijk.
Pagina: 1