PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Zend/Feed.php

https://gitlab.com/LisovyiEvhenii/ismextensions
PHP | 409 lines | 169 code | 40 blank | 200 comment | 27 complexity | 90930372cd8489f1be5480df69e492a3 MD5 | raw file
  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
  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. /** @see Zend_Xml_Security */
  22. #require_once 'Zend/Xml/Security.php';
  23. /**
  24. * Feed utility class
  25. *
  26. * Base Zend_Feed class, containing constants and the Zend_Http_Client instance
  27. * accessor.
  28. *
  29. * @category Zend
  30. * @package Zend_Feed
  31. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  32. * @license http://framework.zend.com/license/new-bsd New BSD License
  33. */
  34. class Zend_Feed
  35. {
  36. /**
  37. * HTTP client object to use for retrieving feeds
  38. *
  39. * @var Zend_Http_Client
  40. */
  41. protected static $_httpClient = null;
  42. /**
  43. * Override HTTP PUT and DELETE request methods?
  44. *
  45. * @var boolean
  46. */
  47. protected static $_httpMethodOverride = false;
  48. /**
  49. * @var array
  50. */
  51. protected static $_namespaces = array(
  52. 'opensearch' => 'http://a9.com/-/spec/opensearchrss/1.0/',
  53. 'atom' => 'http://www.w3.org/2005/Atom',
  54. 'rss' => 'http://blogs.law.harvard.edu/tech/rss',
  55. );
  56. /**
  57. * Set the HTTP client instance
  58. *
  59. * Sets the HTTP client object to use for retrieving the feeds.
  60. *
  61. * @param Zend_Http_Client $httpClient
  62. * @return void
  63. */
  64. public static function setHttpClient(Zend_Http_Client $httpClient)
  65. {
  66. self::$_httpClient = $httpClient;
  67. }
  68. /**
  69. * Gets the HTTP client object. If none is set, a new Zend_Http_Client will be used.
  70. *
  71. * @return Zend_Http_Client_Abstract
  72. */
  73. public static function getHttpClient()
  74. {
  75. if (!self::$_httpClient instanceof Zend_Http_Client) {
  76. /**
  77. * @see Zend_Http_Client
  78. */
  79. #require_once 'Zend/Http/Client.php';
  80. self::$_httpClient = new Zend_Http_Client();
  81. }
  82. return self::$_httpClient;
  83. }
  84. /**
  85. * Toggle using POST instead of PUT and DELETE HTTP methods
  86. *
  87. * Some feed implementations do not accept PUT and DELETE HTTP
  88. * methods, or they can't be used because of proxies or other
  89. * measures. This allows turning on using POST where PUT and
  90. * DELETE would normally be used; in addition, an
  91. * X-Method-Override header will be sent with a value of PUT or
  92. * DELETE as appropriate.
  93. *
  94. * @param boolean $override Whether to override PUT and DELETE.
  95. * @return void
  96. */
  97. public static function setHttpMethodOverride($override = true)
  98. {
  99. self::$_httpMethodOverride = $override;
  100. }
  101. /**
  102. * Get the HTTP override state
  103. *
  104. * @return boolean
  105. */
  106. public static function getHttpMethodOverride()
  107. {
  108. return self::$_httpMethodOverride;
  109. }
  110. /**
  111. * Get the full version of a namespace prefix
  112. *
  113. * Looks up a prefix (atom:, etc.) in the list of registered
  114. * namespaces and returns the full namespace URI if
  115. * available. Returns the prefix, unmodified, if it's not
  116. * registered.
  117. *
  118. * @return string
  119. */
  120. public static function lookupNamespace($prefix)
  121. {
  122. return isset(self::$_namespaces[$prefix]) ?
  123. self::$_namespaces[$prefix] :
  124. $prefix;
  125. }
  126. /**
  127. * Add a namespace and prefix to the registered list
  128. *
  129. * Takes a prefix and a full namespace URI and adds them to the
  130. * list of registered namespaces for use by
  131. * Zend_Feed::lookupNamespace().
  132. *
  133. * @param string $prefix The namespace prefix
  134. * @param string $namespaceURI The full namespace URI
  135. * @return void
  136. */
  137. public static function registerNamespace($prefix, $namespaceURI)
  138. {
  139. self::$_namespaces[$prefix] = $namespaceURI;
  140. }
  141. /**
  142. * Imports a feed located at $uri.
  143. *
  144. * @param string $uri
  145. * @throws Zend_Feed_Exception
  146. * @return Zend_Feed_Abstract
  147. */
  148. public static function import($uri)
  149. {
  150. $client = self::getHttpClient();
  151. $client->setUri($uri);
  152. $response = $client->request('GET');
  153. if ($response->getStatus() !== 200) {
  154. /**
  155. * @see Zend_Feed_Exception
  156. */
  157. #require_once 'Zend/Feed/Exception.php';
  158. throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus());
  159. }
  160. $feed = $response->getBody();
  161. return self::importString($feed);
  162. }
  163. /**
  164. * Imports a feed represented by $string.
  165. *
  166. * @param string $string
  167. * @throws Zend_Feed_Exception
  168. * @return Zend_Feed_Abstract
  169. */
  170. public static function importString($string)
  171. {
  172. if (trim($string) == '') {
  173. #require_once 'Zend/Feed/Exception.php';
  174. throw new Zend_Feed_Exception('Document/string being imported'
  175. . ' is an Empty string or comes from an empty HTTP response');
  176. }
  177. $doc = new DOMDocument;
  178. $doc = Zend_Xml_Security::scan($string, $doc);
  179. if (!$doc) {
  180. // prevent the class to generate an undefined variable notice (ZF-2590)
  181. // Build error message
  182. $error = libxml_get_last_error();
  183. if ($error && $error->message) {
  184. $errormsg = "DOMDocument cannot parse XML: {$error->message}";
  185. } else {
  186. $errormsg = "DOMDocument cannot parse XML";
  187. }
  188. /**
  189. * @see Zend_Feed_Exception
  190. */
  191. #require_once 'Zend/Feed/Exception.php';
  192. throw new Zend_Feed_Exception($errormsg);
  193. }
  194. // Try to find the base feed element or a single <entry> of an Atom feed
  195. if ($doc->getElementsByTagName('feed')->item(0) ||
  196. $doc->getElementsByTagName('entry')->item(0)) {
  197. /**
  198. * @see Zend_Feed_Atom
  199. */
  200. #require_once 'Zend/Feed/Atom.php';
  201. // return a newly created Zend_Feed_Atom object
  202. return new Zend_Feed_Atom(null, $string);
  203. }
  204. // Try to find the base feed element of an RSS feed
  205. if ($doc->getElementsByTagName('channel')->item(0)) {
  206. /**
  207. * @see Zend_Feed_Rss
  208. */
  209. #require_once 'Zend/Feed/Rss.php';
  210. // return a newly created Zend_Feed_Rss object
  211. return new Zend_Feed_Rss(null, $string);
  212. }
  213. // $string does not appear to be a valid feed of the supported types
  214. /**
  215. * @see Zend_Feed_Exception
  216. */
  217. #require_once 'Zend/Feed/Exception.php';
  218. throw new Zend_Feed_Exception('Invalid or unsupported feed format');
  219. }
  220. /**
  221. * Imports a feed from a file located at $filename.
  222. *
  223. * @param string $filename
  224. * @throws Zend_Feed_Exception
  225. * @return Zend_Feed_Abstract
  226. */
  227. public static function importFile($filename)
  228. {
  229. @ini_set('track_errors', 1);
  230. $feed = @file_get_contents($filename);
  231. @ini_restore('track_errors');
  232. if ($feed === false) {
  233. /**
  234. * @see Zend_Feed_Exception
  235. */
  236. #require_once 'Zend/Feed/Exception.php';
  237. throw new Zend_Feed_Exception("File could not be loaded: $php_errormsg");
  238. }
  239. return self::importString($feed);
  240. }
  241. /**
  242. * Attempts to find feeds at $uri referenced by <link ... /> tags. Returns an
  243. * array of the feeds referenced at $uri.
  244. *
  245. * @todo Allow findFeeds() to follow one, but only one, code 302.
  246. *
  247. * @param string $uri
  248. * @throws Zend_Feed_Exception
  249. * @return array
  250. */
  251. public static function findFeeds($uri)
  252. {
  253. // Get the HTTP response from $uri and save the contents
  254. $client = self::getHttpClient();
  255. $client->setUri($uri);
  256. $response = $client->request();
  257. if ($response->getStatus() !== 200) {
  258. /**
  259. * @see Zend_Feed_Exception
  260. */
  261. #require_once 'Zend/Feed/Exception.php';
  262. throw new Zend_Feed_Exception("Failed to access $uri, got response code " . $response->getStatus());
  263. }
  264. $contents = $response->getBody();
  265. // Parse the contents for appropriate <link ... /> tags
  266. @ini_set('track_errors', 1);
  267. $pattern = '~(<link[^>]+)/?>~i';
  268. $result = @preg_match_all($pattern, $contents, $matches);
  269. @ini_restore('track_errors');
  270. if ($result === false) {
  271. /**
  272. * @see Zend_Feed_Exception
  273. */
  274. #require_once 'Zend/Feed/Exception.php';
  275. throw new Zend_Feed_Exception("Internal error: $php_errormsg");
  276. }
  277. // Try to fetch a feed for each link tag that appears to refer to a feed
  278. $feeds = array();
  279. if (isset($matches[1]) && count($matches[1]) > 0) {
  280. foreach ($matches[1] as $link) {
  281. // force string to be an utf-8 one
  282. if (!mb_check_encoding($link, 'UTF-8')) {
  283. $link = mb_convert_encoding($link, 'UTF-8');
  284. }
  285. $xml = @Zend_Xml_Security::scan(rtrim($link, ' /') . ' />');
  286. if ($xml === false) {
  287. continue;
  288. }
  289. $attributes = $xml->attributes();
  290. if (!isset($attributes['rel']) || !@preg_match('~^(?:alternate|service\.feed)~i', $attributes['rel'])) {
  291. continue;
  292. }
  293. if (!isset($attributes['type']) ||
  294. !@preg_match('~^application/(?:atom|rss|rdf)\+xml~', $attributes['type'])) {
  295. continue;
  296. }
  297. if (!isset($attributes['href'])) {
  298. continue;
  299. }
  300. try {
  301. // checks if we need to canonize the given uri
  302. try {
  303. $uri = Zend_Uri::factory((string) $attributes['href']);
  304. } catch (Zend_Uri_Exception $e) {
  305. // canonize the uri
  306. $path = (string) $attributes['href'];
  307. $query = $fragment = '';
  308. if (substr($path, 0, 1) != '/') {
  309. // add the current root path to this one
  310. $path = rtrim($client->getUri()->getPath(), '/') . '/' . $path;
  311. }
  312. if (strpos($path, '?') !== false) {
  313. list($path, $query) = explode('?', $path, 2);
  314. }
  315. if (strpos($query, '#') !== false) {
  316. list($query, $fragment) = explode('#', $query, 2);
  317. }
  318. $uri = Zend_Uri::factory($client->getUri(true));
  319. $uri->setPath($path);
  320. $uri->setQuery($query);
  321. $uri->setFragment($fragment);
  322. }
  323. $feed = self::import($uri);
  324. } catch (Exception $e) {
  325. continue;
  326. }
  327. $feeds[$uri->getUri()] = $feed;
  328. }
  329. }
  330. // Return the fetched feeds
  331. return $feeds;
  332. }
  333. /**
  334. * Construct a new Zend_Feed_Abstract object from a custom array
  335. *
  336. * @param array $data
  337. * @param string $format (rss|atom) the requested output format
  338. * @return Zend_Feed_Abstract
  339. */
  340. public static function importArray(array $data, $format = 'atom')
  341. {
  342. $obj = 'Zend_Feed_' . ucfirst(strtolower($format));
  343. if (!class_exists($obj)) {
  344. #require_once 'Zend/Loader.php';
  345. Zend_Loader::loadClass($obj);
  346. }
  347. /**
  348. * @see Zend_Feed_Builder
  349. */
  350. #require_once 'Zend/Feed/Builder.php';
  351. return new $obj(null, null, new Zend_Feed_Builder($data));
  352. }
  353. /**
  354. * Construct a new Zend_Feed_Abstract object from a Zend_Feed_Builder_Interface data source
  355. *
  356. * @param Zend_Feed_Builder_Interface $builder this object will be used to extract the data of the feed
  357. * @param string $format (rss|atom) the requested output format
  358. * @return Zend_Feed_Abstract
  359. */
  360. public static function importBuilder(Zend_Feed_Builder_Interface $builder, $format = 'atom')
  361. {
  362. $obj = 'Zend_Feed_' . ucfirst(strtolower($format));
  363. if (!class_exists($obj)) {
  364. #require_once 'Zend/Loader.php';
  365. Zend_Loader::loadClass($obj);
  366. }
  367. return new $obj(null, null, $builder);
  368. }
  369. }