Overview

Packages

  • CONTENIDO
  • Core
    • Authentication
    • Backend
    • Cache
    • CEC
    • Chain
    • ContentType
    • Database
    • Debug
    • Exception
    • Frontend
      • Search
      • URI
      • Util
    • GenericDB
      • Model
    • GUI
      • HTML
    • I18N
    • LayoutHandler
    • Log
    • Security
    • Session
    • Util
    • Validation
    • Versioning
    • XML
  • Module
    • ContentRssCreator
    • ContentSitemapHtml
    • ContentSitemapXml
    • ContentUserForum
    • NavigationTop
    • ScriptCookieDirective
  • mpAutoloaderClassMap
  • None
  • Plugin
    • ContentAllocation
    • CronjobOverview
    • FormAssistant
    • FrontendLogic
    • FrontendUsers
    • Linkchecker
    • ModRewrite
    • Newsletter
    • Repository
      • FrontendNavigation
      • KeywordDensity
    • SearchSolr
    • SmartyWrapper
    • UrlShortener
    • UserForum
    • Workflow
  • PluginManager
  • Setup
    • Form
    • GUI
    • Helper
      • Environment
      • Filesystem
      • MySQL
      • PHP
    • UpgradeJob
  • Smarty
    • Cacher
    • Compiler
    • Config
    • Debug
    • PluginsBlock
    • PluginsFilter
    • PluginsFunction
    • PluginsInternal
    • PluginsModifier
    • PluginsModifierCompiler
    • PluginsShared
    • Security
    • Template
    • TemplateResources
  • Swift
    • ByteStream
    • CharacterStream
    • Encoder
    • Events
    • KeyCache
    • Mailer
    • Mime
    • Plugins
    • Transport

Classes

  • Swift_FailoverTransport
  • Swift_LoadBalancedTransport
  • Swift_MailTransport
  • Swift_Plugins_Loggers_ArrayLogger
  • Swift_Plugins_Loggers_EchoLogger
  • Swift_SendmailTransport
  • Swift_SmtpTransport
  • Swift_Transport_AbstractSmtpTransport
  • Swift_Transport_Esmtp_Auth_CramMd5Authenticator
  • Swift_Transport_Esmtp_Auth_LoginAuthenticator
  • Swift_Transport_Esmtp_Auth_PlainAuthenticator
  • Swift_Transport_Esmtp_AuthHandler
  • Swift_Transport_EsmtpTransport
  • Swift_Transport_FailoverTransport
  • Swift_Transport_LoadBalancedTransport
  • Swift_Transport_MailTransport
  • Swift_Transport_SendmailTransport
  • Swift_Transport_SimpleMailInvoker
  • Swift_Transport_StreamBuffer

Interfaces

  • Swift_Plugins_Logger
  • Swift_Plugins_Pop_Pop3Exception
  • Swift_Transport
  • Swift_Transport_Esmtp_Authenticator
  • Swift_Transport_EsmtpHandler
  • Swift_Transport_IoBuffer
  • Swift_Transport_MailInvoker
  • Swift_Transport_SmtpAgent
  • Swift_TransportException
  • Overview
  • Package
  • Function
  • Todo
  • Download
  1: <?php
  2: 
  3: /**
  4:  * Generate an XML sitemap.
  5:  *
  6:  * The module configuration allows for the selection of a category which is used
  7:  * as root to determine articles that will be listed in the sitemap.
  8:  *
  9:  * An optional filename can be defined too. If no filename is given, the sitemap
 10:  * is displayed immediatly. With a filename the sitemap is written to the given
 11:  * file. The filename has to be a basename (no path). The clients frontend path
 12:  * is used instead. In this case this module makes sure that the sitemap is
 13:  * generated only once each 23h.
 14:  *
 15:  * SETTING: content-sitemap-xml/cat-url-for-startart (default: true)
 16:  * If set to true for all startarticles the URL is generated for their category
 17:  * instead for the article itself.
 18:  * This should be done if the navigation produces category links which is
 19:  * usually the case..
 20:  *
 21:  * @package Module
 22:  * @subpackage ContentSitemapXml
 23:  * @version SVN Revision $Rev:$
 24:  *
 25:  * @version SVN Revision $Rev:$
 26:  * @author simon.sprankel@4fb.de
 27:  * @author marcus.gnass@4fb.de
 28:  * @copyright four for business AG
 29:  * @link http://www.4fb.de
 30:  * @see http://www.sitemaps.org/
 31:  */
 32: 
 33: $client = cRegistry::getClientId();
 34: $cfgClient = cRegistry::getClientConfig();
 35: 
 36: // get idcat of category to generate sitemap from
 37: $idcatStart = "CMS_VALUE[1]";
 38: $idcatStart = cSecurity::toInteger($idcatStart);
 39: 
 40: // get filename to save sitemap to (optional)
 41: $filename = "CMS_VALUE[2]";
 42: if (!empty($filename)) {
 43:     $filename = basename($filename);
 44:     // assert .xml extension
 45:     if (substr($filename, -4) !== '.xml') {
 46:         $filename .= '.xml';
 47:     }
 48: }
 49: 
 50: try {
 51: 
 52:     // check if this is a rerun (a cException will then be thrown)
 53:     // check is skipped when 'rerun' is forced
 54:     if (!empty($filename) && !array_key_exists('rerun', $_REQUEST)) {
 55:         checkJobRerun('xml_sitemap_' . cRegistry::getClient()->get('name') . '_' . cRegistry::getLanguage()->get('name'));
 56:     }
 57: 
 58:     // get all categories recursively
 59:     $categoryCollection = new cApiCategoryCollection();
 60:     $categoryIds = $categoryCollection->getAllCategoryIdsRecursive($idcatStart, $client);
 61: 
 62:     $xmlString = <<<EOD
 63: <?xml version="1.0" encoding="UTF-8"?>
 64: <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"></urlset>
 65: EOD;
 66: 
 67:     $sitemap = new SimpleXMLElement($xmlString);
 68: 
 69:     $itemCount = array();
 70: 
 71:     // loop all languages of current client
 72:     $clientLanguageCollection = new cApiClientLanguageCollection();
 73:     foreach ($clientLanguageCollection->getLanguagesByClient($client) as $currentIdlang) {
 74: 
 75:         // skip nonexistant or incative languages
 76:         $language = new cApiLanguage($currentIdlang);
 77:         if (!$language->isLoaded() || '1' != $language->get('active')) {
 78:             continue;
 79:         }
 80: 
 81:         // create copy of category ids
 82:         $arrayObject = new ArrayObject($categoryIds);
 83:         $currentCategoryIds = $arrayObject->getArrayCopy();
 84: 
 85:         // filter the categories - category must be visible and public!
 86:         foreach ($currentCategoryIds as $key => $categoryId) {
 87:             $categoryLanguage = new cApiCategoryLanguage();
 88:             $categoryLanguage->loadByCategoryIdAndLanguageId($categoryId, $currentIdlang);
 89:             if ($categoryLanguage->get('visible') == false || $categoryLanguage->get('public') == false) {
 90:                 unset($currentCategoryIds[$key]);
 91:             }
 92:         }
 93: 
 94:         $itemCount[] = addArticlesToSitemap($sitemap, $currentCategoryIds, $currentIdlang);
 95:     }
 96: 
 97:     // if there are items
 98:     if (0 < array_sum($itemCount)) {
 99:         // provide the possibility to alter the sitemap content
100:         $sitemap = cApiCecHook::executeAndReturn('Contenido.Content.XmlSitemapCreate', $sitemap);
101:     }
102: 
103:     // echo sitemap or write it to file with the specified filename
104:     saveSitemap($sitemap, $filename);
105: } catch (cException $e) {
106:     echo "\n\n[" . date('Y-m-d') . "] " . $e->getMessage() . "\n";
107: }
108: 
109: /**
110:  * Reads timestamp from last job run and compares it to current timestamp.
111:  * If last run is less than 23h ago this script will be aborted. Elsethe
112:  * current timestamp is stored into job file.
113:  *
114:  * @param unknown_type $jobname
115:  * @throws cException if job was already executed within last 23h
116:  */
117: function checkJobRerun($jobname) {
118:     // get filename of cron job file
119:     $cfg = cRegistry::getConfig();
120:     $filename = $cfg['path']['contenido_cronlog'] . $jobname . '.job';
121:     if (cFileHandler::exists($filename)) {
122:         // get timestamp of last runf from cron job file
123:         $cronlogContent = file_get_contents($filename);
124:         $lastRun = cSecurity::toInteger($cronlogContent);
125:         // check timestamp of last run
126:         if ($lastRun > strtotime('-23 hour')) {
127:             // abort if last run is less than 23h ago
128:             throw new cException('job was already executed within last 23h');
129:         }
130:     }
131:     // store current timestamp in cronjob file
132:     file_put_contents($filename, time());
133: }
134: 
135: /**
136:  * Add all online and searchable articles of theses categories to the sitemap.
137:  *
138:  * @param SimpleXMLElement $sitemap
139:  */
140: function addArticlesToSitemap(SimpleXMLElement $sitemap, $categoryIds, $lang) {
141:     $itemCount = 0;
142: 
143:     // check if there are categories
144:     if (0 < count($categoryIds)) {
145: 
146:         $cfg = cRegistry::getConfig();
147:         $tab = $cfg['tab'];
148:         $db = cRegistry::getDb();
149: 
150:         $useCategoryUrlsForStartArticles = 'true' == getEffectiveSetting('content-sitemap-xml', 'cat-url-for-startart', 'true');
151: 
152:         $categoryIds = implode(',', $categoryIds);
153: 
154:         // get articles from DB
155:         $db->query("
156:             SELECT
157:                 art_lang.idart
158:                 , art_lang.idartlang
159:                 , UNIX_TIMESTAMP(art_lang.lastmodified) as lastmod
160:                 , art_lang.changefreq
161:                 , art_lang.sitemapprio
162:                 , cat_art.idcat
163:                 , IF(art_lang.idartlang = cat_lang.startidartlang, 1, 0) AS is_start
164:             FROM
165:                 `$tab[art_lang]` AS art_lang
166:                 , `$tab[cat_art]` AS cat_art
167:                 , `$tab[cat_lang]` AS cat_lang
168:             WHERE
169:                 art_lang.idart = cat_art.idart
170:                 AND art_lang.idlang = $lang
171:                 AND art_lang.online = 1
172:                 AND cat_art.idcat = cat_lang.idcat
173:                 AND cat_art.idcat IN ($categoryIds)
174:                 AND cat_lang.idlang = $lang
175:             ;");
176: 
177:         // construct the XML node
178:         while ($db->nextRecord()) {
179:             $indexState = conGetMetaValue($db->f('idartlang'), 7);
180: 
181:             if (preg_match('/noindex/', $indexState)) {
182:                 continue;
183:             }
184: 
185:             $params = array();
186:             $params['lang'] = $lang;
187:             $params['changelang'] = $lang;
188: 
189:             // if it is a startarticle the generated URL should be that of
190:             // the category (assuming the navigation contains category URLs)
191:             if (1 == $db->f('is_start') && $useCategoryUrlsForStartArticles) {
192:                 $params['idcat'] = $db->f('idcat');
193:             } else {
194:                 $params['idart'] = $db->f('idart');
195:             }
196: 
197:             $loc = cUri::getInstance()->build($params, true);
198:             $loc = htmlentities($loc);
199: 
200:             addUrl($sitemap, array(
201:                 // construct the link
202:                 'loc' => $loc,
203:                 // construct the last modified date in ISO 8601
204:                 'lastmod' => (int) $db->f('lastmod'),
205:                 // get the sitemap change frequency
206:                 'changefreq' => $db->f('changefreq'),
207:                 // get the sitemap priority
208:                 'priority' => $db->f('sitemapprio')
209:             ));
210:             $itemCount++;
211:         }
212:     }
213: 
214:     return $itemCount;
215: }
216: 
217: /**
218:  *
219:  * @param SimpleXMLElement $sitemap
220:  * @param array $data
221:  */
222: function addUrl(SimpleXMLElement $sitemap, array $data) {
223:     $url = $sitemap->addChild('url');
224: 
225:     $url->addChild('loc', $data['loc']);
226: 
227:     if ($data['lastmod'] == '0000-00-00 00:00:00' || $data['lastmod'] == '') {
228:         $url->addChild('lastmod', conHtmlSpecialChars(iso8601Date(mktime())));
229:     } else {
230:         $url->addChild('lastmod', conHtmlSpecialChars(iso8601Date($data['lastmod'])));
231:     }
232: 
233:     if (!empty($data['changefreq'])) {
234:         $url->addChild('changefreq', $data['changefreq']);
235:     }
236: 
237:     if (!empty($data['priority']) || $data['priority'] == 0) {
238:         $url->addChild('priority', $data['priority']);
239:     }
240: }
241: 
242: /**
243:  * Formats a date/time according to ISO 8601.
244:  *
245:  * Example:
246:  * YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
247:  *
248:  * @param int $time a UNIX timestamp
249:  * @return string the formatted date string
250:  */
251: function iso8601Date($time) {
252:     $tzd = date('O', $time);
253:     $tzd = chunk_split($tzd, 3, ':');
254:     $tzd = substr($tzd, 0, 6);
255:     $date = date('Y-m-d\TH:i:s', $time);
256:     return $date . $tzd;
257: }
258: 
259: /**
260:  * Saves the sitemap to the file with the given filename.
261:  * If no filename is given, it outputs the sitemap.
262:  *
263:  * @todo How can I save this properly formatted?
264:  * @see http://stackoverflow.com/questions/1191167/format-output-of-simplexml-asxml
265:  * @param SimpleXMLElement $sitemap the XML structure of the sitemap
266:  * @param string $filename [optional] the filename to which the sitemap should
267:  *        be written
268:  */
269: function saveSitemap(SimpleXMLElement $sitemap, $filename = '') {
270:     if (empty($filename)) {
271:         header('Content-type: text/xml');
272:         echo $sitemap->asXML();
273:     } else if ($sitemap->asXML($cfgClient[$client]['path']['frontend'] . $filename)) {
274:         echo conHtmlSpecialChars(mi18n("XML sitemap successfully written to %s", $filename));
275:     } else {
276:         echo conHtmlSpecialChars(mi18n("XML sitemap could not be written to %s", $filename));
277:     }
278: }
279: 
280: ?>
CMS CONTENIDO 4.9.7 API documentation generated by ApiGen