File indexing completed on 2024-12-22 05:37:14
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Wildfire 0017 * @subpackage Channel 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 /** Zend_Wildfire_Channel_Interface */ 0024 // require_once 'Zend/Wildfire/Channel/Interface.php'; 0025 0026 /** Zend_Controller_Request_Abstract */ 0027 // require_once('Zend/Controller/Request/Abstract.php'); 0028 0029 /** Zend_Controller_Response_Abstract */ 0030 // require_once('Zend/Controller/Response/Abstract.php'); 0031 0032 /** Zend_Controller_Plugin_Abstract */ 0033 // require_once 'Zend/Controller/Plugin/Abstract.php'; 0034 0035 /** Zend_Wildfire_Protocol_JsonStream */ 0036 // require_once 'Zend/Wildfire/Protocol/JsonStream.php'; 0037 0038 /** Zend_Controller_Front **/ 0039 // require_once 'Zend/Controller/Front.php'; 0040 0041 /** 0042 * Implements communication via HTTP request and response headers for Wildfire Protocols. 0043 * 0044 * @category Zend 0045 * @package Zend_Wildfire 0046 * @subpackage Channel 0047 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0048 * @license http://framework.zend.com/license/new-bsd New BSD License 0049 */ 0050 class Zend_Wildfire_Channel_HttpHeaders extends Zend_Controller_Plugin_Abstract implements Zend_Wildfire_Channel_Interface 0051 { 0052 /** 0053 * The string to be used to prefix the headers. 0054 * @var string 0055 */ 0056 protected static $_headerPrefix = 'X-WF-'; 0057 0058 /** 0059 * Singleton instance 0060 * @var Zend_Wildfire_Channel_HttpHeaders 0061 */ 0062 protected static $_instance = null; 0063 0064 /** 0065 * The index of the plugin in the controller dispatch loop plugin stack 0066 * @var integer 0067 */ 0068 protected static $_controllerPluginStackIndex = 999; 0069 0070 /** 0071 * The protocol instances for this channel 0072 * @var array 0073 */ 0074 protected $_protocols = null; 0075 0076 /** 0077 * Initialize singleton instance. 0078 * 0079 * @param string $class OPTIONAL Subclass of Zend_Wildfire_Channel_HttpHeaders 0080 * @return Zend_Wildfire_Channel_HttpHeaders Returns the singleton Zend_Wildfire_Channel_HttpHeaders instance 0081 * @throws Zend_Wildfire_Exception 0082 */ 0083 public static function init($class = null) 0084 { 0085 if (self::$_instance !== null) { 0086 // require_once 'Zend/Wildfire/Exception.php'; 0087 throw new Zend_Wildfire_Exception('Singleton instance of Zend_Wildfire_Channel_HttpHeaders already exists!'); 0088 } 0089 if ($class !== null) { 0090 if (!is_string($class)) { 0091 // require_once 'Zend/Wildfire/Exception.php'; 0092 throw new Zend_Wildfire_Exception('Third argument is not a class string'); 0093 } 0094 0095 if (!class_exists($class)) { 0096 // require_once 'Zend/Loader.php'; 0097 Zend_Loader::loadClass($class); 0098 } 0099 0100 self::$_instance = new $class(); 0101 0102 if (!self::$_instance instanceof Zend_Wildfire_Channel_HttpHeaders) { 0103 self::$_instance = null; 0104 // require_once 'Zend/Wildfire/Exception.php'; 0105 throw new Zend_Wildfire_Exception('Invalid class to third argument. Must be subclass of Zend_Wildfire_Channel_HttpHeaders.'); 0106 } 0107 } else { 0108 self::$_instance = new self(); 0109 } 0110 0111 return self::$_instance; 0112 } 0113 0114 0115 /** 0116 * Get or create singleton instance 0117 * 0118 * @param bool $skipCreate True if an instance should not be created 0119 * @return Zend_Wildfire_Channel_HttpHeaders 0120 */ 0121 public static function getInstance($skipCreate=false) 0122 { 0123 if (self::$_instance===null && $skipCreate!==true) { 0124 return self::init(); 0125 } 0126 return self::$_instance; 0127 } 0128 0129 /** 0130 * Destroys the singleton instance 0131 * 0132 * Primarily used for testing. 0133 * 0134 * @return void 0135 */ 0136 public static function destroyInstance() 0137 { 0138 self::$_instance = null; 0139 } 0140 0141 /** 0142 * Get the instance of a give protocol for this channel 0143 * 0144 * @param string $uri The URI for the protocol 0145 * @return object Returns the protocol instance for the diven URI 0146 */ 0147 public function getProtocol($uri) 0148 { 0149 if (!isset($this->_protocols[$uri])) { 0150 $this->_protocols[$uri] = $this->_initProtocol($uri); 0151 } 0152 0153 $this->_registerControllerPlugin(); 0154 0155 return $this->_protocols[$uri]; 0156 } 0157 0158 /** 0159 * Initialize a new protocol 0160 * 0161 * @param string $uri The URI for the protocol to be initialized 0162 * @return object Returns the new initialized protocol instance 0163 * @throws Zend_Wildfire_Exception 0164 */ 0165 protected function _initProtocol($uri) 0166 { 0167 switch ($uri) { 0168 case Zend_Wildfire_Protocol_JsonStream::PROTOCOL_URI; 0169 return new Zend_Wildfire_Protocol_JsonStream(); 0170 } 0171 // require_once 'Zend/Wildfire/Exception.php'; 0172 throw new Zend_Wildfire_Exception('Tyring to initialize unknown protocol for URI "'.$uri.'".'); 0173 } 0174 0175 0176 /** 0177 * Flush all data from all protocols and send all data to response headers. 0178 * 0179 * @return boolean Returns TRUE if data was flushed 0180 */ 0181 public function flush() 0182 { 0183 if (!$this->_protocols || !$this->isReady()) { 0184 return false; 0185 } 0186 0187 foreach ( $this->_protocols as $protocol ) { 0188 0189 $payload = $protocol->getPayload($this); 0190 0191 if ($payload) { 0192 foreach( $payload as $message ) { 0193 0194 $this->getResponse()->setHeader(self::$_headerPrefix.$message[0], 0195 $message[1], true); 0196 } 0197 } 0198 } 0199 return true; 0200 } 0201 0202 /** 0203 * Set the index of the plugin in the controller dispatch loop plugin stack 0204 * 0205 * @param integer $index The index of the plugin in the stack 0206 * @return integer The previous index. 0207 */ 0208 public static function setControllerPluginStackIndex($index) 0209 { 0210 $previous = self::$_controllerPluginStackIndex; 0211 self::$_controllerPluginStackIndex = $index; 0212 return $previous; 0213 } 0214 0215 /** 0216 * Register this object as a controller plugin. 0217 * 0218 * @return void 0219 */ 0220 protected function _registerControllerPlugin() 0221 { 0222 $controller = Zend_Controller_Front::getInstance(); 0223 if (!$controller->hasPlugin(get_class($this))) { 0224 $controller->registerPlugin($this, self::$_controllerPluginStackIndex); 0225 } 0226 } 0227 0228 0229 /* 0230 * Zend_Wildfire_Channel_Interface 0231 */ 0232 0233 /** 0234 * Determine if channel is ready. 0235 * 0236 * The channel is ready as long as the request and response objects are initialized, 0237 * can send headers and the FirePHP header exists in the User-Agent. 0238 * 0239 * If the header does not exist in the User-Agent, no appropriate client 0240 * is making this request and the messages should not be sent. 0241 * 0242 * A timing issue arises when messages are logged before the request/response 0243 * objects are initialized. In this case we do not yet know if the client 0244 * will be able to accept the messages. If we consequently indicate that 0245 * the channel is not ready, these messages will be dropped which is in 0246 * most cases not the intended behaviour. The intent is to send them at the 0247 * end of the request when the request/response objects will be available 0248 * for sure. 0249 * 0250 * If the request/response objects are not yet initialized we assume if messages are 0251 * logged, the client will be able to receive them. As soon as the request/response 0252 * objects are availoable and a message is logged this assumption is challenged. 0253 * If the client cannot accept the messages any further messages are dropped 0254 * and messages sent prior are kept but discarded when the channel is finally 0255 * flushed at the end of the request. 0256 * 0257 * When the channel is flushed the $forceCheckRequest option is used to force 0258 * a check of the request/response objects. This is the last verification to ensure 0259 * messages are only sent when the client can accept them. 0260 * 0261 * @param boolean $forceCheckRequest OPTIONAL Set to TRUE if the request must be checked 0262 * @return boolean Returns TRUE if channel is ready. 0263 */ 0264 public function isReady($forceCheckRequest=false) 0265 { 0266 if (!$forceCheckRequest 0267 && !$this->_request 0268 && !$this->_response 0269 ) { 0270 return true; 0271 } 0272 0273 if (!($this->getRequest() instanceof Zend_Controller_Request_Http)) { 0274 return false; 0275 } 0276 0277 return ($this->getResponse()->canSendHeaders() 0278 && (preg_match_all( 0279 '/\s?FirePHP\/([\.\d]*)\s?/si', 0280 $this->getRequest()->getHeader('User-Agent'), 0281 $m 0282 ) || 0283 (($header = $this->getRequest()->getHeader('X-FirePHP-Version')) 0284 && preg_match_all('/^([\.\d]*)$/si', $header, $m) 0285 )) 0286 ); 0287 } 0288 0289 0290 /* 0291 * Zend_Controller_Plugin_Abstract 0292 */ 0293 0294 /** 0295 * Flush messages to headers as late as possible but before headers have been sent. 0296 * 0297 * @return void 0298 */ 0299 public function dispatchLoopShutdown() 0300 { 0301 $this->flush(); 0302 } 0303 0304 /** 0305 * Get the request object 0306 * 0307 * @return Zend_Controller_Request_Abstract 0308 * @throws Zend_Wildfire_Exception 0309 */ 0310 public function getRequest() 0311 { 0312 if (!$this->_request) { 0313 $controller = Zend_Controller_Front::getInstance(); 0314 $this->setRequest($controller->getRequest()); 0315 } 0316 if (!$this->_request) { 0317 // require_once 'Zend/Wildfire/Exception.php'; 0318 throw new Zend_Wildfire_Exception('Request objects not initialized.'); 0319 } 0320 return $this->_request; 0321 } 0322 0323 /** 0324 * Get the response object 0325 * 0326 * @return Zend_Controller_Response_Abstract 0327 * @throws Zend_Wildfire_Exception 0328 */ 0329 public function getResponse() 0330 { 0331 if (!$this->_response) { 0332 $response = Zend_Controller_Front::getInstance()->getResponse(); 0333 if ($response) { 0334 $this->setResponse($response); 0335 } 0336 } 0337 if (!$this->_response) { 0338 // require_once 'Zend/Wildfire/Exception.php'; 0339 throw new Zend_Wildfire_Exception('Response objects not initialized.'); 0340 } 0341 return $this->_response; 0342 } 0343 }