From 1d3baedf5ac9a388c707787801359775c51b5289 Mon Sep 17 00:00:00 2001 From: Daniel Richter Date: Tue, 3 Nov 2015 16:56:55 -0800 Subject: [PATCH] Add BufferBusting echo handler When you serve PHP via FCGI, you can experience buffering which is very hard/impossible to get rid of. This PR adds an EchoHandler which outputs whitespace ahead of the payload to trigger a buffer flush for each event. The fix is tested in production and confirmed to work without side-effects. --- README.md | 9 +++++ .../EventSource/BufferBustingEchoHandler.php | 38 +++++++++++++++++++ .../BufferBustingEchoHandlerTest.php | 31 +++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 src/Igorw/EventSource/BufferBustingEchoHandler.php create mode 100644 tests/Igorw/Tests/EventSource/BufferBustingEchoHandlerTest.php diff --git a/README.md b/README.md index 94bb14d..4d7ae51 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,15 @@ You just pass it to the constructor of the stream: $stream = new Stream($handler); ``` +If you serve PHP via FCGI, you may run into buffering issues, preventing +individual events from being sent to the browser as they are being issued. +For this case the library includes a "BufferBusting" handler which outputs +a configurable amount of whitespace before the actual event data. + +While this does not interfere with the protocol, it obviously adds some +overhead to the network connection. Only choose this option if you are +unable to disable the buffers otherwise. + ### PHP time limit In some setups it may be required to remove the time limit of the script. diff --git a/src/Igorw/EventSource/BufferBustingEchoHandler.php b/src/Igorw/EventSource/BufferBustingEchoHandler.php new file mode 100644 index 0000000..81f0d0b --- /dev/null +++ b/src/Igorw/EventSource/BufferBustingEchoHandler.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Igorw\EventSource; + +/** + * This handler outputs whitespace ahead of payload to break potential buffer limits from FCGI. + */ +class BufferBustingEchoHandler extends EchoHandler +{ + /** + * @var string + */ + private $buffer; + + /** + * @param int $bufferSize + */ + public function __construct($bufferSize = 4096) + { + $this->buffer = str_repeat(" ", $bufferSize)."\n"; + } + + public function __invoke($chunk) + { + echo $this->buffer; + + parent::__invoke($chunk); + } +} diff --git a/tests/Igorw/Tests/EventSource/BufferBustingEchoHandlerTest.php b/tests/Igorw/Tests/EventSource/BufferBustingEchoHandlerTest.php new file mode 100644 index 0000000..3e6e41e --- /dev/null +++ b/tests/Igorw/Tests/EventSource/BufferBustingEchoHandlerTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Igorw\Tests\EventSource; + +use Igorw\EventSource\BufferBustingEchoHandler; + +class BufferBustingEchoHandlerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers Igorw\EventSource\BufferBustingEchoHandler + */ + public function testInvoke() + { + $handler = new BufferBustingEchoHandler(10); + + ob_start(); + $handler('test string'); + $output = ob_get_clean(); + + $this->expectOutputString(" \ntest string", $output); + } +}