Yii 1.1: Enabling Gzip

13 followers

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.)

Total 5 comments

#7642 report it
gcaplan at 2012/04/04 10:31am
This may not be the best approach

Please note that the PHP manual says:

You cannot use both ob_gzhandler() and zlib.output_compression. Also note that using zlib.output_compression is preferred over ob_gzhandler().

#7383 report it
tofsjonas at 2012/03/19 05:52am
Lovely!

Thanks :)

#3849 report it
atrandafir at 2011/05/13 11:20am
Possible solution to firefox problem

Hi ScallioXTX and others,

I also had the compression problem when the application had to display an error with the action site/error from the errorHandler.

I looked at the file framework/base/CErrorHandler.php and found the $discardOutput property that does an ob_end_clean(), I don't really understand what this php function does in this case, I sopose it clears all the previous buffer before sending the new error page.

/**
 * @var boolean whether to discard any existing page output before error display. Defaults to true.
 */
public $discardOutput=true;
/**
 * @var string the route (e.g. 'site/error') to the controller action that will be used to display external errors.
 * Inside the action, it can retrieve the error information by Yii::app()->errorHandler->error.
 * This property defaults to null, meaning CErrorHandler will handle the error display.
 * @since 1.0.6
 */
public $errorAction;
 
private $_error;
 
/**
 * Handles the exception/error event.
 * This method is invoked by the application whenever it captures
 * an exception or PHP error.
 * @param CEvent the event containing the exception/error information
 */
public function handle($event)
{
  // set event as handled to prevent it from being handled by other event handlers
  $event->handled=true;
 
  if($this->discardOutput)
  {
    while(@ob_end_clean()) ;
  }
 
  if($event instanceof CExceptionEvent)
    $this->handleException($event->exception);
  else // CErrorEvent
    $this->handleError($event);
}

Well if you set discardOutput to false from the config it will not give you the compression problem anymore:

'errorHandler' => array(
  // use 'site/error' action to display errors
  'errorAction' => 'site/error',
  'discardOutput' => false,
),

Hope it helps someone!

#109 report it
Terry at 2010/09/13 11:21am
I find a new way,we can you Behavior

<?php class WebBehavior extends CBehavior{ public function events(){ return array( 'onBeginRequest'=>'beginRequest', 'onEndRequest'=>'endRequest' ); }

public function beginRequest(){
    return ob_start("ob_gzhandler");
}

public function endRequest(){
    return ob_end_flush();
}

}

then in index.php modify this line as Yii::createWebApplication($config)->run();

$app = Yii::createWebApplication($config); $app->attachBehavior('WebBehavior','application.behavior.WebBehavior'); $app->run();

#933 report it
ScallioXTX at 2010/01/26 06:58am
Solution to the firefox problem

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'
      ...
    )
  )
);

Leave a comment

Please to leave your comment.

Write new article
  • Written by: pestaa
  • Updated by: Yang He
  • Category: Tutorials
  • Yii Version: 1.1
  • Votes: +5 / -1
  • Viewed: 15,810 times
  • Created on: Jul 10, 2009
  • Last updated: Jun 29, 2012