Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [php] output buffer
Forum PHP.pl > Forum > PHP
Remi
Witam, nie mogę sobie poradzić z buforowaniem obrazka. Chciałbym, żeby był on w całości wysyłany do przeglądarki zanim zakończy się praca skryptu. Mam taki kod:
  1. <?php
  2. while(@ob_end_clean());
  3. header("Pragma: no-cache");
  4. header("Cache-Control: no-cache");
  5. header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
  6. header("Cache-Control: must-revalidate");
  7. header('Content-Type: image/png');
  8. readfile('/some/directory/obrazek.png');
  9. $buffer = ob_get_contents();
  10. echo $buffer;
  11. sleep(3);
  12. ?>

  1. <?php
  2. while(@ob_end_clean());
  3. $im = imagecreatefrompng('/some/directory/obrazek.png');
  4. header("Pragma: no-cache");
  5. header("Cache-Control: no-cache");
  6. header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
  7. header("Cache-Control: must-revalidate");
  8. header('Content-Type: image/png');
  9. imagepng($im);
  10. $buffer = ob_get_contents();
  11. echo $buffer;
  12. imagedestroy($im);
  13. sleep(3);
  14. ?>

W obydwu przypadkach nie pojawia się on od razu w całości (obrazek ma 3.7KB). Brakująca część pojawia się dopiero po zakończeniu pracy skryptu. W tym drugim przypadku trochę mniej go brakuje ale wciąż nie pojawia się od razu cały... jakieś sugestie? co_jest.gif
Crozin
ob_flush?
Remi
Dodanie ob_flush() przed sleepem nic nie daje, nadal brakującą część pojawia się dopiero po zakończeniu pracy skryptu.
Crozin
Wykonaj ob_flush w połączeniu z flush (patrz: pierwszy komentarz z dokumentacji pierwszej funkcji). Sprawdź też czy w ogóle podany przykład Ci działa.
Remi
Trochę kombinowałem z tym ob_flush() i flush() ale to nie robi tego co powinno. Obrazek ładuje się w całości tylko dlatego, ze ob_flush generuje „Notice: ob_flush(): failed to flush buffer. No buffer to flush.” zaraz po wysłaniu obrazka (widać to gdy skrypt odpali się z terminala). Jeśli dam @ob_flush() albo wyłączę notice (a tak będzie na produkcyjnym) to nadal jest to samo, obrazek nie ładuje się cały.
  1. # \|/ TAK DZIAŁA \|/
  2. $im = imagecreatefrompng('/some/directory/obrazek.png');
  3. header('Pragma: no-cache');
  4. header('Cache-Control: no-cache');
  5. header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
  6. header('Cache-Control: must-revalidate');
  7. header('Content-Type: image/png');
  8. while(@ob_end_clean());
  9. imagepng($im);
  10. imagedestroy($im);
  11. $buffer = ob_get_contents();
  12. echo $buffer;
  13. ob_flush(); # <- BO TO GENERUJE NOTICE
  14. sleep(2);
  15.  
  16. # \|/ TAK NIE DZIAŁA \|/
  17. $im = imagecreatefrompng('/some/directory/obrazek.png');
  18. header('Pragma: no-cache');
  19. header('Cache-Control: no-cache');
  20. header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
  21. header('Cache-Control: must-revalidate');
  22. header('Content-Type: image/png');
  23. while(@ob_end_clean());
  24. imagepng($im);
  25. imagedestroy($im);
  26. $buffer = ob_get_contents();
  27. echo $buffer;
  28. ob_flush(); # <- BO TO PRZESTAŁO GENEROWAC NOTICE
  29. sleep(2);
  30.  
  31. # \|/ TAK TEZ NIE DZIAŁA \|/
  32. $im = imagecreatefrompng('/some/directory/obrazek.png');
  33. header('Pragma: no-cache');
  34. header('Cache-Control: no-cache');
  35. header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
  36. header('Cache-Control: must-revalidate');
  37. header('Content-Type: image/png');
  38. while(@ob_end_clean());
  39. imagepng($im);
  40. imagedestroy($im);
  41. $buffer = ob_get_contents();
  42. echo $buffer;
  43. @ob_flush(); # <- BO TO PRZESTAŁO GENEROWAC NOTICE
  44. sleep(2);


Ma ktoś jakiś pomyśl, jak poprawnie zmusić ten skrypt do wyplucia całego obrazka gdy jest wyłączone raportowanie błędów? sciana.gif
Crozin
Zrobiłem prosty test: (Apache 2.2.x)
  1. <?php
  2.  
  3.  
  4. header('Pragma: no-cache');
  5. header('Cache-Control: no-cache');
  6. header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
  7. header('Cache-Control: must-revalidate');
  8. header('Content-Type: image/png');
  9.  
  10. file_put_contents("tmp.log", "Start - " . microtime(true) . PHP_EOL, FILE_APPEND);
  11.  
  12. $fh = fopen("logo.png", "rb");
  13. while (!feof($fh)) {
  14. echo fread($fh, 1024);
  15. file_put_contents("tmp.log", "Reading... " . microtime(true) . PHP_EOL, FILE_APPEND);
  16.  
  17. flush();
  18. sleep(1);
  19. }
  20.  
  21. fclose($fh);
  22. file_put_contents("tmp.log", "Closing - " . microtime(true) . PHP_EOL, FILE_APPEND);
  23.  
  24. sleep(2);
  25. file_put_contents("tmp.log", "Some extra code - " . microtime(true) . PHP_EOL, FILE_APPEND);
Efekt:
Kod
Start - 1344208985.1088
Reading... 1344208985.1341
Reading... 1344208986.1352
Reading... 1344208987.1372
Reading... 1344208988.1402
Reading... 1344208989.1463
Reading... 1344208990.2127
Reading... 1344208991.2143
Closing - 1344208992.2164
Some extra code - 1344208994.2185
A przeglądarka oczywiście wyświetla kolejne fragmenty obrazka.

Sprawdź czy powyższy kod zadziała u Ciebie, jeżeli nie sugerowałoby to problemy z konfiguracją serwera HTTP, ale z tym już pomóc nie jestem wstanie. wink.gif
Remi
Wielkie dzięki, rzeczywiście problem leży po stronie serwera (nginx) a nie po stronie php. Gdyby ktoś kiedyś miał z tym także problem to tu jest info jak zmniejszyc bufor w nginx: PHP NGINX OUTPUT FLUSHING
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.