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

/Feed/Abstract.php

https://bitbucket.org/netglue/zf-1.12-release
PHP | 304 lines | 118 code | 37 blank | 149 comment | 16 complexity | f46e80b9241d9385acb85ebe84e2cc4c 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-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_Element
  23. */
  24. require_once 'Zend/Feed/Element.php';
  25. /**
  26. * The Zend_Feed_Abstract class is an abstract class representing feeds.
  27. *
  28. * Zend_Feed_Abstract implements two core PHP 5 interfaces: ArrayAccess and
  29. * Iterator. In both cases the collection being treated as an array is
  30. * considered to be the entry collection, such that iterating over the
  31. * feed takes you through each of the feed.s entries.
  32. *
  33. * @category Zend
  34. * @package Zend_Feed
  35. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  36. * @license http://framework.zend.com/license/new-bsd New BSD License
  37. */
  38. abstract class Zend_Feed_Abstract extends Zend_Feed_Element implements Iterator, Countable
  39. {
  40. /**
  41. * Current index on the collection of feed entries for the
  42. * Iterator implementation.
  43. *
  44. * @var integer
  45. */
  46. protected $_entryIndex = 0;
  47. /**
  48. * Cache of feed entries.
  49. *
  50. * @var array
  51. */
  52. protected $_entries;
  53. /**
  54. * Feed constructor
  55. *
  56. * The Zend_Feed_Abstract constructor takes the URI of a feed or a
  57. * feed represented as a string and loads it as XML.
  58. *
  59. * @param string $uri The full URI of the feed to load, or NULL if not retrieved via HTTP or as an array.
  60. * @param string $string The feed as a string, or NULL if retrieved via HTTP or as an array.
  61. * @param Zend_Feed_Builder_Interface $builder The feed as a builder instance or NULL if retrieved as a string or via HTTP.
  62. * @return void
  63. * @throws Zend_Feed_Exception If loading the feed failed.
  64. */
  65. public function __construct($uri = null, $string = null, Zend_Feed_Builder_Interface $builder = null)
  66. {
  67. if ($uri !== null) {
  68. // Retrieve the feed via HTTP
  69. $client = Zend_Feed::getHttpClient();
  70. $client->setUri($uri);
  71. $response = $client->request('GET');
  72. if ($response->getStatus() !== 200) {
  73. /**
  74. * @see Zend_Feed_Exception
  75. */
  76. require_once 'Zend/Feed/Exception.php';
  77. throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus() . '; request: ' . $client->getLastRequest() . "\nresponse: " . $response->asString());
  78. }
  79. $this->_element = $this->_importFeedFromString($response->getBody());
  80. $this->__wakeup();
  81. } elseif ($string !== null) {
  82. // Retrieve the feed from $string
  83. $this->_element = $string;
  84. $this->__wakeup();
  85. } else {
  86. // Generate the feed from the array
  87. $header = $builder->getHeader();
  88. $this->_element = new DOMDocument('1.0', $header['charset']);
  89. $root = $this->_mapFeedHeaders($header);
  90. $this->_mapFeedEntries($root, $builder->getEntries());
  91. $this->_element = $root;
  92. $this->_buildEntryCache();
  93. }
  94. }
  95. /**
  96. * Load the feed as an XML DOMDocument object
  97. *
  98. * @return void
  99. * @throws Zend_Feed_Exception
  100. */
  101. public function __wakeup()
  102. {
  103. @ini_set('track_errors', 1);
  104. $doc = new DOMDocument;
  105. $status = @$doc->loadXML($this->_element);
  106. @ini_restore('track_errors');
  107. if (!$status) {
  108. // prevent the class to generate an undefined variable notice (ZF-2590)
  109. if (!isset($php_errormsg)) {
  110. if (function_exists('xdebug_is_enabled')) {
  111. $php_errormsg = '(error message not available, when XDebug is running)';
  112. } else {
  113. $php_errormsg = '(error message not available)';
  114. }
  115. }
  116. /**
  117. * @see Zend_Feed_Exception
  118. */
  119. require_once 'Zend/Feed/Exception.php';
  120. throw new Zend_Feed_Exception("DOMDocument cannot parse XML: $php_errormsg");
  121. }
  122. $this->_element = $doc;
  123. }
  124. /**
  125. * Prepare for serialiation
  126. *
  127. * @return array
  128. */
  129. public function __sleep()
  130. {
  131. $this->_element = $this->saveXML();
  132. return array('_element');
  133. }
  134. /**
  135. * Cache the individual feed elements so they don't need to be
  136. * searched for on every operation.
  137. *
  138. * @return void
  139. */
  140. protected function _buildEntryCache()
  141. {
  142. $this->_entries = array();
  143. foreach ($this->_element->childNodes as $child) {
  144. if ($child->localName == $this->_entryElementName) {
  145. $this->_entries[] = $child;
  146. }
  147. }
  148. }
  149. /**
  150. * Get the number of entries in this feed object.
  151. *
  152. * @return integer Entry count.
  153. */
  154. public function count()
  155. {
  156. return count($this->_entries);
  157. }
  158. /**
  159. * Required by the Iterator interface.
  160. *
  161. * @return void
  162. */
  163. public function rewind()
  164. {
  165. $this->_entryIndex = 0;
  166. }
  167. /**
  168. * Required by the Iterator interface.
  169. *
  170. * @return mixed The current row, or null if no rows.
  171. */
  172. public function current()
  173. {
  174. return new $this->_entryClassName(
  175. null,
  176. $this->_entries[$this->_entryIndex]);
  177. }
  178. /**
  179. * Required by the Iterator interface.
  180. *
  181. * @return mixed The current row number (starts at 0), or NULL if no rows
  182. */
  183. public function key()
  184. {
  185. return $this->_entryIndex;
  186. }
  187. /**
  188. * Required by the Iterator interface.
  189. *
  190. * @return mixed The next row, or null if no more rows.
  191. */
  192. public function next()
  193. {
  194. ++$this->_entryIndex;
  195. }
  196. /**
  197. * Required by the Iterator interface.
  198. *
  199. * @return boolean Whether the iteration is valid
  200. */
  201. public function valid()
  202. {
  203. return 0 <= $this->_entryIndex && $this->_entryIndex < $this->count();
  204. }
  205. /**
  206. * Generate the header of the feed when working in write mode
  207. *
  208. * @param array $array the data to use
  209. * @return DOMElement root node
  210. */
  211. abstract protected function _mapFeedHeaders($array);
  212. /**
  213. * Generate the entries of the feed when working in write mode
  214. *
  215. * @param DOMElement $root the root node to use
  216. * @param array $array the data to use
  217. * @return DOMElement root node
  218. */
  219. abstract protected function _mapFeedEntries(DOMElement $root, $array);
  220. /**
  221. * Send feed to a http client with the correct header
  222. *
  223. * @throws Zend_Feed_Exception if headers have already been sent
  224. * @return void
  225. */
  226. abstract public function send();
  227. /**
  228. * Import a feed from a string
  229. *
  230. * Protects against XXE attack vectors.
  231. *
  232. * @param string $feed
  233. * @return string
  234. * @throws Zend_Feed_Exception on detection of an XXE vector
  235. */
  236. protected function _importFeedFromString($feed)
  237. {
  238. // Load the feed as an XML DOMDocument object
  239. $libxml_errflag = libxml_use_internal_errors(true);
  240. $libxml_entity_loader = libxml_disable_entity_loader(true);
  241. $doc = new DOMDocument;
  242. if (trim($feed) == '') {
  243. require_once 'Zend/Feed/Exception.php';
  244. throw new Zend_Feed_Exception('Remote feed being imported'
  245. . ' is an Empty string or comes from an empty HTTP response');
  246. }
  247. $status = $doc->loadXML($feed);
  248. libxml_disable_entity_loader($libxml_entity_loader);
  249. libxml_use_internal_errors($libxml_errflag);
  250. if (!$status) {
  251. // prevent the class to generate an undefined variable notice (ZF-2590)
  252. // Build error message
  253. $error = libxml_get_last_error();
  254. if ($error && $error->message) {
  255. $errormsg = "DOMDocument cannot parse XML: {$error->message}";
  256. } else {
  257. $errormsg = "DOMDocument cannot parse XML";
  258. }
  259. /**
  260. * @see Zend_Feed_Exception
  261. */
  262. require_once 'Zend/Feed/Exception.php';
  263. throw new Zend_Feed_Exception($errormsg);
  264. }
  265. return $doc->saveXML($doc->documentElement);
  266. }
  267. }