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 }