File indexing completed on 2025-01-19 05:21:05
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_Feed_Pubsubhubbub 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** 0023 * @see Zend_Feed_Pubsubhubbub 0024 */ 0025 // require_once 'Zend/Feed/Pubsubhubbub.php'; 0026 0027 /** 0028 * @see Zend_Date 0029 */ 0030 // require_once 'Zend/Date.php'; 0031 0032 /** 0033 * @category Zend 0034 * @package Zend_Feed_Pubsubhubbub 0035 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0036 * @license http://framework.zend.com/license/new-bsd New BSD License 0037 */ 0038 class Zend_Feed_Pubsubhubbub_Subscriber 0039 { 0040 /** 0041 * An array of URLs for all Hub Servers to subscribe/unsubscribe. 0042 * 0043 * @var array 0044 */ 0045 protected $_hubUrls = array(); 0046 0047 /** 0048 * An array of optional parameters to be included in any 0049 * (un)subscribe requests. 0050 * 0051 * @var array 0052 */ 0053 protected $_parameters = array(); 0054 0055 /** 0056 * The URL of the topic (Rss or Atom feed) which is the subject of 0057 * our current intent to subscribe to/unsubscribe from updates from 0058 * the currently configured Hub Servers. 0059 * 0060 * @var string 0061 */ 0062 protected $_topicUrl = ''; 0063 0064 /** 0065 * The URL Hub Servers must use when communicating with this Subscriber 0066 * 0067 * @var string 0068 */ 0069 protected $_callbackUrl = ''; 0070 0071 /** 0072 * The number of seconds for which the subscriber would like to have the 0073 * subscription active. Defaults to null, i.e. not sent, to setup a 0074 * permanent subscription if possible. 0075 * 0076 * @var int 0077 */ 0078 protected $_leaseSeconds = null; 0079 0080 /** 0081 * The preferred verification mode (sync or async). By default, this 0082 * Subscriber prefers synchronous verification, but is considered 0083 * desireable to support asynchronous verification if possible. 0084 * 0085 * Zend_Feed_Pubsubhubbub_Subscriber will always send both modes, whose 0086 * order of occurance in the parameter list determines this preference. 0087 * 0088 * @var string 0089 */ 0090 protected $_preferredVerificationMode 0091 = Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_SYNC; 0092 0093 /** 0094 * An array of any errors including keys for 'response', 'hubUrl'. 0095 * The response is the actual Zend_Http_Response object. 0096 * 0097 * @var array 0098 */ 0099 protected $_errors = array(); 0100 0101 /** 0102 * An array of Hub Server URLs for Hubs operating at this time in 0103 * asynchronous verification mode. 0104 * 0105 * @var array 0106 */ 0107 protected $_asyncHubs = array(); 0108 0109 /** 0110 * An instance of Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface used to background 0111 * save any verification tokens associated with a subscription or other. 0112 * 0113 * @var Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface 0114 */ 0115 protected $_storage = null; 0116 0117 /** 0118 * An array of authentication credentials for HTTP Basic Authentication 0119 * if required by specific Hubs. The array is indexed by Hub Endpoint URI 0120 * and the value is a simple array of the username and password to apply. 0121 * 0122 * @var array 0123 */ 0124 protected $_authentications = array(); 0125 0126 /** 0127 * Tells the Subscriber to append any subscription identifier to the path 0128 * of the base Callback URL. E.g. an identifier "subkey1" would be added 0129 * to the callback URL "http://www.example.com/callback" to create a subscription 0130 * specific Callback URL of "http://www.example.com/callback/subkey1". 0131 * 0132 * This is required for all Hubs using the Pubsubhubbub 0.1 Specification. 0133 * It should be manually intercepted and passed to the Callback class using 0134 * Zend_Feed_Pubsubhubbub_Subscriber_Callback::setSubscriptionKey(). Will 0135 * require a route in the form "callback/:subkey" to allow the parameter be 0136 * retrieved from an action using the Zend_Controller_Action::_getParam() 0137 * method. 0138 * 0139 * @var string 0140 */ 0141 protected $_usePathParameter = false; 0142 0143 /** 0144 * Constructor; accepts an array or Zend_Config instance to preset 0145 * options for the Subscriber without calling all supported setter 0146 * methods in turn. 0147 * 0148 * @param array|Zend_Config|null $config Options array or Zend_Config instance 0149 * @throws Zend_Feed_Pubsubhubbub_Exception 0150 */ 0151 public function __construct($config = null) 0152 { 0153 if ($config !== null) { 0154 $this->setConfig($config); 0155 } 0156 } 0157 0158 /** 0159 * Process any injected configuration options 0160 * 0161 * @param array|Zend_Config $config Options array or Zend_Config instance 0162 * @throws Zend_Feed_Pubsubhubbub_Exception 0163 * @return Zend_Feed_Pubsubhubbub_Subscriber 0164 */ 0165 public function setConfig($config) 0166 { 0167 if ($config instanceof Zend_Config) { 0168 $config = $config->toArray(); 0169 } elseif (!is_array($config)) { 0170 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0171 throw new Zend_Feed_Pubsubhubbub_Exception('Array or Zend_Config object' 0172 . ' expected, got ' . gettype($config)); 0173 } 0174 if (array_key_exists('hubUrls', $config)) { 0175 $this->addHubUrls($config['hubUrls']); 0176 } 0177 if (array_key_exists('callbackUrl', $config)) { 0178 $this->setCallbackUrl($config['callbackUrl']); 0179 } 0180 if (array_key_exists('topicUrl', $config)) { 0181 $this->setTopicUrl($config['topicUrl']); 0182 } 0183 if (array_key_exists('storage', $config)) { 0184 $this->setStorage($config['storage']); 0185 } 0186 if (array_key_exists('leaseSeconds', $config)) { 0187 $this->setLeaseSeconds($config['leaseSeconds']); 0188 } 0189 if (array_key_exists('parameters', $config)) { 0190 $this->setParameters($config['parameters']); 0191 } 0192 if (array_key_exists('authentications', $config)) { 0193 $this->addAuthentications($config['authentications']); 0194 } 0195 if (array_key_exists('usePathParameter', $config)) { 0196 $this->usePathParameter($config['usePathParameter']); 0197 } 0198 if (array_key_exists('preferredVerificationMode', $config)) { 0199 $this->setPreferredVerificationMode( 0200 $config['preferredVerificationMode'] 0201 ); 0202 } 0203 return $this; 0204 } 0205 0206 /** 0207 * Set the topic URL (RSS or Atom feed) to which the intended (un)subscribe 0208 * event will relate 0209 * 0210 * @param string $url 0211 * @throws Zend_Feed_Pubsubhubbub_Exception 0212 * @return Zend_Feed_Pubsubhubbub_Subscriber 0213 */ 0214 public function setTopicUrl($url) 0215 { 0216 if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) { 0217 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0218 throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"' 0219 .' of "' . $url . '" must be a non-empty string and a valid' 0220 .' URL'); 0221 } 0222 $this->_topicUrl = $url; 0223 return $this; 0224 } 0225 0226 /** 0227 * Set the topic URL (RSS or Atom feed) to which the intended (un)subscribe 0228 * event will relate 0229 * 0230 * @throws Zend_Feed_Pubsubhubbub_Exception 0231 * @return string 0232 */ 0233 public function getTopicUrl() 0234 { 0235 if (empty($this->_topicUrl)) { 0236 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0237 throw new Zend_Feed_Pubsubhubbub_Exception('A valid Topic (RSS or Atom' 0238 . ' feed) URL MUST be set before attempting any operation'); 0239 } 0240 return $this->_topicUrl; 0241 } 0242 0243 /** 0244 * Set the number of seconds for which any subscription will remain valid 0245 * 0246 * @param int $seconds 0247 * @throws Zend_Feed_Pubsubhubbub_Exception 0248 * @return Zend_Feed_Pubsubhubbub_Subscriber 0249 */ 0250 public function setLeaseSeconds($seconds) 0251 { 0252 $seconds = intval($seconds); 0253 if ($seconds <= 0) { 0254 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0255 throw new Zend_Feed_Pubsubhubbub_Exception('Expected lease seconds' 0256 . ' must be an integer greater than zero'); 0257 } 0258 $this->_leaseSeconds = $seconds; 0259 return $this; 0260 } 0261 0262 /** 0263 * Get the number of lease seconds on subscriptions 0264 * 0265 * @return int 0266 */ 0267 public function getLeaseSeconds() 0268 { 0269 return $this->_leaseSeconds; 0270 } 0271 0272 /** 0273 * Set the callback URL to be used by Hub Servers when communicating with 0274 * this Subscriber 0275 * 0276 * @param string $url 0277 * @throws Zend_Feed_Pubsubhubbub_Exception 0278 * @return Zend_Feed_Pubsubhubbub_Subscriber 0279 */ 0280 public function setCallbackUrl($url) 0281 { 0282 if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) { 0283 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0284 throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"' 0285 . ' of "' . $url . '" must be a non-empty string and a valid' 0286 . ' URL'); 0287 } 0288 $this->_callbackUrl = $url; 0289 return $this; 0290 } 0291 0292 /** 0293 * Get the callback URL to be used by Hub Servers when communicating with 0294 * this Subscriber 0295 * 0296 * @throws Zend_Feed_Pubsubhubbub_Exception 0297 * @return string 0298 */ 0299 public function getCallbackUrl() 0300 { 0301 if (empty($this->_callbackUrl)) { 0302 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0303 throw new Zend_Feed_Pubsubhubbub_Exception('A valid Callback URL MUST be' 0304 . ' set before attempting any operation'); 0305 } 0306 return $this->_callbackUrl; 0307 } 0308 0309 /** 0310 * Set preferred verification mode (sync or async). By default, this 0311 * Subscriber prefers synchronous verification, but does support 0312 * asynchronous if that's the Hub Server's utilised mode. 0313 * 0314 * Zend_Feed_Pubsubhubbub_Subscriber will always send both modes, whose 0315 * order of occurance in the parameter list determines this preference. 0316 * 0317 * @param string $mode Should be 'sync' or 'async' 0318 * @throws Zend_Feed_Pubsubhubbub_Exception 0319 * @return Zend_Feed_Pubsubhubbub_Subscriber 0320 */ 0321 public function setPreferredVerificationMode($mode) 0322 { 0323 if ($mode !== Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_SYNC 0324 && $mode !== Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_ASYNC) { 0325 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0326 throw new Zend_Feed_Pubsubhubbub_Exception('Invalid preferred' 0327 . ' mode specified: "' . $mode . '" but should be one of' 0328 . ' Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_SYNC or' 0329 . ' Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_ASYNC'); 0330 } 0331 $this->_preferredVerificationMode = $mode; 0332 return $this; 0333 } 0334 0335 /** 0336 * Get preferred verification mode (sync or async). 0337 * 0338 * @return string 0339 */ 0340 public function getPreferredVerificationMode() 0341 { 0342 return $this->_preferredVerificationMode; 0343 } 0344 0345 /** 0346 * Add a Hub Server URL supported by Publisher 0347 * 0348 * @param string $url 0349 * @throws Zend_Feed_Pubsubhubbub_Exception 0350 * @return Zend_Feed_Pubsubhubbub_Subscriber 0351 */ 0352 public function addHubUrl($url) 0353 { 0354 if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) { 0355 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0356 throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"' 0357 . ' of "' . $url . '" must be a non-empty string and a valid' 0358 . ' URL'); 0359 } 0360 $this->_hubUrls[] = $url; 0361 return $this; 0362 } 0363 0364 /** 0365 * Add an array of Hub Server URLs supported by Publisher 0366 * 0367 * @param array $urls 0368 * @return Zend_Feed_Pubsubhubbub_Subscriber 0369 */ 0370 public function addHubUrls(array $urls) 0371 { 0372 foreach ($urls as $url) { 0373 $this->addHubUrl($url); 0374 } 0375 return $this; 0376 } 0377 0378 /** 0379 * Remove a Hub Server URL 0380 * 0381 * @param string $url 0382 * @return Zend_Feed_Pubsubhubbub_Subscriber 0383 */ 0384 public function removeHubUrl($url) 0385 { 0386 if (!in_array($url, $this->getHubUrls())) { 0387 return $this; 0388 } 0389 $key = array_search($url, $this->_hubUrls); 0390 unset($this->_hubUrls[$key]); 0391 return $this; 0392 } 0393 0394 /** 0395 * Return an array of unique Hub Server URLs currently available 0396 * 0397 * @return array 0398 */ 0399 public function getHubUrls() 0400 { 0401 $this->_hubUrls = array_unique($this->_hubUrls); 0402 return $this->_hubUrls; 0403 } 0404 0405 /** 0406 * Add authentication credentials for a given URL 0407 * 0408 * @param string $url 0409 * @param array $authentication 0410 * @throws Zend_Feed_Pubsubhubbub_Exception 0411 * @return Zend_Feed_Pubsubhubbub_Subscriber 0412 */ 0413 public function addAuthentication($url, array $authentication) 0414 { 0415 if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) { 0416 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0417 throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"' 0418 . ' of "' . $url . '" must be a non-empty string and a valid' 0419 . ' URL'); 0420 } 0421 $this->_authentications[$url] = $authentication; 0422 return $this; 0423 } 0424 0425 /** 0426 * Add authentication credentials for hub URLs 0427 * 0428 * @param array $authentications 0429 * @return Zend_Feed_Pubsubhubbub_Subscriber 0430 */ 0431 public function addAuthentications(array $authentications) 0432 { 0433 foreach ($authentications as $url => $authentication) { 0434 $this->addAuthentication($url, $authentication); 0435 } 0436 return $this; 0437 } 0438 0439 /** 0440 * Get all hub URL authentication credentials 0441 * 0442 * @return array 0443 */ 0444 public function getAuthentications() 0445 { 0446 return $this->_authentications; 0447 } 0448 0449 /** 0450 * Set flag indicating whether or not to use a path parameter 0451 * 0452 * @param bool $bool 0453 * @return Zend_Feed_Pubsubhubbub_Subscriber 0454 */ 0455 public function usePathParameter($bool = true) 0456 { 0457 $this->_usePathParameter = $bool; 0458 return $this; 0459 } 0460 0461 /** 0462 * Add an optional parameter to the (un)subscribe requests 0463 * 0464 * @param string $name 0465 * @param string|null $value 0466 * @throws Zend_Feed_Pubsubhubbub_Exception 0467 * @return Zend_Feed_Pubsubhubbub_Subscriber 0468 */ 0469 public function setParameter($name, $value = null) 0470 { 0471 if (is_array($name)) { 0472 $this->setParameters($name); 0473 return $this; 0474 } 0475 if (empty($name) || !is_string($name)) { 0476 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0477 throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "name"' 0478 . ' of "' . $name . '" must be a non-empty string'); 0479 } 0480 if ($value === null) { 0481 $this->removeParameter($name); 0482 return $this; 0483 } 0484 if (empty($value) || (!is_string($value) && $value !== null)) { 0485 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0486 throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "value"' 0487 . ' of "' . $value . '" must be a non-empty string'); 0488 } 0489 $this->_parameters[$name] = $value; 0490 return $this; 0491 } 0492 0493 /** 0494 * Add an optional parameter to the (un)subscribe requests 0495 * 0496 * @param array $parameters 0497 * @throws Zend_Feed_Pubsubhubbub_Exception 0498 * @return Zend_Feed_Pubsubhubbub_Subscriber 0499 */ 0500 public function setParameters(array $parameters) 0501 { 0502 foreach ($parameters as $name => $value) { 0503 $this->setParameter($name, $value); 0504 } 0505 return $this; 0506 } 0507 0508 /** 0509 * Remove an optional parameter for the (un)subscribe requests 0510 * 0511 * @param string $name 0512 * @throws Zend_Feed_Pubsubhubbub_Exception 0513 * @return Zend_Feed_Pubsubhubbub_Subscriber 0514 */ 0515 public function removeParameter($name) 0516 { 0517 if (empty($name) || !is_string($name)) { 0518 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0519 throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "name"' 0520 . ' of "' . $name . '" must be a non-empty string'); 0521 } 0522 if (array_key_exists($name, $this->_parameters)) { 0523 unset($this->_parameters[$name]); 0524 } 0525 return $this; 0526 } 0527 0528 /** 0529 * Return an array of optional parameters for (un)subscribe requests 0530 * 0531 * @return array 0532 */ 0533 public function getParameters() 0534 { 0535 return $this->_parameters; 0536 } 0537 0538 /** 0539 * Sets an instance of Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface used to background 0540 * save any verification tokens associated with a subscription or other. 0541 * 0542 * @param Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface $storage 0543 * @return Zend_Feed_Pubsubhubbub_Subscriber 0544 */ 0545 public function setStorage(Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface $storage) 0546 { 0547 $this->_storage = $storage; 0548 return $this; 0549 } 0550 0551 /** 0552 * Gets an instance of Zend_Feed_Pubsubhubbub_Storage_StorageInterface used 0553 * to background save any verification tokens associated with a subscription 0554 * or other. 0555 * 0556 * @throws Zend_Feed_Pubsubhubbub_Exception 0557 * @return Zend_Feed_Pubsubhubbub_Model_SubscriptionInterface 0558 */ 0559 public function getStorage() 0560 { 0561 if ($this->_storage === null) { 0562 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0563 throw new Zend_Feed_Pubsubhubbub_Exception('No storage vehicle ' 0564 . 'has been set.'); 0565 } 0566 return $this->_storage; 0567 } 0568 0569 /** 0570 * Subscribe to one or more Hub Servers using the stored Hub URLs 0571 * for the given Topic URL (RSS or Atom feed) 0572 */ 0573 public function subscribeAll() 0574 { 0575 return $this->_doRequest('subscribe'); 0576 } 0577 0578 /** 0579 * Unsubscribe from one or more Hub Servers using the stored Hub URLs 0580 * for the given Topic URL (RSS or Atom feed) 0581 */ 0582 public function unsubscribeAll() 0583 { 0584 return $this->_doRequest('unsubscribe'); 0585 } 0586 0587 /** 0588 * Returns a boolean indicator of whether the notifications to Hub 0589 * Servers were ALL successful. If even one failed, FALSE is returned. 0590 * 0591 * @return bool 0592 */ 0593 public function isSuccess() 0594 { 0595 if (count($this->_errors) > 0) { 0596 return false; 0597 } 0598 return true; 0599 } 0600 0601 /** 0602 * Return an array of errors met from any failures, including keys: 0603 * 'response' => the Zend_Http_Response object from the failure 0604 * 'hubUrl' => the URL of the Hub Server whose notification failed 0605 * 0606 * @return array 0607 */ 0608 public function getErrors() 0609 { 0610 return $this->_errors; 0611 } 0612 0613 /** 0614 * Return an array of Hub Server URLs who returned a response indicating 0615 * operation in Asynchronous Verification Mode, i.e. they will not confirm 0616 * any (un)subscription immediately but at a later time (Hubs may be 0617 * doing this as a batch process when load balancing) 0618 * 0619 * @return array 0620 */ 0621 public function getAsyncHubs() 0622 { 0623 return $this->_asyncHubs; 0624 } 0625 0626 /** 0627 * Executes an (un)subscribe request 0628 * 0629 * @param string $mode 0630 * @throws Zend_Feed_Pubsubhubbub_Exception 0631 * @throws Zend_Http_Client_Exception 0632 */ 0633 protected function _doRequest($mode) 0634 { 0635 $client = $this->_getHttpClient(); 0636 $hubs = $this->getHubUrls(); 0637 if (empty($hubs)) { 0638 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0639 throw new Zend_Feed_Pubsubhubbub_Exception('No Hub Server URLs' 0640 . ' have been set so no subscriptions can be attempted'); 0641 } 0642 $this->_errors = array(); 0643 $this->_asyncHubs = array(); 0644 foreach ($hubs as $url) { 0645 if (array_key_exists($url, $this->_authentications)) { 0646 $auth = $this->_authentications[$url]; 0647 $client->setAuth($auth[0], $auth[1]); 0648 } 0649 $client->setUri($url); 0650 $client->setRawData( 0651 $this->_getRequestParameters($url, $mode), 0652 'application/x-www-form-urlencoded' 0653 ); 0654 $response = $client->request(); 0655 if ($response->getStatus() !== 204 0656 && $response->getStatus() !== 202 0657 ) { 0658 $this->_errors[] = array( 0659 'response' => $response, 0660 'hubUrl' => $url, 0661 ); 0662 /** 0663 * At first I thought it was needed, but the backend storage will 0664 * allow tracking async without any user interference. It's left 0665 * here in case the user is interested in knowing what Hubs 0666 * are using async verification modes so they may update Models and 0667 * move these to asynchronous processes. 0668 */ 0669 } elseif ($response->getStatus() == 202) { 0670 $this->_asyncHubs[] = array( 0671 'response' => $response, 0672 'hubUrl' => $url, 0673 ); 0674 } 0675 } 0676 } 0677 0678 /** 0679 * Get a basic prepared HTTP client for use 0680 * 0681 * @return Zend_Http_Client 0682 */ 0683 protected function _getHttpClient() 0684 { 0685 $client = Zend_Feed_Pubsubhubbub::getHttpClient(); 0686 $client->setMethod(Zend_Http_Client::POST); 0687 $client->setConfig(array('useragent' => 'Zend_Feed_Pubsubhubbub_Subscriber/' 0688 . Zend_Version::VERSION)); 0689 return $client; 0690 } 0691 0692 /** 0693 * Return a list of standard protocol/optional parameters for addition to 0694 * client's POST body that are specific to the current Hub Server URL 0695 * 0696 * @param string $hubUrl 0697 * @param string $mode 0698 * @throws Zend_Feed_Pubsubhubbub_Exception 0699 * @return string 0700 */ 0701 protected function _getRequestParameters($hubUrl, $mode) 0702 { 0703 if (!in_array($mode, array('subscribe', 'unsubscribe'))) { 0704 // require_once 'Zend/Feed/Pubsubhubbub/Exception.php'; 0705 throw new Zend_Feed_Pubsubhubbub_Exception('Invalid mode specified: "' 0706 . $mode . '" which should have been "subscribe" or "unsubscribe"'); 0707 } 0708 0709 $params = array( 0710 'hub.mode' => $mode, 0711 'hub.topic' => $this->getTopicUrl(), 0712 ); 0713 0714 if ($this->getPreferredVerificationMode() 0715 == Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_SYNC 0716 ) { 0717 $vmodes = array( 0718 Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_SYNC, 0719 Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_ASYNC, 0720 ); 0721 } else { 0722 $vmodes = array( 0723 Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_ASYNC, 0724 Zend_Feed_Pubsubhubbub::VERIFICATION_MODE_SYNC, 0725 ); 0726 } 0727 $params['hub.verify'] = array(); 0728 foreach($vmodes as $vmode) { 0729 $params['hub.verify'][] = $vmode; 0730 } 0731 0732 /** 0733 * Establish a persistent verify_token and attach key to callback 0734 * URL's path/querystring 0735 */ 0736 $key = $this->_generateSubscriptionKey($params, $hubUrl); 0737 $token = $this->_generateVerifyToken(); 0738 $params['hub.verify_token'] = $token; 0739 0740 // Note: query string only usable with PuSH 0.2 Hubs 0741 if (!$this->_usePathParameter) { 0742 $params['hub.callback'] = $this->getCallbackUrl() 0743 . '?xhub.subscription=' . Zend_Feed_Pubsubhubbub::urlencode($key); 0744 } else { 0745 $params['hub.callback'] = rtrim($this->getCallbackUrl(), '/') 0746 . '/' . Zend_Feed_Pubsubhubbub::urlencode($key); 0747 } 0748 if ($mode == 'subscribe' && $this->getLeaseSeconds() !== null) { 0749 $params['hub.lease_seconds'] = $this->getLeaseSeconds(); 0750 } 0751 0752 // hub.secret not currently supported 0753 $optParams = $this->getParameters(); 0754 foreach ($optParams as $name => $value) { 0755 $params[$name] = $value; 0756 } 0757 0758 // store subscription to storage 0759 $now = new Zend_Date; 0760 $expires = null; 0761 if (isset($params['hub.lease_seconds'])) { 0762 $expires = $now->add($params['hub.lease_seconds'], Zend_Date::SECOND) 0763 ->get('yyyy-MM-dd HH:mm:ss'); 0764 } 0765 $data = array( 0766 'id' => $key, 0767 'topic_url' => $params['hub.topic'], 0768 'hub_url' => $hubUrl, 0769 'created_time' => $now->get('yyyy-MM-dd HH:mm:ss'), 0770 'lease_seconds' => $expires, 0771 'verify_token' => hash('sha256', $params['hub.verify_token']), 0772 'secret' => null, 0773 'expiration_time' => $expires, 0774 'subscription_state' => Zend_Feed_Pubsubhubbub::SUBSCRIPTION_NOTVERIFIED, 0775 ); 0776 $this->getStorage()->setSubscription($data); 0777 0778 return $this->_toByteValueOrderedString( 0779 $this->_urlEncode($params) 0780 ); 0781 } 0782 0783 /** 0784 * Simple helper to generate a verification token used in (un)subscribe 0785 * requests to a Hub Server. Follows no particular method, which means 0786 * it might be improved/changed in future. 0787 * 0788 * @return string 0789 */ 0790 protected function _generateVerifyToken() 0791 { 0792 if (!empty($this->_testStaticToken)) { 0793 return $this->_testStaticToken; 0794 } 0795 return uniqid(rand(), true) . time(); 0796 } 0797 0798 /** 0799 * Simple helper to generate a verification token used in (un)subscribe 0800 * requests to a Hub Server. 0801 * 0802 * @param array $params 0803 * @param string $hubUrl The Hub Server URL for which this token will apply 0804 * @return string 0805 */ 0806 protected function _generateSubscriptionKey(array $params, $hubUrl) 0807 { 0808 $keyBase = $params['hub.topic'] . $hubUrl; 0809 $key = md5($keyBase); 0810 return $key; 0811 } 0812 0813 /** 0814 * URL Encode an array of parameters 0815 * 0816 * @param array $params 0817 * @return array 0818 */ 0819 protected function _urlEncode(array $params) 0820 { 0821 $encoded = array(); 0822 foreach ($params as $key => $value) { 0823 if (is_array($value)) { 0824 $ekey = Zend_Feed_Pubsubhubbub::urlencode($key); 0825 $encoded[$ekey] = array(); 0826 foreach ($value as $duplicateKey) { 0827 $encoded[$ekey][] 0828 = Zend_Feed_Pubsubhubbub::urlencode($duplicateKey); 0829 } 0830 } else { 0831 $encoded[Zend_Feed_Pubsubhubbub::urlencode($key)] 0832 = Zend_Feed_Pubsubhubbub::urlencode($value); 0833 } 0834 } 0835 return $encoded; 0836 } 0837 0838 /** 0839 * Order outgoing parameters 0840 * 0841 * @param array $params 0842 * @return array 0843 */ 0844 protected function _toByteValueOrderedString(array $params) 0845 { 0846 $return = array(); 0847 uksort($params, 'strnatcmp'); 0848 foreach ($params as $key => $value) { 0849 if (is_array($value)) { 0850 foreach ($value as $keyduplicate) { 0851 $return[] = $key . '=' . $keyduplicate; 0852 } 0853 } else { 0854 $return[] = $key . '=' . $value; 0855 } 0856 } 0857 return implode('&', $return); 0858 } 0859 0860 /** 0861 * This is STRICTLY for testing purposes only... 0862 */ 0863 protected $_testStaticToken = null; 0864 0865 final public function setTestStaticToken($token) 0866 { 0867 $this->_testStaticToken = (string) $token; 0868 } 0869 }