Mercurial > hg > cmmr2012-drupal-site
comparison vendor/zendframework/zend-feed/src/PubSubHubbub/Subscriber/Callback.php @ 0:c75dbcec494b
Initial commit from drush-created site
author | Chris Cannam |
---|---|
date | Thu, 05 Jul 2018 14:24:15 +0000 |
parents | |
children | 5311817fb629 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c75dbcec494b |
---|---|
1 <?php | |
2 /** | |
3 * Zend Framework (http://framework.zend.com/) | |
4 * | |
5 * @link http://github.com/zendframework/zf2 for the canonical source repository | |
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) | |
7 * @license http://framework.zend.com/license/new-bsd New BSD License | |
8 */ | |
9 | |
10 namespace Zend\Feed\PubSubHubbub\Subscriber; | |
11 | |
12 use Zend\Feed\PubSubHubbub; | |
13 use Zend\Feed\PubSubHubbub\Exception; | |
14 use Zend\Feed\Uri; | |
15 | |
16 class Callback extends PubSubHubbub\AbstractCallback | |
17 { | |
18 /** | |
19 * Contains the content of any feeds sent as updates to the Callback URL | |
20 * | |
21 * @var string | |
22 */ | |
23 protected $feedUpdate = null; | |
24 | |
25 /** | |
26 * Holds a manually set subscription key (i.e. identifies a unique | |
27 * subscription) which is typical when it is not passed in the query string | |
28 * but is part of the Callback URL path, requiring manual retrieval e.g. | |
29 * using a route and the \Zend\Mvc\Router\RouteMatch::getParam() method. | |
30 * | |
31 * @var string | |
32 */ | |
33 protected $subscriptionKey = null; | |
34 | |
35 /** | |
36 * After verification, this is set to the verified subscription's data. | |
37 * | |
38 * @var array | |
39 */ | |
40 protected $currentSubscriptionData = null; | |
41 | |
42 /** | |
43 * Set a subscription key to use for the current callback request manually. | |
44 * Required if usePathParameter is enabled for the Subscriber. | |
45 * | |
46 * @param string $key | |
47 * @return \Zend\Feed\PubSubHubbub\Subscriber\Callback | |
48 */ | |
49 public function setSubscriptionKey($key) | |
50 { | |
51 $this->subscriptionKey = $key; | |
52 return $this; | |
53 } | |
54 | |
55 /** | |
56 * Handle any callback from a Hub Server responding to a subscription or | |
57 * unsubscription request. This should be the Hub Server confirming the | |
58 * the request prior to taking action on it. | |
59 * | |
60 * @param array $httpGetData GET data if available and not in $_GET | |
61 * @param bool $sendResponseNow Whether to send response now or when asked | |
62 * @return void | |
63 */ | |
64 public function handle(array $httpGetData = null, $sendResponseNow = false) | |
65 { | |
66 if ($httpGetData === null) { | |
67 $httpGetData = $_GET; | |
68 } | |
69 | |
70 /** | |
71 * Handle any feed updates (sorry for the mess :P) | |
72 * | |
73 * This DOES NOT attempt to process a feed update. Feed updates | |
74 * SHOULD be validated/processed by an asynchronous process so as | |
75 * to avoid holding up responses to the Hub. | |
76 */ | |
77 $contentType = $this->_getHeader('Content-Type'); | |
78 if (strtolower($_SERVER['REQUEST_METHOD']) == 'post' | |
79 && $this->_hasValidVerifyToken(null, false) | |
80 && (stripos($contentType, 'application/atom+xml') === 0 | |
81 || stripos($contentType, 'application/rss+xml') === 0 | |
82 || stripos($contentType, 'application/xml') === 0 | |
83 || stripos($contentType, 'text/xml') === 0 | |
84 || stripos($contentType, 'application/rdf+xml') === 0) | |
85 ) { | |
86 $this->setFeedUpdate($this->_getRawBody()); | |
87 $this->getHttpResponse()->setHeader('X-Hub-On-Behalf-Of', $this->getSubscriberCount()); | |
88 /** | |
89 * Handle any (un)subscribe confirmation requests | |
90 */ | |
91 } elseif ($this->isValidHubVerification($httpGetData)) { | |
92 $this->getHttpResponse()->setContent($httpGetData['hub_challenge']); | |
93 | |
94 switch (strtolower($httpGetData['hub_mode'])) { | |
95 case 'subscribe': | |
96 $data = $this->currentSubscriptionData; | |
97 $data['subscription_state'] = PubSubHubbub\PubSubHubbub::SUBSCRIPTION_VERIFIED; | |
98 if (isset($httpGetData['hub_lease_seconds'])) { | |
99 $data['lease_seconds'] = $httpGetData['hub_lease_seconds']; | |
100 } | |
101 $this->getStorage()->setSubscription($data); | |
102 break; | |
103 case 'unsubscribe': | |
104 $verifyTokenKey = $this->_detectVerifyTokenKey($httpGetData); | |
105 $this->getStorage()->deleteSubscription($verifyTokenKey); | |
106 break; | |
107 default: | |
108 throw new Exception\RuntimeException(sprintf( | |
109 'Invalid hub_mode ("%s") provided', | |
110 $httpGetData['hub_mode'] | |
111 )); | |
112 } | |
113 /** | |
114 * Hey, C'mon! We tried everything else! | |
115 */ | |
116 } else { | |
117 $this->getHttpResponse()->setStatusCode(404); | |
118 } | |
119 | |
120 if ($sendResponseNow) { | |
121 $this->sendResponse(); | |
122 } | |
123 } | |
124 | |
125 /** | |
126 * Checks validity of the request simply by making a quick pass and | |
127 * confirming the presence of all REQUIRED parameters. | |
128 * | |
129 * @param array $httpGetData | |
130 * @return bool | |
131 */ | |
132 public function isValidHubVerification(array $httpGetData) | |
133 { | |
134 /** | |
135 * As per the specification, the hub.verify_token is OPTIONAL. This | |
136 * implementation of Pubsubhubbub considers it REQUIRED and will | |
137 * always send a hub.verify_token parameter to be echoed back | |
138 * by the Hub Server. Therefore, its absence is considered invalid. | |
139 */ | |
140 if (strtolower($_SERVER['REQUEST_METHOD']) !== 'get') { | |
141 return false; | |
142 } | |
143 $required = [ | |
144 'hub_mode', | |
145 'hub_topic', | |
146 'hub_challenge', | |
147 'hub_verify_token', | |
148 ]; | |
149 foreach ($required as $key) { | |
150 if (!array_key_exists($key, $httpGetData)) { | |
151 return false; | |
152 } | |
153 } | |
154 if ($httpGetData['hub_mode'] !== 'subscribe' | |
155 && $httpGetData['hub_mode'] !== 'unsubscribe' | |
156 ) { | |
157 return false; | |
158 } | |
159 if ($httpGetData['hub_mode'] == 'subscribe' | |
160 && !array_key_exists('hub_lease_seconds', $httpGetData) | |
161 ) { | |
162 return false; | |
163 } | |
164 if (!Uri::factory($httpGetData['hub_topic'])->isValid()) { | |
165 return false; | |
166 } | |
167 | |
168 /** | |
169 * Attempt to retrieve any Verification Token Key attached to Callback | |
170 * URL's path by our Subscriber implementation | |
171 */ | |
172 if (!$this->_hasValidVerifyToken($httpGetData)) { | |
173 return false; | |
174 } | |
175 return true; | |
176 } | |
177 | |
178 /** | |
179 * Sets a newly received feed (Atom/RSS) sent by a Hub as an update to a | |
180 * Topic we've subscribed to. | |
181 * | |
182 * @param string $feed | |
183 * @return \Zend\Feed\PubSubHubbub\Subscriber\Callback | |
184 */ | |
185 public function setFeedUpdate($feed) | |
186 { | |
187 $this->feedUpdate = $feed; | |
188 return $this; | |
189 } | |
190 | |
191 /** | |
192 * Check if any newly received feed (Atom/RSS) update was received | |
193 * | |
194 * @return bool | |
195 */ | |
196 public function hasFeedUpdate() | |
197 { | |
198 if ($this->feedUpdate === null) { | |
199 return false; | |
200 } | |
201 return true; | |
202 } | |
203 | |
204 /** | |
205 * Gets a newly received feed (Atom/RSS) sent by a Hub as an update to a | |
206 * Topic we've subscribed to. | |
207 * | |
208 * @return string | |
209 */ | |
210 public function getFeedUpdate() | |
211 { | |
212 return $this->feedUpdate; | |
213 } | |
214 | |
215 /** | |
216 * Check for a valid verify_token. By default attempts to compare values | |
217 * with that sent from Hub, otherwise merely ascertains its existence. | |
218 * | |
219 * @param array $httpGetData | |
220 * @param bool $checkValue | |
221 * @return bool | |
222 */ | |
223 protected function _hasValidVerifyToken(array $httpGetData = null, $checkValue = true) | |
224 { | |
225 $verifyTokenKey = $this->_detectVerifyTokenKey($httpGetData); | |
226 if (empty($verifyTokenKey)) { | |
227 return false; | |
228 } | |
229 $verifyTokenExists = $this->getStorage()->hasSubscription($verifyTokenKey); | |
230 if (!$verifyTokenExists) { | |
231 return false; | |
232 } | |
233 if ($checkValue) { | |
234 $data = $this->getStorage()->getSubscription($verifyTokenKey); | |
235 $verifyToken = $data['verify_token']; | |
236 if ($verifyToken !== hash('sha256', $httpGetData['hub_verify_token'])) { | |
237 return false; | |
238 } | |
239 $this->currentSubscriptionData = $data; | |
240 return true; | |
241 } | |
242 return true; | |
243 } | |
244 | |
245 /** | |
246 * Attempt to detect the verification token key. This would be passed in | |
247 * the Callback URL (which we are handling with this class!) as a URI | |
248 * path part (the last part by convention). | |
249 * | |
250 * @param null|array $httpGetData | |
251 * @return false|string | |
252 */ | |
253 protected function _detectVerifyTokenKey(array $httpGetData = null) | |
254 { | |
255 /** | |
256 * Available when sub keys encoding in Callback URL path | |
257 */ | |
258 if (isset($this->subscriptionKey)) { | |
259 return $this->subscriptionKey; | |
260 } | |
261 | |
262 /** | |
263 * Available only if allowed by PuSH 0.2 Hubs | |
264 */ | |
265 if (is_array($httpGetData) | |
266 && isset($httpGetData['xhub_subscription']) | |
267 ) { | |
268 return $httpGetData['xhub_subscription']; | |
269 } | |
270 | |
271 /** | |
272 * Available (possibly) if corrupted in transit and not part of $_GET | |
273 */ | |
274 $params = $this->_parseQueryString(); | |
275 if (isset($params['xhub.subscription'])) { | |
276 return rawurldecode($params['xhub.subscription']); | |
277 } | |
278 | |
279 return false; | |
280 } | |
281 | |
282 /** | |
283 * Build an array of Query String parameters. | |
284 * This bypasses $_GET which munges parameter names and cannot accept | |
285 * multiple parameters with the same key. | |
286 * | |
287 * @return array|void | |
288 */ | |
289 protected function _parseQueryString() | |
290 { | |
291 $params = []; | |
292 $queryString = ''; | |
293 if (isset($_SERVER['QUERY_STRING'])) { | |
294 $queryString = $_SERVER['QUERY_STRING']; | |
295 } | |
296 if (empty($queryString)) { | |
297 return []; | |
298 } | |
299 $parts = explode('&', $queryString); | |
300 foreach ($parts as $kvpair) { | |
301 $pair = explode('=', $kvpair); | |
302 $key = rawurldecode($pair[0]); | |
303 $value = rawurldecode($pair[1]); | |
304 if (isset($params[$key])) { | |
305 if (is_array($params[$key])) { | |
306 $params[$key][] = $value; | |
307 } else { | |
308 $params[$key] = [$params[$key], $value]; | |
309 } | |
310 } else { | |
311 $params[$key] = $value; | |
312 } | |
313 } | |
314 return $params; | |
315 } | |
316 } |