File indexing completed on 2024-12-29 05:28:12
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_View 0017 * @subpackage Helper 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 * @see Zend_View_Helper_Navigation_HelperAbstract 0025 */ 0026 // require_once 'Zend/View/Helper/Navigation/HelperAbstract.php'; 0027 0028 /** 0029 * Helper for printing sitemaps 0030 * 0031 * @link http://www.sitemaps.org/protocol.php 0032 * 0033 * @category Zend 0034 * @package Zend_View 0035 * @subpackage Helper 0036 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0037 * @license http://framework.zend.com/license/new-bsd New BSD License 0038 */ 0039 class Zend_View_Helper_Navigation_Sitemap 0040 extends Zend_View_Helper_Navigation_HelperAbstract 0041 { 0042 /** 0043 * Namespace for the <urlset> tag 0044 * 0045 * @var string 0046 */ 0047 const SITEMAP_NS = 'http://www.sitemaps.org/schemas/sitemap/0.9'; 0048 0049 /** 0050 * Schema URL 0051 * 0052 * @var string 0053 */ 0054 const SITEMAP_XSD = 'http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd'; 0055 0056 /** 0057 * Whether the XML declaration should be included in XML output 0058 * 0059 * @var bool 0060 */ 0061 protected $_useXmlDeclaration = true; 0062 0063 /** 0064 * Whether sitemap should be validated using Zend_Validate_Sitemap_* 0065 * 0066 * @var bool 0067 */ 0068 protected $_useSitemapValidators = true; 0069 0070 /** 0071 * Whether sitemap should be schema validated when generated 0072 * 0073 * @var bool 0074 */ 0075 protected $_useSchemaValidation = false; 0076 0077 /** 0078 * Server url 0079 * 0080 * @var string 0081 */ 0082 protected $_serverUrl; 0083 0084 /** 0085 * View helper entry point: 0086 * Retrieves helper and optionally sets container to operate on 0087 * 0088 * @param Zend_Navigation_Container $container [optional] container to 0089 * operate on 0090 * @return Zend_View_Helper_Navigation_Sitemap fluent interface, returns 0091 * self 0092 */ 0093 public function sitemap(Zend_Navigation_Container $container = null) 0094 { 0095 if (null !== $container) { 0096 $this->setContainer($container); 0097 } 0098 0099 return $this; 0100 } 0101 0102 // Accessors: 0103 0104 /** 0105 * Sets whether the XML declaration should be used in output 0106 * 0107 * @param bool $useXmlDecl whether XML delcaration 0108 * should be rendered 0109 * @return Zend_View_Helper_Navigation_Sitemap fluent interface, returns 0110 * self 0111 */ 0112 public function setUseXmlDeclaration($useXmlDecl) 0113 { 0114 $this->_useXmlDeclaration = (bool) $useXmlDecl; 0115 return $this; 0116 } 0117 0118 /** 0119 * Returns whether the XML declaration should be used in output 0120 * 0121 * @return bool whether the XML declaration should be used in output 0122 */ 0123 public function getUseXmlDeclaration() 0124 { 0125 return $this->_useXmlDeclaration; 0126 } 0127 0128 /** 0129 * Sets whether sitemap should be validated using Zend_Validate_Sitemap_* 0130 * 0131 * @param bool $useSitemapValidators whether sitemap validators 0132 * should be used 0133 * @return Zend_View_Helper_Navigation_Sitemap fluent interface, returns 0134 * self 0135 */ 0136 public function setUseSitemapValidators($useSitemapValidators) 0137 { 0138 $this->_useSitemapValidators = (bool) $useSitemapValidators; 0139 return $this; 0140 } 0141 0142 /** 0143 * Returns whether sitemap should be validated using Zend_Validate_Sitemap_* 0144 * 0145 * @return bool whether sitemap should be validated using validators 0146 */ 0147 public function getUseSitemapValidators() 0148 { 0149 return $this->_useSitemapValidators; 0150 } 0151 0152 /** 0153 * Sets whether sitemap should be schema validated when generated 0154 * 0155 * @param bool $schemaValidation whether sitemap should 0156 * validated using XSD Schema 0157 * @return Zend_View_Helper_Navigation_Sitemap fluent interface, returns 0158 * self 0159 */ 0160 public function setUseSchemaValidation($schemaValidation) 0161 { 0162 $this->_useSchemaValidation = (bool) $schemaValidation; 0163 return $this; 0164 } 0165 0166 /** 0167 * Returns true if sitemap should be schema validated when generated 0168 * 0169 * @return bool 0170 */ 0171 public function getUseSchemaValidation() 0172 { 0173 return $this->_useSchemaValidation; 0174 } 0175 0176 /** 0177 * Sets server url (scheme and host-related stuff without request URI) 0178 * 0179 * E.g. http://www.example.com 0180 * 0181 * @param string $serverUrl server URL to set (only 0182 * scheme and host) 0183 * @throws Zend_Uri_Exception if invalid server URL 0184 * @return Zend_View_Helper_Navigation_Sitemap fluent interface, returns 0185 * self 0186 */ 0187 public function setServerUrl($serverUrl) 0188 { 0189 // require_once 'Zend/Uri.php'; 0190 $uri = Zend_Uri::factory($serverUrl); 0191 $uri->setFragment(''); 0192 $uri->setPath(''); 0193 $uri->setQuery(''); 0194 0195 if ($uri->valid()) { 0196 $this->_serverUrl = $uri->getUri(); 0197 } else { 0198 // require_once 'Zend/Uri/Exception.php'; 0199 $e = new Zend_Uri_Exception(sprintf( 0200 'Invalid server URL: "%s"', 0201 $serverUrl)); 0202 $e->setView($this->view); 0203 throw $e; 0204 } 0205 0206 return $this; 0207 } 0208 0209 /** 0210 * Returns server URL 0211 * 0212 * @return string server URL 0213 */ 0214 public function getServerUrl() 0215 { 0216 if (!isset($this->_serverUrl)) { 0217 $this->_serverUrl = $this->view->serverUrl(); 0218 } 0219 0220 return $this->_serverUrl; 0221 } 0222 0223 // Helper methods: 0224 0225 /** 0226 * Escapes string for XML usage 0227 * 0228 * @param string $string string to escape 0229 * @return string escaped string 0230 */ 0231 protected function _xmlEscape($string) 0232 { 0233 $enc = 'UTF-8'; 0234 if ($this->view instanceof Zend_View_Interface 0235 && method_exists($this->view, 'getEncoding') 0236 ) { 0237 $enc = $this->view->getEncoding(); 0238 } 0239 0240 // do not encode existing HTML entities 0241 return htmlspecialchars($string, ENT_QUOTES, $enc, false); 0242 } 0243 0244 // Public methods: 0245 0246 /** 0247 * Returns an escaped absolute URL for the given page 0248 * 0249 * @param Zend_Navigation_Page $page page to get URL from 0250 * @return string 0251 */ 0252 public function url(Zend_Navigation_Page $page) 0253 { 0254 $href = $page->getHref(); 0255 0256 if (!isset($href{0})) { 0257 // no href 0258 return ''; 0259 } elseif ($href{0} == '/') { 0260 // href is relative to root; use serverUrl helper 0261 $url = $this->getServerUrl() . $href; 0262 } elseif (preg_match('/^[a-z]+:/im', (string) $href)) { 0263 // scheme is given in href; assume absolute URL already 0264 $url = (string) $href; 0265 } else { 0266 // href is relative to current document; use url helpers 0267 $url = $this->getServerUrl() 0268 . rtrim($this->view->url(), '/') . '/' 0269 . $href; 0270 } 0271 0272 return $this->_xmlEscape($url); 0273 } 0274 0275 /** 0276 * Returns a DOMDocument containing the Sitemap XML for the given container 0277 * 0278 * @param Zend_Navigation_Container $container [optional] container to get 0279 * breadcrumbs from, defaults 0280 * to what is registered in the 0281 * helper 0282 * @return DOMDocument DOM representation of the 0283 * container 0284 * @throws Zend_View_Exception if schema validation is on 0285 * and the sitemap is invalid 0286 * according to the sitemap 0287 * schema, or if sitemap 0288 * validators are used and the 0289 * loc element fails validation 0290 */ 0291 public function getDomSitemap(Zend_Navigation_Container $container = null) 0292 { 0293 if (null === $container) { 0294 $container = $this->getContainer(); 0295 } 0296 0297 // check if we should validate using our own validators 0298 if ($this->getUseSitemapValidators()) { 0299 // require_once 'Zend/Validate/Sitemap/Changefreq.php'; 0300 // require_once 'Zend/Validate/Sitemap/Lastmod.php'; 0301 // require_once 'Zend/Validate/Sitemap/Loc.php'; 0302 // require_once 'Zend/Validate/Sitemap/Priority.php'; 0303 0304 // create validators 0305 $locValidator = new Zend_Validate_Sitemap_Loc(); 0306 $lastmodValidator = new Zend_Validate_Sitemap_Lastmod(); 0307 $changefreqValidator = new Zend_Validate_Sitemap_Changefreq(); 0308 $priorityValidator = new Zend_Validate_Sitemap_Priority(); 0309 } 0310 0311 // create document 0312 $dom = new DOMDocument('1.0', 'UTF-8'); 0313 $dom->formatOutput = $this->getFormatOutput(); 0314 0315 // ...and urlset (root) element 0316 $urlSet = $dom->createElementNS(self::SITEMAP_NS, 'urlset'); 0317 $dom->appendChild($urlSet); 0318 0319 // create iterator 0320 $iterator = new RecursiveIteratorIterator($container, 0321 RecursiveIteratorIterator::SELF_FIRST); 0322 0323 $maxDepth = $this->getMaxDepth(); 0324 if (is_int($maxDepth)) { 0325 $iterator->setMaxDepth($maxDepth); 0326 } 0327 $minDepth = $this->getMinDepth(); 0328 if (!is_int($minDepth) || $minDepth < 0) { 0329 $minDepth = 0; 0330 } 0331 0332 // iterate container 0333 foreach ($iterator as $page) { 0334 if ($iterator->getDepth() < $minDepth || !$this->accept($page)) { 0335 // page should not be included 0336 continue; 0337 } 0338 0339 // get absolute url from page 0340 if (!$url = $this->url($page)) { 0341 // skip page if it has no url (rare case) 0342 continue; 0343 } 0344 0345 // create url node for this page 0346 $urlNode = $dom->createElementNS(self::SITEMAP_NS, 'url'); 0347 $urlSet->appendChild($urlNode); 0348 0349 if ($this->getUseSitemapValidators() && 0350 !$locValidator->isValid($url)) { 0351 // require_once 'Zend/View/Exception.php'; 0352 $e = new Zend_View_Exception(sprintf( 0353 'Encountered an invalid URL for Sitemap XML: "%s"', 0354 $url)); 0355 $e->setView($this->view); 0356 throw $e; 0357 } 0358 0359 // put url in 'loc' element 0360 $urlNode->appendChild($dom->createElementNS(self::SITEMAP_NS, 0361 'loc', $url)); 0362 0363 // add 'lastmod' element if a valid lastmod is set in page 0364 if (isset($page->lastmod)) { 0365 $lastmod = strtotime((string) $page->lastmod); 0366 0367 // prevent 1970-01-01... 0368 if ($lastmod !== false) { 0369 $lastmod = date('c', $lastmod); 0370 } 0371 0372 if (!$this->getUseSitemapValidators() || 0373 $lastmodValidator->isValid($lastmod)) { 0374 $urlNode->appendChild( 0375 $dom->createElementNS(self::SITEMAP_NS, 'lastmod', 0376 $lastmod) 0377 ); 0378 } 0379 } 0380 0381 // add 'changefreq' element if a valid changefreq is set in page 0382 if (isset($page->changefreq)) { 0383 $changefreq = $page->changefreq; 0384 if (!$this->getUseSitemapValidators() || 0385 $changefreqValidator->isValid($changefreq)) { 0386 $urlNode->appendChild( 0387 $dom->createElementNS(self::SITEMAP_NS, 'changefreq', 0388 $changefreq) 0389 ); 0390 } 0391 } 0392 0393 // add 'priority' element if a valid priority is set in page 0394 if (isset($page->priority)) { 0395 $priority = $page->priority; 0396 if (!$this->getUseSitemapValidators() || 0397 $priorityValidator->isValid($priority)) { 0398 $urlNode->appendChild( 0399 $dom->createElementNS(self::SITEMAP_NS, 'priority', 0400 $priority) 0401 ); 0402 } 0403 } 0404 } 0405 0406 // validate using schema if specified 0407 if ($this->getUseSchemaValidation()) { 0408 if (!@$dom->schemaValidate(self::SITEMAP_XSD)) { 0409 // require_once 'Zend/View/Exception.php'; 0410 $e = new Zend_View_Exception(sprintf( 0411 'Sitemap is invalid according to XML Schema at "%s"', 0412 self::SITEMAP_XSD)); 0413 $e->setView($this->view); 0414 throw $e; 0415 } 0416 } 0417 0418 return $dom; 0419 } 0420 0421 // Zend_View_Helper_Navigation_Helper: 0422 0423 /** 0424 * Renders helper 0425 * 0426 * Implements {@link Zend_View_Helper_Navigation_Helper::render()}. 0427 * 0428 * @param Zend_Navigation_Container $container [optional] container to 0429 * render. Default is to 0430 * render the container 0431 * registered in the helper. 0432 * @return string helper output 0433 */ 0434 public function render(Zend_Navigation_Container $container = null) 0435 { 0436 $dom = $this->getDomSitemap($container); 0437 0438 $xml = $this->getUseXmlDeclaration() ? 0439 $dom->saveXML() : 0440 $dom->saveXML($dom->documentElement); 0441 0442 return rtrim($xml, self::EOL); 0443 } 0444 }