Publisher.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Feed_Pubsubhubbub
  17. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id$
  20. */
  21. /**
  22. * @see Zend_Feed_Pubsubhubbub
  23. */
  24. require_once 'Zend/Feed/Pubsubhubbub.php';
  25. /**
  26. * @category Zend
  27. * @package Zend_Feed_Pubsubhubbub
  28. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  29. * @license http://framework.zend.com/license/new-bsd New BSD License
  30. */
  31. class Zend_Feed_Pubsubhubbub_Publisher
  32. {
  33. /**
  34. * An array of URLs for all Hub Servers used by the Publisher, and to
  35. * which all topic update notifications will be sent.
  36. *
  37. * @var array
  38. */
  39. protected $_hubUrls = array();
  40. /**
  41. * An array of topic (Atom or RSS feed) URLs which have been updated and
  42. * whose updated status will be notified to all Hub Servers.
  43. *
  44. * @var array
  45. */
  46. protected $_updatedTopicUrls = array();
  47. /**
  48. * An array of any errors including keys for 'response', 'hubUrl'.
  49. * The response is the actual Zend_Http_Response object.
  50. *
  51. * @var array
  52. */
  53. protected $_errors = array();
  54. /**
  55. * An array of topic (Atom or RSS feed) URLs which have been updated and
  56. * whose updated status will be notified to all Hub Servers.
  57. *
  58. * @var array
  59. */
  60. protected $_parameters = array();
  61. /**
  62. * Constructor; accepts an array or Zend_Config instance to preset
  63. * options for the Publisher without calling all supported setter
  64. * methods in turn.
  65. *
  66. * @param array|Zend_Config $config Options array or Zend_Config instance
  67. * @throws Zend_Feed_Pubsubhubbub_Exception
  68. */
  69. public function __construct($config = null)
  70. {
  71. if ($config !== null) {
  72. $this->setConfig($config);
  73. }
  74. }
  75. /**
  76. * Process any injected configuration options
  77. *
  78. * @param array|Zend_Config $config Options array or Zend_Config instance
  79. * @throws Zend_Feed_Pubsubhubbub_Exception
  80. * @return Zend_Feed_Pubsubhubbub_Publisher
  81. */
  82. public function setConfig($config)
  83. {
  84. if ($config instanceof Zend_Config) {
  85. $config = $config->toArray();
  86. } elseif (!is_array($config)) {
  87. require_once 'Zend/Feed/Pubsubhubbub/Exception.php';
  88. throw new Zend_Feed_Pubsubhubbub_Exception('Array or Zend_Config object'
  89. . 'expected, got ' . gettype($config));
  90. }
  91. if (array_key_exists('hubUrls', $config)) {
  92. $this->addHubUrls($config['hubUrls']);
  93. }
  94. if (array_key_exists('updatedTopicUrls', $config)) {
  95. $this->addUpdatedTopicUrls($config['updatedTopicUrls']);
  96. }
  97. if (array_key_exists('parameters', $config)) {
  98. $this->setParameters($config['parameters']);
  99. }
  100. return $this;
  101. }
  102. /**
  103. * Add a Hub Server URL supported by Publisher
  104. *
  105. * @param string $url
  106. * @throws Zend_Feed_Pubsubhubbub_Exception
  107. * @return Zend_Feed_Pubsubhubbub_Publisher
  108. */
  109. public function addHubUrl($url)
  110. {
  111. if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) {
  112. require_once 'Zend/Feed/Pubsubhubbub/Exception.php';
  113. throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"'
  114. .' of "' . $url . '" must be a non-empty string and a valid'
  115. .'URL');
  116. }
  117. $this->_hubUrls[] = $url;
  118. return $this;
  119. }
  120. /**
  121. * Add an array of Hub Server URLs supported by Publisher
  122. *
  123. * @param array $urls
  124. * @return Zend_Feed_Pubsubhubbub_Publisher
  125. */
  126. public function addHubUrls(array $urls)
  127. {
  128. foreach ($urls as $url) {
  129. $this->addHubUrl($url);
  130. }
  131. return $this;
  132. }
  133. /**
  134. * Remove a Hub Server URL
  135. *
  136. * @param string $url
  137. * @return Zend_Feed_Pubsubhubbub_Publisher
  138. */
  139. public function removeHubUrl($url)
  140. {
  141. if (!in_array($url, $this->getHubUrls())) {
  142. return $this;
  143. }
  144. $key = array_search($url, $this->_hubUrls);
  145. unset($this->_hubUrls[$key]);
  146. return $this;
  147. }
  148. /**
  149. * Return an array of unique Hub Server URLs currently available
  150. *
  151. * @return array
  152. */
  153. public function getHubUrls()
  154. {
  155. $this->_hubUrls = array_unique($this->_hubUrls);
  156. return $this->_hubUrls;
  157. }
  158. /**
  159. * Add a URL to a topic (Atom or RSS feed) which has been updated
  160. *
  161. * @param string $url
  162. * @throws Zend_Feed_Pubsubhubbub_Exception
  163. * @return Zend_Feed_Pubsubhubbub_Publisher
  164. */
  165. public function addUpdatedTopicUrl($url)
  166. {
  167. if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) {
  168. require_once 'Zend/Feed/Pubsubhubbub/Exception.php';
  169. throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"'
  170. .' of "' . $url . '" must be a non-empty string and a valid'
  171. .'URL');
  172. }
  173. $this->_updatedTopicUrls[] = $url;
  174. return $this;
  175. }
  176. /**
  177. * Add an array of Topic URLs which have been updated
  178. *
  179. * @param array $urls
  180. * @return Zend_Feed_Pubsubhubbub_Publisher
  181. */
  182. public function addUpdatedTopicUrls(array $urls)
  183. {
  184. foreach ($urls as $url) {
  185. $this->addUpdatedTopicUrl($url);
  186. }
  187. return $this;
  188. }
  189. /**
  190. * Remove an updated topic URL
  191. *
  192. * @param string $url
  193. * @return Zend_Feed_Pubsubhubbub_Publisher
  194. */
  195. public function removeUpdatedTopicUrl($url)
  196. {
  197. if (!in_array($url, $this->getUpdatedTopicUrls())) {
  198. return $this;
  199. }
  200. $key = array_search($url, $this->_updatedTopicUrls);
  201. unset($this->_updatedTopicUrls[$key]);
  202. return $this;
  203. }
  204. /**
  205. * Return an array of unique updated topic URLs currently available
  206. *
  207. * @return array
  208. */
  209. public function getUpdatedTopicUrls()
  210. {
  211. $this->_updatedTopicUrls = array_unique($this->_updatedTopicUrls);
  212. return $this->_updatedTopicUrls;
  213. }
  214. /**
  215. * Notifies a single Hub Server URL of changes
  216. *
  217. * @param string $url The Hub Server's URL
  218. * @return void
  219. * @throws Zend_Feed_Pubsubhubbub_Exception Thrown on failure
  220. */
  221. public function notifyHub($url)
  222. {
  223. if (empty($url) || !is_string($url) || !Zend_Uri::check($url)) {
  224. require_once 'Zend/Feed/Pubsubhubbub/Exception.php';
  225. throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "url"'
  226. .' of "' . $url . '" must be a non-empty string and a valid'
  227. .'URL');
  228. }
  229. $client = $this->_getHttpClient();
  230. $client->setUri($url);
  231. $response = $client->request();
  232. if ($response->getStatus() !== 204) {
  233. require_once 'Zend/Feed/Pubsubhubbub/Exception.php';
  234. throw new Zend_Feed_Pubsubhubbub_Exception('Notification to Hub Server '
  235. . 'at "' . $url . '" appears to have failed with a status code of "'
  236. . $response->getStatus() . '" and message "'
  237. . $response->getMessage() . '"');
  238. }
  239. }
  240. /**
  241. * Notifies all Hub Server URLs of changes
  242. *
  243. * If a Hub notification fails, certain data will be retained in an
  244. * an array retrieved using getErrors(), if a failure occurs for any Hubs
  245. * the isSuccess() check will return FALSE. This method is designed not
  246. * to needlessly fail with an Exception/Error unless from Zend_Http_Client.
  247. *
  248. * @return void
  249. * @throws Zend_Feed_Pubsubhubbub_Exception Thrown if no hubs attached
  250. */
  251. public function notifyAll()
  252. {
  253. $client = $this->_getHttpClient();
  254. $hubs = $this->getHubUrls();
  255. if (empty($hubs)) {
  256. require_once 'Zend/Feed/Pubsubhubbub/Exception.php';
  257. throw new Zend_Feed_Pubsubhubbub_Exception('No Hub Server URLs'
  258. . ' have been set so no notifcations can be sent');
  259. }
  260. $this->_errors = array();
  261. foreach ($hubs as $url) {
  262. $client->setUri($url);
  263. $response = $client->request();
  264. if ($response->getStatus() !== 204) {
  265. $this->_errors[] = array(
  266. 'response' => $response,
  267. 'hubUrl' => $url
  268. );
  269. }
  270. }
  271. }
  272. /**
  273. * Add an optional parameter to the update notification requests
  274. *
  275. * @param string $name
  276. * @param string|null $value
  277. * @throws Zend_Feed_Pubsubhubbub_Exception
  278. * @return Zend_Feed_Pubsubhubbub_Publisher
  279. */
  280. public function setParameter($name, $value = null)
  281. {
  282. if (is_array($name)) {
  283. $this->setParameters($name);
  284. return $this;
  285. }
  286. if (empty($name) || !is_string($name)) {
  287. require_once 'Zend/Feed/Pubsubhubbub/Exception.php';
  288. throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "name"'
  289. .' of "' . $name . '" must be a non-empty string');
  290. }
  291. if ($value === null) {
  292. $this->removeParameter($name);
  293. return $this;
  294. }
  295. if (empty($value) || (!is_string($value) && $value !== null)) {
  296. require_once 'Zend/Feed/Pubsubhubbub/Exception.php';
  297. throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "value"'
  298. .' of "' . $value . '" must be a non-empty string');
  299. }
  300. $this->_parameters[$name] = $value;
  301. return $this;
  302. }
  303. /**
  304. * Add an optional parameter to the update notification requests
  305. *
  306. * @param array $parameters
  307. * @return Zend_Feed_Pubsubhubbub_Publisher
  308. */
  309. public function setParameters(array $parameters)
  310. {
  311. foreach ($parameters as $name => $value) {
  312. $this->setParameter($name, $value);
  313. }
  314. return $this;
  315. }
  316. /**
  317. * Remove an optional parameter for the notification requests
  318. *
  319. * @param string $name
  320. * @throws Zend_Feed_Pubsubhubbub_Exception
  321. * @return Zend_Feed_Pubsubhubbub_Publisher
  322. */
  323. public function removeParameter($name)
  324. {
  325. if (empty($name) || !is_string($name)) {
  326. require_once 'Zend/Feed/Pubsubhubbub/Exception.php';
  327. throw new Zend_Feed_Pubsubhubbub_Exception('Invalid parameter "name"'
  328. .' of "' . $name . '" must be a non-empty string');
  329. }
  330. if (array_key_exists($name, $this->_parameters)) {
  331. unset($this->_parameters[$name]);
  332. }
  333. return $this;
  334. }
  335. /**
  336. * Return an array of optional parameters for notification requests
  337. *
  338. * @return array
  339. */
  340. public function getParameters()
  341. {
  342. return $this->_parameters;
  343. }
  344. /**
  345. * Returns a boolean indicator of whether the notifications to Hub
  346. * Servers were ALL successful. If even one failed, FALSE is returned.
  347. *
  348. * @return bool
  349. */
  350. public function isSuccess()
  351. {
  352. if (count($this->_errors) > 0) {
  353. return false;
  354. }
  355. return true;
  356. }
  357. /**
  358. * Return an array of errors met from any failures, including keys:
  359. * 'response' => the Zend_Http_Response object from the failure
  360. * 'hubUrl' => the URL of the Hub Server whose notification failed
  361. *
  362. * @return array
  363. */
  364. public function getErrors()
  365. {
  366. return $this->_errors;
  367. }
  368. /**
  369. * Get a basic prepared HTTP client for use
  370. *
  371. * @throws Zend_Feed_Pubsubhubbub_Exception
  372. * @throws Zend_Http_Client_Exception
  373. * @return Zend_Http_Client
  374. */
  375. protected function _getHttpClient()
  376. {
  377. $client = Zend_Feed_Pubsubhubbub::getHttpClient();
  378. $client->setMethod(Zend_Http_Client::POST);
  379. $client->setConfig(array(
  380. 'useragent' => 'Zend_Feed_Pubsubhubbub_Publisher/' . Zend_Version::VERSION,
  381. ));
  382. $params = array();
  383. $params[] = 'hub.mode=publish';
  384. $topics = $this->getUpdatedTopicUrls();
  385. if (empty($topics)) {
  386. require_once 'Zend/Feed/Pubsubhubbub/Exception.php';
  387. throw new Zend_Feed_Pubsubhubbub_Exception('No updated topic URLs'
  388. . ' have been set');
  389. }
  390. foreach ($topics as $topicUrl) {
  391. $params[] = 'hub.url=' . urlencode($topicUrl);
  392. }
  393. $optParams = $this->getParameters();
  394. foreach ($optParams as $name => $value) {
  395. $params[] = urlencode($name) . '=' . urlencode($value);
  396. }
  397. $paramString = implode('&', $params);
  398. $client->setRawData($paramString, 'application/x-www-form-urlencoded');
  399. return $client;
  400. }
  401. }