setUri($uri); $response = $client->request('GET'); if ($response->getStatus() !== 200) { /** * @see Zend_Feed_Exception */ #require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus() . '; request: ' . $client->getLastRequest() . "\nresponse: " . $response->asString()); } $this->_element = $this->_importFeedFromString($response->getBody()); $this->__wakeup(); } elseif ($string !== null) { // Retrieve the feed from $string $this->_element = $string; $this->__wakeup(); } else { // Generate the feed from the array $header = $builder->getHeader(); $this->_element = new DOMDocument('1.0', $header['charset']); $root = $this->_mapFeedHeaders($header); $this->_mapFeedEntries($root, $builder->getEntries()); $this->_element = $root; $this->_buildEntryCache(); } } /** * Load the feed as an XML DOMDocument object * * @return void * @throws Zend_Feed_Exception */ public function __wakeup() { @ini_set('track_errors', 1); $doc = new DOMDocument; $status = @$doc->loadXML($this->_element); @ini_restore('track_errors'); if (!$status) { // prevent the class to generate an undefined variable notice (ZF-2590) if (!isset($php_errormsg)) { if (function_exists('xdebug_is_enabled')) { $php_errormsg = '(error message not available, when XDebug is running)'; } else { $php_errormsg = '(error message not available)'; } } /** * @see Zend_Feed_Exception */ #require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception("DOMDocument cannot parse XML: $php_errormsg"); } $this->_element = $doc; } /** * Prepare for serialiation * * @return array */ public function __sleep() { $this->_element = $this->saveXML(); return array('_element'); } /** * Cache the individual feed elements so they don't need to be * searched for on every operation. * * @return void */ protected function _buildEntryCache() { $this->_entries = array(); foreach ($this->_element->childNodes as $child) { if ($child->localName == $this->_entryElementName) { $this->_entries[] = $child; } } } /** * Get the number of entries in this feed object. * * @return integer Entry count. */ public function count() { return count($this->_entries); } /** * Required by the Iterator interface. * * @return void */ public function rewind() { $this->_entryIndex = 0; } /** * Required by the Iterator interface. * * @return mixed The current row, or null if no rows. */ public function current() { return new $this->_entryClassName( null, $this->_entries[$this->_entryIndex]); } /** * Required by the Iterator interface. * * @return mixed The current row number (starts at 0), or NULL if no rows */ public function key() { return $this->_entryIndex; } /** * Required by the Iterator interface. * * @return mixed The next row, or null if no more rows. */ public function next() { ++$this->_entryIndex; } /** * Required by the Iterator interface. * * @return boolean Whether the iteration is valid */ public function valid() { return 0 <= $this->_entryIndex && $this->_entryIndex < $this->count(); } /** * Generate the header of the feed when working in write mode * * @param array $array the data to use * @return DOMElement root node */ abstract protected function _mapFeedHeaders($array); /** * Generate the entries of the feed when working in write mode * * @param DOMElement $root the root node to use * @param array $array the data to use * @return DOMElement root node */ abstract protected function _mapFeedEntries(DOMElement $root, $array); /** * Send feed to a http client with the correct header * * @throws Zend_Feed_Exception if headers have already been sent * @return void */ abstract public function send(); /** * Import a feed from a string * * Protects against XXE attack vectors. * * @param string $feed * @return string * @throws Zend_Feed_Exception on detection of an XXE vector */ protected function _importFeedFromString($feed) { // Load the feed as an XML DOMDocument object $libxml_errflag = libxml_use_internal_errors(true); $libxml_entity_loader = libxml_disable_entity_loader(true); $doc = new DOMDocument; if (trim($feed) == '') { #require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception('Remote feed being imported' . ' is an Empty string or comes from an empty HTTP response'); } $status = $doc->loadXML($feed); libxml_disable_entity_loader($libxml_entity_loader); libxml_use_internal_errors($libxml_errflag); if (!$status) { // prevent the class to generate an undefined variable notice (ZF-2590) // Build error message $error = libxml_get_last_error(); if ($error && $error->message) { $errormsg = "DOMDocument cannot parse XML: {$error->message}"; } else { $errormsg = "DOMDocument cannot parse XML"; } /** * @see Zend_Feed_Exception */ #require_once 'Zend/Feed/Exception.php'; throw new Zend_Feed_Exception($errormsg); } return $doc->saveXML($doc->documentElement); } }