Reader.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  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_Reader
  17. * @copyright Copyright (c) 2005-2012 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
  23. */
  24. require_once 'Zend/Feed.php';
  25. /**
  26. * @see Zend_Feed_Reader_Feed_Rss
  27. */
  28. require_once 'Zend/Feed/Reader/Feed/Rss.php';
  29. /**
  30. * @see Zend_Feed_Reader_Feed_Atom
  31. */
  32. require_once 'Zend/Feed/Reader/Feed/Atom.php';
  33. /**
  34. * @see Zend_Feed_Reader_FeedSet
  35. */
  36. require_once 'Zend/Feed/Reader/FeedSet.php';
  37. /**
  38. * @category Zend
  39. * @package Zend_Feed_Reader
  40. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  41. * @license http://framework.zend.com/license/new-bsd New BSD License
  42. */
  43. class Zend_Feed_Reader
  44. {
  45. /**
  46. * Namespace constants
  47. */
  48. const NAMESPACE_ATOM_03 = 'http://purl.org/atom/ns#';
  49. const NAMESPACE_ATOM_10 = 'http://www.w3.org/2005/Atom';
  50. const NAMESPACE_RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
  51. const NAMESPACE_RSS_090 = 'http://my.netscape.com/rdf/simple/0.9/';
  52. const NAMESPACE_RSS_10 = 'http://purl.org/rss/1.0/';
  53. /**
  54. * Feed type constants
  55. */
  56. const TYPE_ANY = 'any';
  57. const TYPE_ATOM_03 = 'atom-03';
  58. const TYPE_ATOM_10 = 'atom-10';
  59. const TYPE_ATOM_10_ENTRY = 'atom-10-entry';
  60. const TYPE_ATOM_ANY = 'atom';
  61. const TYPE_RSS_090 = 'rss-090';
  62. const TYPE_RSS_091 = 'rss-091';
  63. const TYPE_RSS_091_NETSCAPE = 'rss-091n';
  64. const TYPE_RSS_091_USERLAND = 'rss-091u';
  65. const TYPE_RSS_092 = 'rss-092';
  66. const TYPE_RSS_093 = 'rss-093';
  67. const TYPE_RSS_094 = 'rss-094';
  68. const TYPE_RSS_10 = 'rss-10';
  69. const TYPE_RSS_20 = 'rss-20';
  70. const TYPE_RSS_ANY = 'rss';
  71. /**
  72. * Cache instance
  73. *
  74. * @var Zend_Cache_Core
  75. */
  76. protected static $_cache = null;
  77. /**
  78. * HTTP client object to use for retrieving feeds
  79. *
  80. * @var Zend_Http_Client
  81. */
  82. protected static $_httpClient = null;
  83. /**
  84. * Override HTTP PUT and DELETE request methods?
  85. *
  86. * @var boolean
  87. */
  88. protected static $_httpMethodOverride = false;
  89. protected static $_httpConditionalGet = false;
  90. protected static $_pluginLoader = null;
  91. protected static $_prefixPaths = array();
  92. protected static $_extensions = array(
  93. 'feed' => array(
  94. 'DublinCore_Feed',
  95. 'Atom_Feed'
  96. ),
  97. 'entry' => array(
  98. 'Content_Entry',
  99. 'DublinCore_Entry',
  100. 'Atom_Entry'
  101. ),
  102. 'core' => array(
  103. 'DublinCore_Feed',
  104. 'Atom_Feed',
  105. 'Content_Entry',
  106. 'DublinCore_Entry',
  107. 'Atom_Entry'
  108. )
  109. );
  110. /**
  111. * Get the Feed cache
  112. *
  113. * @return Zend_Cache_Core
  114. */
  115. public static function getCache()
  116. {
  117. return self::$_cache;
  118. }
  119. /**
  120. * Set the feed cache
  121. *
  122. * @param Zend_Cache_Core $cache
  123. * @return void
  124. */
  125. public static function setCache(Zend_Cache_Core $cache)
  126. {
  127. self::$_cache = $cache;
  128. }
  129. /**
  130. * Set the HTTP client instance
  131. *
  132. * Sets the HTTP client object to use for retrieving the feeds.
  133. *
  134. * @param Zend_Http_Client $httpClient
  135. * @return void
  136. */
  137. public static function setHttpClient(Zend_Http_Client $httpClient)
  138. {
  139. self::$_httpClient = $httpClient;
  140. }
  141. /**
  142. * Gets the HTTP client object. If none is set, a new Zend_Http_Client will be used.
  143. *
  144. * @return Zend_Http_Client_Abstract
  145. */
  146. public static function getHttpClient()
  147. {
  148. if (!self::$_httpClient instanceof Zend_Http_Client) {
  149. /**
  150. * @see Zend_Http_Client
  151. */
  152. require_once 'Zend/Http/Client.php';
  153. self::$_httpClient = new Zend_Http_Client();
  154. }
  155. return self::$_httpClient;
  156. }
  157. /**
  158. * Toggle using POST instead of PUT and DELETE HTTP methods
  159. *
  160. * Some feed implementations do not accept PUT and DELETE HTTP
  161. * methods, or they can't be used because of proxies or other
  162. * measures. This allows turning on using POST where PUT and
  163. * DELETE would normally be used; in addition, an
  164. * X-Method-Override header will be sent with a value of PUT or
  165. * DELETE as appropriate.
  166. *
  167. * @param boolean $override Whether to override PUT and DELETE.
  168. * @return void
  169. */
  170. public static function setHttpMethodOverride($override = true)
  171. {
  172. self::$_httpMethodOverride = $override;
  173. }
  174. /**
  175. * Get the HTTP override state
  176. *
  177. * @return boolean
  178. */
  179. public static function getHttpMethodOverride()
  180. {
  181. return self::$_httpMethodOverride;
  182. }
  183. /**
  184. * Set the flag indicating whether or not to use HTTP conditional GET
  185. *
  186. * @param bool $bool
  187. * @return void
  188. */
  189. public static function useHttpConditionalGet($bool = true)
  190. {
  191. self::$_httpConditionalGet = $bool;
  192. }
  193. /**
  194. * Import a feed by providing a URL
  195. *
  196. * @param string $url The URL to the feed
  197. * @param string $etag OPTIONAL Last received ETag for this resource
  198. * @param string $lastModified OPTIONAL Last-Modified value for this resource
  199. * @return Zend_Feed_Reader_FeedInterface
  200. */
  201. public static function import($uri, $etag = null, $lastModified = null)
  202. {
  203. $cache = self::getCache();
  204. $feed = null;
  205. $responseXml = '';
  206. $client = self::getHttpClient();
  207. $client->resetParameters();
  208. $client->setHeaders('If-None-Match', null);
  209. $client->setHeaders('If-Modified-Since', null);
  210. $client->setUri($uri);
  211. $cacheId = 'Zend_Feed_Reader_' . md5($uri);
  212. if (self::$_httpConditionalGet && $cache) {
  213. $data = $cache->load($cacheId);
  214. if ($data) {
  215. if ($etag === null) {
  216. $etag = $cache->load($cacheId.'_etag');
  217. }
  218. if ($lastModified === null) {
  219. $lastModified = $cache->load($cacheId.'_lastmodified');
  220. }
  221. if ($etag) {
  222. $client->setHeaders('If-None-Match', $etag);
  223. }
  224. if ($lastModified) {
  225. $client->setHeaders('If-Modified-Since', $lastModified);
  226. }
  227. }
  228. $response = $client->request('GET');
  229. if ($response->getStatus() !== 200 && $response->getStatus() !== 304) {
  230. require_once 'Zend/Feed/Exception.php';
  231. throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus());
  232. }
  233. if ($response->getStatus() == 304) {
  234. $responseXml = $data;
  235. } else {
  236. $responseXml = $response->getBody();
  237. $cache->save($responseXml, $cacheId);
  238. if ($response->getHeader('ETag')) {
  239. $cache->save($response->getHeader('ETag'), $cacheId.'_etag');
  240. }
  241. if ($response->getHeader('Last-Modified')) {
  242. $cache->save($response->getHeader('Last-Modified'), $cacheId.'_lastmodified');
  243. }
  244. }
  245. if (empty($responseXml)) {
  246. require_once 'Zend/Feed/Exception.php';
  247. throw new Zend_Feed_Exception('Feed failed to load, got empty response body');
  248. }
  249. return self::importString($responseXml);
  250. } elseif ($cache) {
  251. $data = $cache->load($cacheId);
  252. if ($data !== false) {
  253. return self::importString($data);
  254. }
  255. $response = $client->request('GET');
  256. if ($response->getStatus() !== 200) {
  257. require_once 'Zend/Feed/Exception.php';
  258. throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus());
  259. }
  260. $responseXml = $response->getBody();
  261. $cache->save($responseXml, $cacheId);
  262. if (empty($responseXml)) {
  263. require_once 'Zend/Feed/Exception.php';
  264. throw new Zend_Feed_Exception('Feed failed to load, got empty response body');
  265. }
  266. return self::importString($responseXml);
  267. } else {
  268. $response = $client->request('GET');
  269. if ($response->getStatus() !== 200) {
  270. require_once 'Zend/Feed/Exception.php';
  271. throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus());
  272. }
  273. $responseXml = $response->getBody();
  274. if (empty($responseXml)) {
  275. require_once 'Zend/Feed/Exception.php';
  276. throw new Zend_Feed_Exception('Feed failed to load, got empty response body');
  277. }
  278. $reader = self::importString($responseXml);
  279. $reader->setOriginalSourceUri($uri);
  280. return $reader;
  281. }
  282. }
  283. /**
  284. * Import a feed by providing a Zend_Feed_Abstract object
  285. *
  286. * @param Zend_Feed_Abstract $feed A fully instantiated Zend_Feed object
  287. * @return Zend_Feed_Reader_FeedInterface
  288. */
  289. public static function importFeed(Zend_Feed_Abstract $feed)
  290. {
  291. $dom = $feed->getDOM()->ownerDocument;
  292. $type = self::detectType($dom);
  293. self::_registerCoreExtensions();
  294. if (substr($type, 0, 3) == 'rss') {
  295. $reader = new Zend_Feed_Reader_Feed_Rss($dom, $type);
  296. } else {
  297. $reader = new Zend_Feed_Reader_Feed_Atom($dom, $type);
  298. }
  299. return $reader;
  300. }
  301. /**
  302. * Import a feed froma string
  303. *
  304. * @param string $string
  305. * @return Zend_Feed_Reader_FeedInterface
  306. */
  307. public static function importString($string)
  308. {
  309. $libxml_errflag = libxml_use_internal_errors(true);
  310. $oldValue = libxml_disable_entity_loader(true);
  311. $dom = new DOMDocument;
  312. $status = $dom->loadXML($string);
  313. foreach ($dom->childNodes as $child) {
  314. if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
  315. require_once 'Zend/Feed/Exception.php';
  316. throw new Zend_Feed_Exception(
  317. 'Invalid XML: Detected use of illegal DOCTYPE'
  318. );
  319. }
  320. }
  321. libxml_disable_entity_loader($oldValue);
  322. libxml_use_internal_errors($libxml_errflag);
  323. if (!$status) {
  324. // Build error message
  325. $error = libxml_get_last_error();
  326. if ($error && $error->message) {
  327. $errormsg = "DOMDocument cannot parse XML: {$error->message}";
  328. } else {
  329. $errormsg = "DOMDocument cannot parse XML: Please check the XML document's validity";
  330. }
  331. require_once 'Zend/Feed/Exception.php';
  332. throw new Zend_Feed_Exception($errormsg);
  333. }
  334. $type = self::detectType($dom);
  335. self::_registerCoreExtensions();
  336. if (substr($type, 0, 3) == 'rss') {
  337. $reader = new Zend_Feed_Reader_Feed_Rss($dom, $type);
  338. } elseif (substr($type, 8, 5) == 'entry') {
  339. $reader = new Zend_Feed_Reader_Entry_Atom($dom->documentElement, 0, Zend_Feed_Reader::TYPE_ATOM_10);
  340. } elseif (substr($type, 0, 4) == 'atom') {
  341. $reader = new Zend_Feed_Reader_Feed_Atom($dom, $type);
  342. } else {
  343. require_once 'Zend/Feed/Exception.php';
  344. throw new Zend_Feed_Exception('The URI used does not point to a '
  345. . 'valid Atom, RSS or RDF feed that Zend_Feed_Reader can parse.');
  346. }
  347. return $reader;
  348. }
  349. /**
  350. * Imports a feed from a file located at $filename.
  351. *
  352. * @param string $filename
  353. * @throws Zend_Feed_Exception
  354. * @return Zend_Feed_Reader_FeedInterface
  355. */
  356. public static function importFile($filename)
  357. {
  358. @ini_set('track_errors', 1);
  359. $feed = @file_get_contents($filename);
  360. @ini_restore('track_errors');
  361. if ($feed === false) {
  362. /**
  363. * @see Zend_Feed_Exception
  364. */
  365. require_once 'Zend/Feed/Exception.php';
  366. throw new Zend_Feed_Exception("File could not be loaded: $php_errormsg");
  367. }
  368. return self::importString($feed);
  369. }
  370. public static function findFeedLinks($uri)
  371. {
  372. // Get the HTTP response from $uri and save the contents
  373. $client = self::getHttpClient();
  374. $client->setUri($uri);
  375. $response = $client->request();
  376. if ($response->getStatus() !== 200) {
  377. /**
  378. * @see Zend_Feed_Exception
  379. */
  380. require_once 'Zend/Feed/Exception.php';
  381. throw new Zend_Feed_Exception("Failed to access $uri, got response code " . $response->getStatus());
  382. }
  383. $responseHtml = $response->getBody();
  384. $libxml_errflag = libxml_use_internal_errors(true);
  385. $oldValue = libxml_disable_entity_loader(true);
  386. $dom = new DOMDocument;
  387. $status = $dom->loadHTML($responseHtml);
  388. libxml_disable_entity_loader($oldValue);
  389. libxml_use_internal_errors($libxml_errflag);
  390. if (!$status) {
  391. // Build error message
  392. $error = libxml_get_last_error();
  393. if ($error && $error->message) {
  394. $errormsg = "DOMDocument cannot parse HTML: {$error->message}";
  395. } else {
  396. $errormsg = "DOMDocument cannot parse HTML: Please check the XML document's validity";
  397. }
  398. require_once 'Zend/Feed/Exception.php';
  399. throw new Zend_Feed_Exception($errormsg);
  400. }
  401. $feedSet = new Zend_Feed_Reader_FeedSet;
  402. $links = $dom->getElementsByTagName('link');
  403. $feedSet->addLinks($links, $uri);
  404. return $feedSet;
  405. }
  406. /**
  407. * Detect the feed type of the provided feed
  408. *
  409. * @param Zend_Feed_Abstract|DOMDocument|string $feed
  410. * @param bool $specOnly
  411. * @return string
  412. * @throws Zend_Feed_Exception
  413. */
  414. public static function detectType($feed, $specOnly = false)
  415. {
  416. if ($feed instanceof Zend_Feed_Reader_FeedInterface) {
  417. $dom = $feed->getDomDocument();
  418. } elseif($feed instanceof DOMDocument) {
  419. $dom = $feed;
  420. } elseif(is_string($feed) && !empty($feed)) {
  421. @ini_set('track_errors', 1);
  422. $oldValue = libxml_disable_entity_loader(true);
  423. $dom = new DOMDocument;
  424. $status = @$dom->loadXML($feed);
  425. foreach ($dom->childNodes as $child) {
  426. if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
  427. require_once 'Zend/Feed/Exception.php';
  428. throw new Zend_Feed_Exception(
  429. 'Invalid XML: Detected use of illegal DOCTYPE'
  430. );
  431. }
  432. }
  433. libxml_disable_entity_loader($oldValue);
  434. @ini_restore('track_errors');
  435. if (!$status) {
  436. if (!isset($php_errormsg)) {
  437. if (function_exists('xdebug_is_enabled')) {
  438. $php_errormsg = '(error message not available, when XDebug is running)';
  439. } else {
  440. $php_errormsg = '(error message not available)';
  441. }
  442. }
  443. require_once 'Zend/Feed/Exception.php';
  444. throw new Zend_Feed_Exception("DOMDocument cannot parse XML: $php_errormsg");
  445. }
  446. } else {
  447. require_once 'Zend/Feed/Exception.php';
  448. throw new Zend_Feed_Exception('Invalid object/scalar provided: must'
  449. . ' be of type Zend_Feed_Reader_FeedInterface, DomDocument or string');
  450. }
  451. $xpath = new DOMXPath($dom);
  452. if ($xpath->query('/rss')->length) {
  453. $type = self::TYPE_RSS_ANY;
  454. $version = $xpath->evaluate('string(/rss/@version)');
  455. if (strlen($version) > 0) {
  456. switch($version) {
  457. case '2.0':
  458. $type = self::TYPE_RSS_20;
  459. break;
  460. case '0.94':
  461. $type = self::TYPE_RSS_094;
  462. break;
  463. case '0.93':
  464. $type = self::TYPE_RSS_093;
  465. break;
  466. case '0.92':
  467. $type = self::TYPE_RSS_092;
  468. break;
  469. case '0.91':
  470. $type = self::TYPE_RSS_091;
  471. break;
  472. }
  473. }
  474. return $type;
  475. }
  476. $xpath->registerNamespace('rdf', self::NAMESPACE_RDF);
  477. if ($xpath->query('/rdf:RDF')->length) {
  478. $xpath->registerNamespace('rss', self::NAMESPACE_RSS_10);
  479. if ($xpath->query('/rdf:RDF/rss:channel')->length
  480. || $xpath->query('/rdf:RDF/rss:image')->length
  481. || $xpath->query('/rdf:RDF/rss:item')->length
  482. || $xpath->query('/rdf:RDF/rss:textinput')->length
  483. ) {
  484. return self::TYPE_RSS_10;
  485. }
  486. $xpath->registerNamespace('rss', self::NAMESPACE_RSS_090);
  487. if ($xpath->query('/rdf:RDF/rss:channel')->length
  488. || $xpath->query('/rdf:RDF/rss:image')->length
  489. || $xpath->query('/rdf:RDF/rss:item')->length
  490. || $xpath->query('/rdf:RDF/rss:textinput')->length
  491. ) {
  492. return self::TYPE_RSS_090;
  493. }
  494. }
  495. $type = self::TYPE_ATOM_ANY;
  496. $xpath->registerNamespace('atom', self::NAMESPACE_ATOM_10);
  497. if ($xpath->query('//atom:feed')->length) {
  498. return self::TYPE_ATOM_10;
  499. }
  500. if ($xpath->query('//atom:entry')->length) {
  501. if ($specOnly == true) {
  502. return self::TYPE_ATOM_10;
  503. } else {
  504. return self::TYPE_ATOM_10_ENTRY;
  505. }
  506. }
  507. $xpath->registerNamespace('atom', self::NAMESPACE_ATOM_03);
  508. if ($xpath->query('//atom:feed')->length) {
  509. return self::TYPE_ATOM_03;
  510. }
  511. return self::TYPE_ANY;
  512. }
  513. /**
  514. * Set plugin loader for use with Extensions
  515. *
  516. * @param Zend_Loader_PluginLoader_Interface $loader
  517. */
  518. public static function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader)
  519. {
  520. self::$_pluginLoader = $loader;
  521. }
  522. /**
  523. * Get plugin loader for use with Extensions
  524. *
  525. * @return Zend_Loader_PluginLoader_Interface $loader
  526. */
  527. public static function getPluginLoader()
  528. {
  529. if (!isset(self::$_pluginLoader)) {
  530. require_once 'Zend/Loader/PluginLoader.php';
  531. self::$_pluginLoader = new Zend_Loader_PluginLoader(array(
  532. 'Zend_Feed_Reader_Extension_' => 'Zend/Feed/Reader/Extension/',
  533. ));
  534. }
  535. return self::$_pluginLoader;
  536. }
  537. /**
  538. * Add prefix path for loading Extensions
  539. *
  540. * @param string $prefix
  541. * @param string $path
  542. * @return void
  543. */
  544. public static function addPrefixPath($prefix, $path)
  545. {
  546. $prefix = rtrim($prefix, '_');
  547. $path = rtrim($path, DIRECTORY_SEPARATOR);
  548. self::getPluginLoader()->addPrefixPath($prefix, $path);
  549. }
  550. /**
  551. * Add multiple Extension prefix paths at once
  552. *
  553. * @param array $spec
  554. * @return void
  555. */
  556. public static function addPrefixPaths(array $spec)
  557. {
  558. if (isset($spec['prefix']) && isset($spec['path'])) {
  559. self::addPrefixPath($spec['prefix'], $spec['path']);
  560. }
  561. foreach ($spec as $prefixPath) {
  562. if (isset($prefixPath['prefix']) && isset($prefixPath['path'])) {
  563. self::addPrefixPath($prefixPath['prefix'], $prefixPath['path']);
  564. }
  565. }
  566. }
  567. /**
  568. * Register an Extension by name
  569. *
  570. * @param string $name
  571. * @return void
  572. * @throws Zend_Feed_Exception if unable to resolve Extension class
  573. */
  574. public static function registerExtension($name)
  575. {
  576. $feedName = $name . '_Feed';
  577. $entryName = $name . '_Entry';
  578. if (self::isRegistered($name)) {
  579. if (self::getPluginLoader()->isLoaded($feedName) ||
  580. self::getPluginLoader()->isLoaded($entryName)) {
  581. return;
  582. }
  583. }
  584. try {
  585. self::getPluginLoader()->load($feedName);
  586. self::$_extensions['feed'][] = $feedName;
  587. } catch (Zend_Loader_PluginLoader_Exception $e) {
  588. }
  589. try {
  590. self::getPluginLoader()->load($entryName);
  591. self::$_extensions['entry'][] = $entryName;
  592. } catch (Zend_Loader_PluginLoader_Exception $e) {
  593. }
  594. if (!self::getPluginLoader()->isLoaded($feedName)
  595. && !self::getPluginLoader()->isLoaded($entryName)
  596. ) {
  597. require_once 'Zend/Feed/Exception.php';
  598. throw new Zend_Feed_Exception('Could not load extension: ' . $name
  599. . 'using Plugin Loader. Check prefix paths are configured and extension exists.');
  600. }
  601. }
  602. /**
  603. * Is a given named Extension registered?
  604. *
  605. * @param string $extensionName
  606. * @return boolean
  607. */
  608. public static function isRegistered($extensionName)
  609. {
  610. $feedName = $extensionName . '_Feed';
  611. $entryName = $extensionName . '_Entry';
  612. if (in_array($feedName, self::$_extensions['feed'])
  613. || in_array($entryName, self::$_extensions['entry'])
  614. ) {
  615. return true;
  616. }
  617. return false;
  618. }
  619. /**
  620. * Get a list of extensions
  621. *
  622. * @return array
  623. */
  624. public static function getExtensions()
  625. {
  626. return self::$_extensions;
  627. }
  628. /**
  629. * Reset class state to defaults
  630. *
  631. * @return void
  632. */
  633. public static function reset()
  634. {
  635. self::$_cache = null;
  636. self::$_httpClient = null;
  637. self::$_httpMethodOverride = false;
  638. self::$_httpConditionalGet = false;
  639. self::$_pluginLoader = null;
  640. self::$_prefixPaths = array();
  641. self::$_extensions = array(
  642. 'feed' => array(
  643. 'DublinCore_Feed',
  644. 'Atom_Feed'
  645. ),
  646. 'entry' => array(
  647. 'Content_Entry',
  648. 'DublinCore_Entry',
  649. 'Atom_Entry'
  650. ),
  651. 'core' => array(
  652. 'DublinCore_Feed',
  653. 'Atom_Feed',
  654. 'Content_Entry',
  655. 'DublinCore_Entry',
  656. 'Atom_Entry'
  657. )
  658. );
  659. }
  660. /**
  661. * Register core (default) extensions
  662. *
  663. * @return void
  664. */
  665. protected static function _registerCoreExtensions()
  666. {
  667. self::registerExtension('DublinCore');
  668. self::registerExtension('Content');
  669. self::registerExtension('Atom');
  670. self::registerExtension('Slash');
  671. self::registerExtension('WellFormedWeb');
  672. self::registerExtension('Thread');
  673. self::registerExtension('Podcast');
  674. }
  675. /**
  676. * Utility method to apply array_unique operation to a multidimensional
  677. * array.
  678. *
  679. * @param array
  680. * @return array
  681. */
  682. public static function arrayUnique(array $array)
  683. {
  684. foreach ($array as &$value) {
  685. $value = serialize($value);
  686. }
  687. $array = array_unique($array);
  688. foreach ($array as &$value) {
  689. $value = unserialize($value);
  690. }
  691. return $array;
  692. }
  693. }