1<?php 2/** 3 * Sitemap handling functions 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Michael Hamann <michael@content-space.de> 7 */ 8 9namespace dokuwiki\Sitemap; 10 11/** 12 * A class for building sitemaps and pinging search engines with the sitemap URL. 13 * 14 * @author Michael Hamann 15 */ 16class Mapper { 17 /** 18 * Builds a Google Sitemap of all public pages known to the indexer 19 * 20 * The map is placed in the cache directory named sitemap.xml.gz - This 21 * file needs to be writable! 22 * 23 * @author Michael Hamann 24 * @author Andreas Gohr 25 * @link https://www.google.com/webmasters/sitemaps/docs/en/about.html 26 * @link http://www.sitemaps.org/ 27 * 28 * @return bool 29 */ 30 public static function generate(){ 31 global $conf; 32 if($conf['sitemap'] < 1 || !is_numeric($conf['sitemap'])) return false; 33 34 $sitemap = Mapper::getFilePath(); 35 36 if(file_exists($sitemap)){ 37 if(!is_writable($sitemap)) return false; 38 }else{ 39 if(!is_writable(dirname($sitemap))) return false; 40 } 41 42 if(@filesize($sitemap) && 43 @filemtime($sitemap) > (time()-($conf['sitemap']*86400))){ // 60*60*24=86400 44 dbglog('Sitemapper::generate(): Sitemap up to date'); 45 return false; 46 } 47 48 dbglog("Sitemapper::generate(): using $sitemap"); 49 50 $pages = idx_get_indexer()->getPages(); 51 dbglog('Sitemapper::generate(): creating sitemap using '.count($pages).' pages'); 52 $items = array(); 53 54 // build the sitemap items 55 foreach($pages as $id){ 56 //skip hidden, non existing and restricted files 57 if(isHiddenPage($id)) continue; 58 if(auth_aclcheck($id,'',array()) < AUTH_READ) continue; 59 $item = Item::createFromID($id); 60 if ($item !== null) 61 $items[] = $item; 62 } 63 64 $eventData = array('items' => &$items, 'sitemap' => &$sitemap); 65 $event = new \Doku_Event('SITEMAP_GENERATE', $eventData); 66 if ($event->advise_before(true)) { 67 //save the new sitemap 68 $event->result = io_saveFile($sitemap, Mapper::getXML($items)); 69 } 70 $event->advise_after(); 71 72 return $event->result; 73 } 74 75 /** 76 * Builds the sitemap XML string from the given array auf SitemapItems. 77 * 78 * @param $items array The SitemapItems that shall be included in the sitemap. 79 * @return string The sitemap XML. 80 * 81 * @author Michael Hamann 82 */ 83 private static function getXML($items) { 84 ob_start(); 85 echo '<?xml version="1.0" encoding="UTF-8"?>'.NL; 86 echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'.NL; 87 foreach ($items as $item) { 88 /** @var Item $item */ 89 echo $item->toXML(); 90 } 91 echo '</urlset>'.NL; 92 $result = ob_get_contents(); 93 ob_end_clean(); 94 return $result; 95 } 96 97 /** 98 * Helper function for getting the path to the sitemap file. 99 * 100 * @return string The path to the sitemap file. 101 * 102 * @author Michael Hamann 103 */ 104 public static function getFilePath() { 105 global $conf; 106 107 $sitemap = $conf['cachedir'].'/sitemap.xml'; 108 if (self::sitemapIsCompressed()) { 109 $sitemap .= '.gz'; 110 } 111 112 return $sitemap; 113 } 114 115 /** 116 * Helper function for checking if the sitemap is compressed 117 * 118 * @return bool If the sitemap file is compressed 119 */ 120 public static function sitemapIsCompressed() { 121 global $conf; 122 return $conf['compression'] === 'bz2' || $conf['compression'] === 'gz'; 123 } 124 125 /** 126 * Pings search engines with the sitemap url. Plugins can add or remove 127 * urls to ping using the SITEMAP_PING event. 128 * 129 * @author Michael Hamann 130 * 131 * @return bool 132 */ 133 public static function pingSearchEngines() { 134 //ping search engines... 135 $http = new \DokuHTTPClient(); 136 $http->timeout = 8; 137 138 $encoded_sitemap_url = urlencode(wl('', array('do' => 'sitemap'), true, '&')); 139 $ping_urls = array( 140 'google' => 'http://www.google.com/webmasters/sitemaps/ping?sitemap='.$encoded_sitemap_url, 141 'microsoft' => 'http://www.bing.com/webmaster/ping.aspx?siteMap='.$encoded_sitemap_url, 142 'yandex' => 'http://blogs.yandex.ru/pings/?status=success&url='.$encoded_sitemap_url 143 ); 144 145 $data = array('ping_urls' => $ping_urls, 146 'encoded_sitemap_url' => $encoded_sitemap_url 147 ); 148 $event = new \Doku_Event('SITEMAP_PING', $data); 149 if ($event->advise_before(true)) { 150 foreach ($data['ping_urls'] as $name => $url) { 151 dbglog("Sitemapper::PingSearchEngines(): pinging $name"); 152 $resp = $http->get($url); 153 if($http->error) dbglog("Sitemapper:pingSearchengines(): $http->error"); 154 dbglog('Sitemapper:pingSearchengines(): '.preg_replace('/[\n\r]/',' ',strip_tags($resp))); 155 } 156 } 157 $event->advise_after(); 158 159 return true; 160 } 161} 162 163