Reader.php 24 KB

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