Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien
Toon posts:

[PHP] Flush / buffer probleem

Pagina: 1
Acties:

Onderwerpen


Verwijderd

Topicstarter
Tweakerts,

Lang geleden. Ik zit met een issue op een server die niet van mij. Het heeft met buffering te maken.
Probleem is dit; er staan files op een server en die moeten users kunnen downloaden. Daar moeten ze voor betalen dus daar kom je alleen aan via een PHP script.

So far so good. PHP script met de controle, wat headers en iets van fread of readfile. Allemaal koek en ei.

Echter bleken grote files (> 50MB) problemen te geven. Dat komt natuurlijk door de memory_limit van 64M ingesteld op de server. Nou dacht ik, dan lezen we hem in stukjes en flushen we de output na elke fread.... Echter lijkt hoe ik ook flush de output gebuffered te worden tot het geheugen op is, de max execution time overschreven of het uitvoeren van het script klaar is...

Om te te verifiëren deed ik zoiets;
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function flush_buffers(){
    ob_end_flush();
    ob_flush();
    flush();
    ob_start();
}

ini_set('zlib.output_compression', 0);
ini_set('implicit_flush', 1);
ini_set('output_buffering', 1);
$i = 0;

while($i < 15) {
        $i++;
        flush_buffers();
        sleep(1);
        echo date('h:i:s') . '<br />';
}


En inderdaad... Op mijn servers (zendserver / centos / redelijk default .ini) krijg je hier netjes om de seconde de tijd voor je snufferd in de browser. Op de server waar het om draait blijft hij cachen tot de tijd op is... Sterker nog zodra ik flush_buffers(); aanroep komt er helemaal niets meer uit.

Bekijk ik dit probleem van de juiste hoek? En zoja, welke settings in php.ini veroorzaken het verschil in gedrag?

[ Voor 0% gewijzigd door Woy op 15-02-2011 12:58 . Reden: Code tag aangepast ]


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
offtopic:
Ik heb je code tag even aangepast. Met [code=php] of [php] krijg je ook syntax highlighting. Voor meer informate: Overzicht van UBB-codes #tag_code

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • WouZz
  • Registratie: Mei 2000
  • Niet online

WouZz

Elvis is alive!

Output buffers kunnen genest worden. Wellicht dat er op een hoger niveau nog een buffer geïnitialiseerd wordt?

On track


Verwijderd

Topicstarter
Buiten de bovenstaande code is er geen code (voor mijn test). Of wat bedoel je met "hoger niveau"? Een andere apache module (zag trouwens dat PHP daar met fastcgi draait)?

  • Evilbee
  • Registratie: November 2002
  • Laatst online: 28-11 07:40
Als ik mijn buffers wil legen gebruik ik meestal:
PHP:
1
while(ob_end_flush());

Dan worden alle buffers geleegd en niet alleen de laatst geopende.

LinkedIn - Collega worden?


  • Guillome
  • Registratie: Januari 2001
  • Niet online

Guillome

test

What about:
PHP:
1
ini_set("memory_limit", "256M");

?

If then else matters! - I5 12600KF, Asus Tuf GT501, Asus Tuf OC 3080, Asus Tuf Gaming H670 Pro, 48GB, Corsair RM850X PSU, SN850 1TB, Arctic Liquid Freezer 280, ASUS RT-AX1800U router


Verwijderd

Topicstarter
Haha ja dat is een goeie.
Vermoed dat ik ini_set niet mag gebruiken?
Iemand een idee hoe dat zit?
Evilbee schreef op dinsdag 15 februari 2011 @ 16:26:
Als ik mijn buffers wil legen gebruik ik meestal:
PHP:
1
while(ob_end_flush());

Dan worden alle buffers geleegd en niet alleen de laatst geopende.
Ja dat is een goeie. Alleen is er in deze situatie geen andere code dan de hierboven getoonde...

[ Voor 65% gewijzigd door Verwijderd op 15-02-2011 17:01 ]


  • kwaakvaak_v2
  • Registratie: Juni 2009
  • Laatst online: 10-10 08:02
ja of je haalt gewoon de file op met een fread en doet zelf wat aan buffering. Heb je die hele ob_* dingen ook niet nodig ;)

RTFM enzo ;)

Driving a cadillac in a fool's parade.


Verwijderd

Topicstarter
Wat bedoel je met doet zelf wat aan buffering?
Ik kan de file niet in 1x inlezen heb je de post gelezen?
En wat heeft het hele probleem met fread te maken....

[ Voor 22% gewijzigd door Verwijderd op 15-02-2011 17:59 ]


  • WouZz
  • Registratie: Mei 2000
  • Niet online

WouZz

Elvis is alive!

Verwijderd schreef op dinsdag 15 februari 2011 @ 16:20:
... Of wat bedoel je met "hoger niveau"? Een andere apache module (zag trouwens dat PHP daar met fastcgi draait)?
Met hoger niveau bedoel ik dus een framework of web-server. En zo te zien is de combinatie met fastcgi niet helemaal ideaal.

On track


  • Guillome
  • Registratie: Januari 2001
  • Niet online

Guillome

test

Verwijderd schreef op dinsdag 15 februari 2011 @ 16:54:
Haha ja dat is een goeie.
Vermoed dat ik ini_set niet mag gebruiken?
Waarom niet? Zie php.net

If then else matters! - I5 12600KF, Asus Tuf GT501, Asus Tuf OC 3080, Asus Tuf Gaming H670 Pro, 48GB, Corsair RM850X PSU, SN850 1TB, Arctic Liquid Freezer 280, ASUS RT-AX1800U router


  • alex3305
  • Registratie: Januari 2004
  • Laatst online: 11:27
Misschien omdat het niet de netste oplossing is? Wat gebeurt er bijvoorbeeld als 100 mensen tegelijkertijd 100MB downloaden, waarbij er maar 2GB RAM in die server hangt? Als je de documentatie namelijk goed gelezen had staat er ook het volgende:
This sets the maximum amount of memory in bytes that a script is allowed to allocate. This helps prevent poorly written scripts for eating up all available memory on a server. Note that to have no memory limit, set this directive to -1.
Waarbij ik nu refereer aan het cursieve gedeelte.

De optie welke kwaakvaak_v2 aandraagt is echter vele malen beter. Als je namelijk even de fread documentatie bekijkt zie je o.a. de volgende code staan:

PHP:
1
2
3
4
5
//start buffered download
    while(!feof($fp))
    {
        ...
    }


Ik denk dat Pieter het daar wel mee kan vinden en oplossen :).

  • Guillome
  • Registratie: Januari 2001
  • Niet online

Guillome

test

Eksjooeeeeess mie!

If then else matters! - I5 12600KF, Asus Tuf GT501, Asus Tuf OC 3080, Asus Tuf Gaming H670 Pro, 48GB, Corsair RM850X PSU, SN850 1TB, Arctic Liquid Freezer 280, ASUS RT-AX1800U router


  • ReenL
  • Registratie: Augustus 2010
  • Laatst online: 14-09-2022
ob_ functies kunnen zich nesten, alsin je gaat elke keer een level dieper "bufferen" als op server 1 buffer uit staat en op server 2 aan, dan kan je verschillen krijgen.

http://nl.php.net/manual/en/function.ob-get-level.php

  • -DarkShadow-
  • Registratie: December 2001
  • Niet online
Misschien kun je X-Sendfile gebruiken.

Specialist in:
Soldeerstations
Oscilloscoop


Verwijderd

Topicstarter
alex3305 schreef op woensdag 16 februari 2011 @ 00:37:
[...]

Misschien omdat het niet de netste oplossing is? Wat gebeurt er bijvoorbeeld als 100 mensen tegelijkertijd 100MB downloaden, waarbij er maar 2GB RAM in die server hangt? Als je de documentatie namelijk goed gelezen had staat er ook het volgende:

[...]

Waarbij ik nu refereer aan het cursieve gedeelte.

De optie welke kwaakvaak_v2 aandraagt is echter vele malen beter. Als je namelijk even de fread documentatie bekijkt zie je o.a. de volgende code staan:

PHP:
1
2
3
4
5
//start buffered download
    while(!feof($fp))
    {
        ...
    }


Ik denk dat Pieter het daar wel mee kan vinden en oplossen :).
kwaakvaak_v2 schreef op dinsdag 15 februari 2011 @ 17:42:
ja of je haalt gewoon de file op met een fread en doet zelf wat aan buffering. Heb je die hele ob_* dingen ook niet nodig ;)

RTFM enzo ;)
Ok nogmaals ik lijk niet duidelijk. Of je moet je toch even de tijd nemen om de vraag te lezen.

Zoals in mijn eerste bericht omschreven heb ik readfile vervangen door een oplossing die met fread chunks leest en flushed.

Maar het flushen werkt niet!!!! Je kunt in chunks lezen wat je wil als alles gebuffered blijft tot het einde van het script zal het geheugen nog vollopen... Vandaar het hele verhaal met het echoen van tijd ter controle....

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
 function readfile_chunked ($filename) {
  $chunksize = 1*(1024); // how many bytes per chunk
  $buffer = '';
  $handle = fopen($filename, 'rb');
  if ($handle === false) {
    return false;
  }
  while (!feof($handle)) {
    $buffer = fread($handle, $chunksize);
    // Print echo flush maakt niet uit als je gelezen had wat mijn vraag was....?
  }
  return fclose($handle);
}

werkt dus niet.

Sommige mensen....

[ Voor 25% gewijzigd door Verwijderd op 16-02-2011 13:02 ]


  • Ventieldopje
  • Registratie: December 2005
  • Laatst online: 26-11 20:53

Ventieldopje

I'm not your pal, mate!

www.maartendeboer.net
1D X | 5Ds | Zeiss Milvus 25, 50, 85 f/1.4 | Zeiss Otus 55 f/1.4 | Canon 200 f/1.8 | Canon 200 f/2 | Canon 300 f/2.8


Verwijderd

Topicstarter
-DarkShadow- schreef op woensdag 16 februari 2011 @ 10:12:
Misschien kun je X-Sendfile gebruiken.
Koning! Die kende ik nog niet... Dat is een hoopvolle oplossing.
Ga ik meteen uitproberen.

Edit: helaas die apache module is niet aanwezig in die hosted omgeving.

[ Voor 12% gewijzigd door Verwijderd op 16-02-2011 13:23 ]


  • WouZz
  • Registratie: Mei 2000
  • Niet online

WouZz

Elvis is alive!

"OutputBufferSize 0" in je mod_fcgid config lijkt de enige oplossing. En zorgen dat je geen mod_deflate hebt draaien. (Heb je toch je hoster nodig).

Een work-around is om tijdelijke download bestanden aan de maken met een unieke bestandsnaam. Deze worden dan gewoon door apache geserveerd. Voorwaarde is dat je genoeg disk space over hebt en een opruim-cron kan laten draaien.

On track


Verwijderd

Topicstarter
WouZz schreef op woensdag 16 februari 2011 @ 17:49:
"OutputBufferSize 0" in je mod_fcgid config lijkt de enige oplossing. En zorgen dat je geen mod_deflate hebt draaien. (Heb je toch je hoster nodig).

Een work-around is om tijdelijke download bestanden aan de maken met een unieke bestandsnaam. Deze worden dan gewoon door apache geserveerd. Voorwaarde is dat je genoeg disk space over hebt en een opruim-cron kan laten draaien.
Geniaal idee inderdaad. Klein issue is dat je iets van een "grace period" moet hebben voor de file. Dwz controleren op tijdstip dat de file aangemaakt is en dan schatten of nog iemand aan het downloaden is. Vervelend als de file verwijderd wordt op het moment dat je nog zit te downloaden. En het op moment dat je de user de file laat downloaden via apache heb je geen terugkoppeling meer over wanneer de download klaar is.

Nog suggestie om dat te verbeteren (dus beter dan op basis van file size & created timestamp de file niet verwijderen als cron draaid)? Cron zit namelijk wel in het hosting pakket.

  • WouZz
  • Registratie: Mei 2000
  • Niet online

WouZz

Elvis is alive!

Mja, het probleem is inderdaad dat je 1) niet weet of iemand überhaupt al een download gestart heeft, 2) of de download al voltooid is, 3) "iedereen" met de link er bij kan. Maar goed, het was dan ook niet de ideale oplossing. Wat betreft die "grace" period zou ik voor de zekerheid gewoon 10 of 24 uur doen. Eventueel kan je dat zelfs communiceren. Je kan ook zelf uitrekenen hoeveel download tijd je nodig hebt op een zeer langzame verbinding. Overigens zou ik alle gecreëerde en opgeruimde downloads wel bijhouden in een database.

Eventueel zou je ook naar S3 kunnen kijken, maar veel verschil met zelf (sym?) linkjes aanmaken is er verder niet.

On track


Verwijderd

Voor mijn site gebruik ik ook een soortgelijk fread download script alleen dan met resume ondersteuning. Voordeel is dat het bijna geen CPU kracht kost dus het werkt in de praktijk bijna net zo goed als hotlinken. Bij mij werkt het flushen wel goed dus er zit echt wat fout in je installatie. En je mist nog een sleep functie die na de flush komt
Flushen in PHP werkt echter niet altijd goed, probeer deze code maar eens:
code:
1
2
3
4
5
for($i = 0; $i < 100: $i++)
  echo '.';
  flush();
  sleep(1);
}

Je zult zien dat er soms geen puntje verschijnt en soms opeens twee. Maar dit probleem heb je niet altijd en ook niet op elk systeem. Flush() moet je dus meer als een suggestie aan de browser zien.

Verwijderd

Topicstarter
WouZz schreef op woensdag 16 februari 2011 @ 23:38:
Mja, het probleem is inderdaad dat je 1) niet weet of iemand überhaupt al een download gestart heeft, 2) of de download al voltooid is, 3) "iedereen" met de link er bij kan. Maar goed, het was dan ook niet de ideale oplossing. Wat betreft die "grace" period zou ik voor de zekerheid gewoon 10 of 24 uur doen. Eventueel kan je dat zelfs communiceren. Je kan ook zelf uitrekenen hoeveel download tijd je nodig hebt op een zeer langzame verbinding. Overigens zou ik alle gecreëerde en opgeruimde downloads wel bijhouden in een database.

Eventueel zou je ook naar S3 kunnen kijken, maar veel verschil met zelf (sym?) linkjes aanmaken is er verder niet.
Yeah het is niet voor mezelf en het is ook geen commercieel iets anders had ik ze gewoon zelf hosting aangeboden (of bij een andere partij). Ze zitten bij een of andere Americaanse hoster. Ik ga het alleen op deze manier doen voor te grote files (er is gelukkig wel voldoende opslag ruimte in het pakket). Beste oplossing die ik tot nu toe tegengekomen ben iig, waarvoor dank.

  • WouZz
  • Registratie: Mei 2000
  • Niet online

WouZz

Elvis is alive!

Ok, graag gedaan! Hopelijk heb je ook mijn opmerking over symlinkjes gezien. Mocht dat mogelijk zijn dan zit je ook niet aan die disk space beperking vast.

On track

Pagina: 1