* @license PHP License * @package WB * @subpackage base */ WBClass::load( 'WBResponse' ); /** * HTTP response class * * Improved output header * * @version 0.4.0 * @package WB * @subpackage base */ class WBResponse_Http extends WBResponse { /** * request path * @var string */ protected $_path = '/'; /** * start * */ public function __construct() { $this->_header['Content-Type'] = 'text/html; charset=utf-8;'; } /** * thing send * * @param WBRequest $request * @return bool true un success */ protected function onSend( WBRequest $request ) { $this->_path = $request->path; // caching header $cacheControl = WBResponse::CACHECONTROL_MUSTREVALIDATE; $pragma = 'no-cache'; if( $this->_useCache ) { $pragma = 'cache'; // check browser cache if( $request->getMeta('HTTP_IF_NONE_MATCH') === $this->_checksum) { $this->setStatus(304); return true; } // add vary header $this->addHeader('Vary', 'User-Agent, Accept, Accept-Encoding, Accept-Language, Cookie'); if ($this->expireAge) { $cacheControl = 'max-age: '.strval($this->expireAge).', ' . $this->cacheControl; $this->addHeader('Expires', gmdate('D, j M Y H:i:s', time() + $this->expireAge) . ' GMT'); } $this->addHeader('ETag', $this->_checksum); } $this->addHeader('Cache-Control', $cacheControl); $this->addHeader('Pragma', $pragma); $this->addHeader('Content-MD5', $this->_checksum); // check content type to activate string replace $cType = explode(';', $this->_header['Content-Type'], 2); $cType = array_shift($cType); $cType = explode('/', $cType); if ($cType[0] == 'text' || $cType[1] == 'x-javascript') { $this->addOutputFilter( array( $this, 'filterStringReplace' ) ); } /* * generic compression filters are not suitable for mixed streaming content * @todo reconsider whether compression works anyway */ $zip = true; $last = $this->_data[0]['type']; foreach ($this->_data as $d) { if ($d['type'] != $last) { $zip = true; break; } } if ($zip) { $this->checkCompression( $request ); } return true; } /** * send header * * @return bool true on success */ protected function sendHeader() { $this->addHeader( 'HTTP/1.1', $this->_responseStatus . ' ' . $this->_statusCodes[$this->_responseStatus]['msg'] ); foreach( $this->_header as $name => $value ) { if( $value === null ) { header( $name ); } else { header( $name.': '.$value ); } } return true; } /** * Allow output compression * * Check whether out compression may be used and add output filter: gzip or deflate * * @return bool true on success */ protected function checkCompression( $request ) { // check config if (!WBParam::get('wb/response/compress', 1)) { return true; } // check if deflate is accepted from client $acceptEncoding = explode(',', trim($request->getMeta( 'HTTP_ACCEPT_ENCODING'))); $this->_compressor = null; // get accepted client encodings if (in_array('gzip', $acceptEncoding)) { $this->addOutputFilter(array($this, 'filterCompress')); $this->_compressor = 'gzip'; return true; } if (in_array('deflate', $acceptEncoding)) { $this->addOutputFilter(array($this, 'filterCompress')); $this->_compressor = 'deflate'; return true; } return true; } /** * Global string replace * * * @param string $in * @return string $out */ public function filterStringReplace($in) { WBClass::load('WBString'); return WBString::replaceSuperPlaceholders($in, $this->_path); } /** * Applay output filter: compress * * Either gzip or deflate * * @param string $in * @return string $out */ public function filterCompress($in) { if (!$this->_compressor) { // this should never happen return $in; } // compression does not make sense for little data if (strlen($in) < 500) { return $in; } // compress switch ($this->_compressor) { case 'gzip': $this->addHeader('Content-Encoding', 'gzip'); return gzencode($in); break; case 'deflate': $this->addHeader('Content-Encoding', 'deflate'); return gzdeflate($in); break; default: break; } return $in; } } ?>