File indexing completed on 2024-12-22 05:36:40
0001 <?php 0002 0003 /** 0004 * Zend Framework 0005 * 0006 * LICENSE 0007 * 0008 * This source file is subject to the new BSD license that is bundled 0009 * with this package in the file LICENSE.txt. 0010 * It is also available through the world-wide-web at this URL: 0011 * http://framework.zend.com/license/new-bsd 0012 * If you did not receive a copy of the license and are unable to 0013 * obtain it through the world-wide-web, please send an email 0014 * to license@zend.com so we can send you a copy immediately. 0015 * 0016 * @category Zend 0017 * @package Zend_Feed 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 0024 /** 0025 * @see Zend_Feed_Element 0026 */ 0027 // require_once 'Zend/Feed/Element.php'; 0028 0029 /** @see Zend_Xml_Security */ 0030 // require_once 'Zend/Xml/Security.php'; 0031 0032 /** 0033 * The Zend_Feed_Abstract class is an abstract class representing feeds. 0034 * 0035 * Zend_Feed_Abstract implements two core PHP 5 interfaces: ArrayAccess and 0036 * Iterator. In both cases the collection being treated as an array is 0037 * considered to be the entry collection, such that iterating over the 0038 * feed takes you through each of the feed.s entries. 0039 * 0040 * @category Zend 0041 * @package Zend_Feed 0042 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0043 * @license http://framework.zend.com/license/new-bsd New BSD License 0044 */ 0045 abstract class Zend_Feed_Abstract extends Zend_Feed_Element implements Iterator, Countable 0046 { 0047 /** 0048 * Current index on the collection of feed entries for the 0049 * Iterator implementation. 0050 * 0051 * @var integer 0052 */ 0053 protected $_entryIndex = 0; 0054 0055 /** 0056 * Cache of feed entries. 0057 * 0058 * @var array 0059 */ 0060 protected $_entries; 0061 0062 /** 0063 * Feed constructor 0064 * 0065 * The Zend_Feed_Abstract constructor takes the URI of a feed or a 0066 * feed represented as a string and loads it as XML. 0067 * 0068 * @param string $uri The full URI of the feed to load, or NULL if not retrieved via HTTP or as an array. 0069 * @param string $string The feed as a string, or NULL if retrieved via HTTP or as an array. 0070 * @param Zend_Feed_Builder_Interface $builder The feed as a builder instance or NULL if retrieved as a string or via HTTP. 0071 * @return void 0072 * @throws Zend_Feed_Exception If loading the feed failed. 0073 */ 0074 public function __construct($uri = null, $string = null, Zend_Feed_Builder_Interface $builder = null) 0075 { 0076 if ($uri !== null) { 0077 // Retrieve the feed via HTTP 0078 $client = Zend_Feed::getHttpClient(); 0079 $client->setUri($uri); 0080 $response = $client->request('GET'); 0081 if ($response->getStatus() !== 200) { 0082 /** 0083 * @see Zend_Feed_Exception 0084 */ 0085 // require_once 'Zend/Feed/Exception.php'; 0086 throw new Zend_Feed_Exception('Feed failed to load, got response code ' . $response->getStatus() . '; request: ' . $client->getLastRequest() . "\nresponse: " . $response->asString()); 0087 } 0088 $this->_element = $this->_importFeedFromString($response->getBody()); 0089 $this->__wakeup(); 0090 } elseif ($string !== null) { 0091 // Retrieve the feed from $string 0092 $this->_element = $string; 0093 $this->__wakeup(); 0094 } else { 0095 // Generate the feed from the array 0096 $header = $builder->getHeader(); 0097 $this->_element = new DOMDocument('1.0', $header['charset']); 0098 $root = $this->_mapFeedHeaders($header); 0099 $this->_mapFeedEntries($root, $builder->getEntries()); 0100 $this->_element = $root; 0101 $this->_buildEntryCache(); 0102 } 0103 } 0104 0105 0106 /** 0107 * Load the feed as an XML DOMDocument object 0108 * 0109 * @return void 0110 * @throws Zend_Feed_Exception 0111 */ 0112 public function __wakeup() 0113 { 0114 @ini_set('track_errors', 1); 0115 $doc = new DOMDocument; 0116 $doc = @Zend_Xml_Security::scan($this->_element, $doc); 0117 @ini_restore('track_errors'); 0118 0119 if (!$doc) { 0120 // prevent the class to generate an undefined variable notice (ZF-2590) 0121 if (!isset($php_errormsg)) { 0122 if (function_exists('xdebug_is_enabled')) { 0123 $php_errormsg = '(error message not available, when XDebug is running)'; 0124 } else { 0125 $php_errormsg = '(error message not available)'; 0126 } 0127 } 0128 0129 /** 0130 * @see Zend_Feed_Exception 0131 */ 0132 // require_once 'Zend/Feed/Exception.php'; 0133 throw new Zend_Feed_Exception("DOMDocument cannot parse XML: $php_errormsg"); 0134 } 0135 0136 $this->_element = $doc; 0137 } 0138 0139 0140 /** 0141 * Prepare for serialiation 0142 * 0143 * @return array 0144 */ 0145 public function __sleep() 0146 { 0147 $this->_element = $this->saveXML(); 0148 0149 return array('_element'); 0150 } 0151 0152 0153 /** 0154 * Cache the individual feed elements so they don't need to be 0155 * searched for on every operation. 0156 * 0157 * @return void 0158 */ 0159 protected function _buildEntryCache() 0160 { 0161 $this->_entries = array(); 0162 foreach ($this->_element->childNodes as $child) { 0163 if ($child->localName == $this->_entryElementName) { 0164 $this->_entries[] = $child; 0165 } 0166 } 0167 } 0168 0169 0170 /** 0171 * Get the number of entries in this feed object. 0172 * 0173 * @return integer Entry count. 0174 */ 0175 public function count() 0176 { 0177 return count($this->_entries); 0178 } 0179 0180 0181 /** 0182 * Required by the Iterator interface. 0183 * 0184 * @return void 0185 */ 0186 public function rewind() 0187 { 0188 $this->_entryIndex = 0; 0189 } 0190 0191 0192 /** 0193 * Required by the Iterator interface. 0194 * 0195 * @return mixed The current row, or null if no rows. 0196 */ 0197 public function current() 0198 { 0199 return new $this->_entryClassName( 0200 null, 0201 $this->_entries[$this->_entryIndex]); 0202 } 0203 0204 0205 /** 0206 * Required by the Iterator interface. 0207 * 0208 * @return mixed The current row number (starts at 0), or NULL if no rows 0209 */ 0210 public function key() 0211 { 0212 return $this->_entryIndex; 0213 } 0214 0215 0216 /** 0217 * Required by the Iterator interface. 0218 * 0219 * @return mixed The next row, or null if no more rows. 0220 */ 0221 public function next() 0222 { 0223 ++$this->_entryIndex; 0224 } 0225 0226 0227 /** 0228 * Required by the Iterator interface. 0229 * 0230 * @return boolean Whether the iteration is valid 0231 */ 0232 public function valid() 0233 { 0234 return 0 <= $this->_entryIndex && $this->_entryIndex < $this->count(); 0235 } 0236 0237 /** 0238 * Generate the header of the feed when working in write mode 0239 * 0240 * @param array $array the data to use 0241 * @return DOMElement root node 0242 */ 0243 abstract protected function _mapFeedHeaders($array); 0244 0245 /** 0246 * Generate the entries of the feed when working in write mode 0247 * 0248 * @param DOMElement $root the root node to use 0249 * @param array $array the data to use 0250 * @return DOMElement root node 0251 */ 0252 abstract protected function _mapFeedEntries(DOMElement $root, $array); 0253 0254 /** 0255 * Send feed to a http client with the correct header 0256 * 0257 * @throws Zend_Feed_Exception if headers have already been sent 0258 * @return void 0259 */ 0260 abstract public function send(); 0261 0262 /** 0263 * Import a feed from a string 0264 * 0265 * Protects against XXE attack vectors. 0266 * 0267 * @param string $feed 0268 * @return string 0269 * @throws Zend_Feed_Exception on detection of an XXE vector 0270 */ 0271 protected function _importFeedFromString($feed) 0272 { 0273 if (trim($feed) == '') { 0274 // require_once 'Zend/Feed/Exception.php'; 0275 throw new Zend_Feed_Exception('Remote feed being imported' 0276 . ' is an Empty string or comes from an empty HTTP response'); 0277 } 0278 $doc = new DOMDocument; 0279 $doc = Zend_Xml_Security::scan($feed, $doc); 0280 0281 if (!$doc) { 0282 // prevent the class to generate an undefined variable notice (ZF-2590) 0283 // Build error message 0284 $error = libxml_get_last_error(); 0285 if ($error && $error->message) { 0286 $errormsg = "DOMDocument cannot parse XML: {$error->message}"; 0287 } else { 0288 $errormsg = "DOMDocument cannot parse XML"; 0289 } 0290 0291 0292 /** 0293 * @see Zend_Feed_Exception 0294 */ 0295 // require_once 'Zend/Feed/Exception.php'; 0296 throw new Zend_Feed_Exception($errormsg); 0297 } 0298 0299 return $doc->saveXML($doc->documentElement); 0300 } 0301 }