Enabling Gzip

Adding HTTP compression to your application could never have been easier!

Just insert the following two lines to your configuration array, and PHP will do the rest.

'onBeginRequest'=>create_function('$event', 'return ob_start("ob_gzhandler");'),
'onEndRequest'=>create_function('$event', 'return ob_end_flush();'),

An overview about this:

  • PHP's create_function will create lambda functions in runtime, so you don't have to worry about external files. It'll take the parameter list and the internal code, respectively, and return the newly added function name, which will serve here as callbacks.
  • Indexing these items as onBeginRequest and onEndRequest will trigger attaching callbacks to application events.
  • Event handlers are even acceptable since they'll take the event object as first argument.
  • Please visit official PHP site for more information regarding ob_start and ob_gzhandler. In summary, the latter will check whether the client is compatible with gzipped content, set the Content-Encoding header and compress all the content generated during processRequest accordingly.
  • If the current browser is not capable of uncompressing gzip, gzhandler will leave the output untouched.

(If you need additional functionality, you may want to create a separate file for these functions.)

Links

Chinese version

Total 9 comments:

#463
style points
by jonah at 7:36pm on July 11, 2009.

you get style points for doing all this with only two lines of code... nice!

#464
Thank you!
by pestaa at 7:54am on July 12, 2009.

I like it compressed. ;) Thanks Jonah!

#467
you da man
by streetdaddy at 7:20pm on July 12, 2009.

you're right, it can't get any easier! great work :)

#479
errors
by Javache at 7:52am on July 18, 2009.

Too bad it kind of breaks when you get an error page (http://www.yiiframework.com/forum/index.php/topic,3341.msg18059.html#msg18059)

#494
Performance
by Ismael at 7:35pm on July 23, 2009.

Like it!

I just want some feedback is this causes any significant overhead or is just fine...

#502
Ismael,
by pestaa at 7:56am on July 27, 2009.

There is no performance sacrifice. Low level gzipping is always worth implementing.

#657
apache gzip
by Ismael at 9:04pm on September 13, 2009.

Can't we solve this with apache module? Isn't better?

Take a look in .htaccess:

AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/x-javascript

#700
mistakes on coding
by resplendent at 10:46pm on October 1, 2009.

I think your code have some mistakes. onBeginRequest and onEndRequest are void functions so don't require to return the ob_start and ob_end_flush values.

solution: 'onBeginRequest'=>create_function('$event','ob_start("ob_gzhandler");'), 'onEndRequest'=>create_function('$event','ob_end_flush();'),

#1047
Solution to the firefox problem
by ScallioXTX at 1:58am on January 26, 2010.

When using this method, Firefox gives the following error when an exception is raised:

"The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression."

The problem occurs because CErrorHandler closes all output buffers, so the output is no longer gzipped, but the ob_start('ob_gzhandler') in onApplicationBegin has already sent the header that page is gzip compressed. So you get the situation that the HTTP headers tell firefox that the content is gzipped, while in fact it is not.

This can be resolved by setting CErrorHandler::errorAction to something like "site/error" and then implement this action in the SiteController class.

In the config:

return array(
  ...
  'components' => array(
    'errorHandler' => array(
      'errorAction' => 'site/error'
      ...
    )
  )
);

In the SiteController:

public function actionError()
{
  ob_start('ob_gzhandler');
  if(Yii::app()->errorHandler->error)
  {
    $error = Yii::app()->errorHandler->error;
  }
  // handle the error here
}

We call ob_start('ob_gzhandler') here again so the content is gzipped, which solves the problem.

An alternative approach (not tested, but should work theoretically) is to extend the CErrorHandler class like so

class MyErrorHandler extends CErrorHandler
{
  protected function render($view,$data)
  {
    ob_start('ob_gzhandler');
    parent::render($view,$data);
  }
}


and in the config:

return array(
 ...
  'components' => array(
    'errorHandler' => array(
      'class' => 'path.to.MyErrorHandler'
      ...
    )
  )
);

Your Comment:

You may enter comment using Markdown syntax.

Please login with your forum account.
Note: you must have at least ONE forum post with your account.