X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=vendor%2Fzendframework%2Fzend-feed%2Fsrc%2FPubSubHubbub%2FSubscriber%2FCallback.php;fp=vendor%2Fzendframework%2Fzend-feed%2Fsrc%2FPubSubHubbub%2FSubscriber%2FCallback.php;h=a6bffef2170a0e85a23631062b15ce87980b5ddf;hp=0000000000000000000000000000000000000000;hb=a2bd1bf0c2c1f1a17d188f4dc0726a45494cefae;hpb=57c063afa3f66b07c4bbddc2d6129a96d90f0aad diff --git a/vendor/zendframework/zend-feed/src/PubSubHubbub/Subscriber/Callback.php b/vendor/zendframework/zend-feed/src/PubSubHubbub/Subscriber/Callback.php new file mode 100644 index 000000000..a6bffef21 --- /dev/null +++ b/vendor/zendframework/zend-feed/src/PubSubHubbub/Subscriber/Callback.php @@ -0,0 +1,322 @@ +subscriptionKey = $key; + return $this; + } + + /** + * Handle any callback from a Hub Server responding to a subscription or + * unsubscription request. This should be the Hub Server confirming the + * the request prior to taking action on it. + * + * @param array $httpGetData GET data if available and not in $_GET + * @param bool $sendResponseNow Whether to send response now or when asked + * @return void + */ + public function handle(array $httpGetData = null, $sendResponseNow = false) + { + if ($httpGetData === null) { + $httpGetData = $_GET; + } + + /** + * Handle any feed updates (sorry for the mess :P) + * + * This DOES NOT attempt to process a feed update. Feed updates + * SHOULD be validated/processed by an asynchronous process so as + * to avoid holding up responses to the Hub. + */ + $contentType = $this->_getHeader('Content-Type'); + if (strtolower($_SERVER['REQUEST_METHOD']) == 'post' + && $this->_hasValidVerifyToken(null, false) + && (stripos($contentType, 'application/atom+xml') === 0 + || stripos($contentType, 'application/rss+xml') === 0 + || stripos($contentType, 'application/xml') === 0 + || stripos($contentType, 'text/xml') === 0 + || stripos($contentType, 'application/rdf+xml') === 0) + ) { + $this->setFeedUpdate($this->_getRawBody()); + $this->getHttpResponse()->setHeader('X-Hub-On-Behalf-Of', $this->getSubscriberCount()); + /** + * Handle any (un)subscribe confirmation requests + */ + } elseif ($this->isValidHubVerification($httpGetData)) { + $this->getHttpResponse()->setContent($httpGetData['hub_challenge']); + + switch (strtolower($httpGetData['hub_mode'])) { + case 'subscribe': + $data = $this->currentSubscriptionData; + $data['subscription_state'] = PubSubHubbub\PubSubHubbub::SUBSCRIPTION_VERIFIED; + if (isset($httpGetData['hub_lease_seconds'])) { + $data['lease_seconds'] = $httpGetData['hub_lease_seconds']; + } + $this->getStorage()->setSubscription($data); + break; + case 'unsubscribe': + $verifyTokenKey = $this->_detectVerifyTokenKey($httpGetData); + $this->getStorage()->deleteSubscription($verifyTokenKey); + break; + default: + throw new Exception\RuntimeException(sprintf( + 'Invalid hub_mode ("%s") provided', + $httpGetData['hub_mode'] + )); + } + /** + * Hey, C'mon! We tried everything else! + */ + } else { + $this->getHttpResponse()->setStatusCode(404); + } + + if ($sendResponseNow) { + $this->sendResponse(); + } + } + + /** + * Checks validity of the request simply by making a quick pass and + * confirming the presence of all REQUIRED parameters. + * + * @param array $httpGetData + * @return bool + */ + public function isValidHubVerification(array $httpGetData) + { + /** + * As per the specification, the hub.verify_token is OPTIONAL. This + * implementation of Pubsubhubbub considers it REQUIRED and will + * always send a hub.verify_token parameter to be echoed back + * by the Hub Server. Therefore, its absence is considered invalid. + */ + if (strtolower($_SERVER['REQUEST_METHOD']) !== 'get') { + return false; + } + $required = [ + 'hub_mode', + 'hub_topic', + 'hub_challenge', + 'hub_verify_token', + ]; + foreach ($required as $key) { + if (! array_key_exists($key, $httpGetData)) { + return false; + } + } + if ($httpGetData['hub_mode'] !== 'subscribe' + && $httpGetData['hub_mode'] !== 'unsubscribe' + ) { + return false; + } + if ($httpGetData['hub_mode'] == 'subscribe' + && ! array_key_exists('hub_lease_seconds', $httpGetData) + ) { + return false; + } + if (! Uri::factory($httpGetData['hub_topic'])->isValid()) { + return false; + } + + /** + * Attempt to retrieve any Verification Token Key attached to Callback + * URL's path by our Subscriber implementation + */ + if (! $this->_hasValidVerifyToken($httpGetData)) { + return false; + } + return true; + } + + /** + * Sets a newly received feed (Atom/RSS) sent by a Hub as an update to a + * Topic we've subscribed to. + * + * @param string $feed + * @return \Zend\Feed\PubSubHubbub\Subscriber\Callback + */ + public function setFeedUpdate($feed) + { + $this->feedUpdate = $feed; + return $this; + } + + /** + * Check if any newly received feed (Atom/RSS) update was received + * + * @return bool + */ + public function hasFeedUpdate() + { + if ($this->feedUpdate === null) { + return false; + } + return true; + } + + /** + * Gets a newly received feed (Atom/RSS) sent by a Hub as an update to a + * Topic we've subscribed to. + * + * @return string + */ + public function getFeedUpdate() + { + return $this->feedUpdate; + } + + /** + * Check for a valid verify_token. By default attempts to compare values + * with that sent from Hub, otherwise merely ascertains its existence. + * + * @param array $httpGetData + * @param bool $checkValue + * @return bool + */ + // @codingStandardsIgnoreStart + protected function _hasValidVerifyToken(array $httpGetData = null, $checkValue = true) + { + // @codingStandardsIgnoreEnd + $verifyTokenKey = $this->_detectVerifyTokenKey($httpGetData); + if (empty($verifyTokenKey)) { + return false; + } + $verifyTokenExists = $this->getStorage()->hasSubscription($verifyTokenKey); + if (! $verifyTokenExists) { + return false; + } + if ($checkValue) { + $data = $this->getStorage()->getSubscription($verifyTokenKey); + $verifyToken = $data['verify_token']; + if ($verifyToken !== hash('sha256', $httpGetData['hub_verify_token'])) { + return false; + } + $this->currentSubscriptionData = $data; + return true; + } + return true; + } + + /** + * Attempt to detect the verification token key. This would be passed in + * the Callback URL (which we are handling with this class!) as a URI + * path part (the last part by convention). + * + * @param null|array $httpGetData + * @return false|string + */ + // @codingStandardsIgnoreStart + protected function _detectVerifyTokenKey(array $httpGetData = null) + { + // @codingStandardsIgnoreEnd + /** + * Available when sub keys encoding in Callback URL path + */ + if (isset($this->subscriptionKey)) { + return $this->subscriptionKey; + } + + /** + * Available only if allowed by PuSH 0.2 Hubs + */ + if (is_array($httpGetData) + && isset($httpGetData['xhub_subscription']) + ) { + return $httpGetData['xhub_subscription']; + } + + /** + * Available (possibly) if corrupted in transit and not part of $_GET + */ + $params = $this->_parseQueryString(); + if (isset($params['xhub.subscription'])) { + return rawurldecode($params['xhub.subscription']); + } + + return false; + } + + /** + * Build an array of Query String parameters. + * This bypasses $_GET which munges parameter names and cannot accept + * multiple parameters with the same key. + * + * @return array|void + */ + // @codingStandardsIgnoreStart + protected function _parseQueryString() + { + // @codingStandardsIgnoreEnd + $params = []; + $queryString = ''; + if (isset($_SERVER['QUERY_STRING'])) { + $queryString = $_SERVER['QUERY_STRING']; + } + if (empty($queryString)) { + return []; + } + $parts = explode('&', $queryString); + foreach ($parts as $kvpair) { + $pair = explode('=', $kvpair); + $key = rawurldecode($pair[0]); + $value = rawurldecode($pair[1]); + if (isset($params[$key])) { + if (is_array($params[$key])) { + $params[$key][] = $value; + } else { + $params[$key] = [$params[$key], $value]; + } + } else { + $params[$key] = $value; + } + } + return $params; + } +}