<?php // namespace components\com_jmap\controllers; /** * @package JMAP::SITEMAP::components::com_jmap * @subpackage controllers * @author Joomla! Extensions Store * @copyright (C) 2015 - Joomla! Extensions Store * @license GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html */ defined ( '_JEXEC' ) or die ( 'Restricted access' ); jimport ( 'joomla.filesystem.file' ); jimport ( 'joomla.filesystem.archive' ); jimport ( 'joomla.filesystem.stream' ); /** * Main controller class * * @package JMAP::SITEMAP::components::com_jmap * @subpackage controllers * @since 1.0 */ class JMapControllerSitemap extends JMapController { /** * Display the Sitemap * * @access public * @return void */ public function display($cachable = false, $urlparams = false) { // Get REQUEST vars all used to makeId for cache handler $option = $this->option; $format = $this->app->input->get ( 'format', 'html' ); $language = $this->app->input->get ( 'lang', null ); $Itemid = $this->app->input->getInt ( 'Itemid', null ); $ItemidFilter = null; if($Itemid) { $loadedMenuItem = JFactory::getApplication()->getMenu()->getItem($Itemid); if( $loadedMenuItem->home != 1 ) { $ItemidFilter = $Itemid ? '_menuid' . $Itemid : null; } } $xslt = $this->app->input->getInt ( 'xslt', null ); $dataset = $this->app->input->getInt ( 'dataset', null ); // Get sitemap model and view core $document = JFactory::getDocument (); $viewType = $document->getType (); $coreName = $this->getNames (); $viewLayout = $this->app->input->get ( 'layout', 'default' ); $view = $this->getView ( $coreName, $viewType, '', array ( 'base_path' => $this->basePath ) ); // Get/Create the model if ($model = $this->getModel ( $coreName, 'JMapModel', array ( 'document_format' => $format, 'jmap_module' => $this->app->input->getInt ( 'jmap_module', null ) ) )) { // Push the model into the view (as default) $view->setModel ( $model, true ); } // Set model state $model->setState ( 'format', $format ); $model->setState ( 'xslt', $xslt ); // Set the layout $view->setLayout ( $viewLayout ); // Display the view checking for cache feature $componentConfig = $model->getComponentParams (); $cachable = $componentConfig->get ( 'enable_view_cache', false ); $preCaching = $componentConfig->get ( 'enable_precaching', false ); if($format != 'html' && $componentConfig->get ( 'remove_sitemap_serp', false )) { $this->app->setHeader('X-Robots-Tag', 'noindex'); } /** * Order of priorities: * precached sitemap if any --> * Joomla cache if any --> * standard realtime generation */ // First requirement: a file exists for this requested precached sitemap $langString = $language ? '_' . $language : null; $datasetFilter = $dataset ? '_dataset' . $dataset : null; $precachedSitemapFileName = JPATH_COMPONENT . '/precache/sitemap_' . $format . $langString . $datasetFilter . $ItemidFilter . '.xml'; if($preCaching && $format != 'html' && file_exists($precachedSitemapFileName)) { // Read the file and stream out directly $precachedBuffer = JFile::read($precachedSitemapFileName); // Is requested an xslt formatted view, so manage xsl adding if($xslt) { $xslFormat = $format == 'xml' ? null : $format . '-'; $xslFile = "<?xml version='1.0' encoding='UTF-8'?>" . PHP_EOL . "<?xml-stylesheet type='text/xsl' href='" . JUri::root() . "components/com_jmap/xslt/xml-" . $xslFormat . "sitemap.xsl'?>"; // Now add replace xsl to sitemap file $precachedBuffer = preg_replace( "/<\?xml version='1.0' encoding='UTF-8'\?>/i", $xslFile, $precachedBuffer); } // Finally stream out sitemap data $document->setMimeEncoding('application/xml'); echo $precachedBuffer; } elseif ($cachable) { $registeredurlparams = new stdClass (); $registeredurlparams->lang = 'CMD'; $registeredurlparams->dataset = 'INT'; $registeredurlparams->Itemid = 'INT'; $registeredurlparams->xslt = 'INT'; $this->app->registeredurlparams = $registeredurlparams; if ($format != 'html') { $document->setMimeEncoding ( 'application/xml' ); } $cache = $this->getExtensionCache (); $cache->get ( $view, 'display' ); } else { $view->display ( $format ); } } /** * Export XML sitemap file * * @access public * @return void */ public function exportXML() { // Get REQUEST vars $option = $this->option; $format = $this->app->input->get ( 'format', 'xml' ); $jsClient = $this->app->input->get ( 'jsclient', false ); $metainfoJsClient = $this->app->input->get ( 'metainfojsclient', false ); $seospiderJsClient = $this->app->input->get ( 'seospiderjsclient', false ); $cronjobClient = $this->app->input->get ( 'cronjobclient', false ); // Manage language file string naming $lang = $this->app->input->get ( 'lang', null ); $langString = $lang ? '_' . $lang : null; $Itemid = $this->app->input->getInt ( 'Itemid', null ); $ItemidFilter = null; if($Itemid) { $loadedMenuItem = JFactory::getApplication()->getMenu()->getItem($Itemid); if( $loadedMenuItem->home != 1 ) { $ItemidFilter = $Itemid ? '_menuid' . $Itemid : null; } } $dataset = $this->app->input->getInt ( 'dataset', null ); $datasetFilter = $dataset ? '_dataset' . $dataset : null; // Get sitemap model and view core $document = JFactory::getDocument (); $viewType = $document->getType (); $coreName = $this->getNames (); $viewLayout = $this->app->input->get ( 'layout', 'default' ); $view = $this->getView ( $coreName, $viewType, '', array ( 'base_path' => $this->basePath ) ); // Get/Create the model if ($model = $this->getModel ( $coreName, 'JMapModel', array ( 'document_format' => $format ) )) { // Push the model into the view (as default) $view->setModel ( $model, true ); } // Set model state $model->setState ( 'format', $format ); $model->setState ( 'metainfojsclient', $metainfoJsClient ); // Set the layout $view->setLayout ( $viewLayout ); $cParams = JComponentHelper::getParams ( 'com_jmap' ); // Display the view checking for cache feature $componentConfig = $model->getComponentParams (); $cachable = $cParams->get ( 'enable_view_cache', false ); $preCaching = $cParams->get ( 'enable_precaching', false ); // Start XML buffer ob_start (); /** * Order of priorities: * precached sitemap if any --> * Joomla cache if any --> * standard realtime generation */ // First requirement: a file exists for this requested precached sitemap $precachedSitemapFileName = JPATH_COMPONENT . '/precache/sitemap_' . $format . $langString . $datasetFilter . $ItemidFilter . '.xml'; $precachedSitemapDirectFile = false; if($preCaching && file_exists($precachedSitemapFileName)) { $precachedSitemapDirectFile = $precachedSitemapFileName; // Read the file and stream out directly $precachedBuffer = JFile::read($precachedSitemapFileName); echo $precachedBuffer; } elseif ($cachable) { $registeredurlparams = new stdClass (); $registeredurlparams->lang = 'CMD'; $registeredurlparams->dataset = 'INT'; $registeredurlparams->Itemid = 'INT'; $registeredurlparams->xslt = 'INT'; $this->app->registeredurlparams = $registeredurlparams; $cache = $this->getExtensionCache (); $cache->get ( $view, 'display' ); } else { $view->display ( $format, true ); } $xmlSitemap = ob_get_contents (); ob_end_clean (); // Choose if split sitemap, exclude rss and videos (including CDATA parsed from XML) and every kind of js client used for analyzer and metainfo if ($cParams->get ( 'split_sitemap', false ) && !$jsClient && !$metainfoJsClient && !$seospiderJsClient && !$cronjobClient && $format != 'rss' && $format != 'videos') { // Split the sitemap $splitter = new JMapXmlSplitter ( $format, $langString, $datasetFilter, $ItemidFilter ); $splitter->chunkXMLString ( $xmlSitemap, 'url', $cParams->get ( 'split_chunks', 5 ), $precachedSitemapDirectFile ); // Check if chunks was generated if ($xmlChunkFiles = $splitter->getChunks ()) { // Create ZIP archive and pass contents of written file to export $archiver = JArchive::getAdapter ( 'zip' ); $pathForArchive = JPATH_COMPONENT_ADMINISTRATOR . '/cache/sitemap_' . $format . $langString . $datasetFilter . $ItemidFilter . '.zip'; $archiver->create ( $pathForArchive, $xmlChunkFiles ); // Export download as attachment if (! $model->exportXMLSitemap ( $pathForArchive, $format, 'zip', $langString, $datasetFilter, $ItemidFilter, 'application/zip', true )) { $msg = 'COM_JMAP_ERROR_EXPORTING_SITEMAP'; $this->setRedirect ( "index.php?option=$option&task=sitemap.display", JText::_ ( $msg ) ); } } } elseif ($jsClient) { $pathForFile = JPATH_COMPONENT_ADMINISTRATOR . '/cache/analyzer/sitemap_' . $format . $langString . $datasetFilter . $ItemidFilter . '.xml'; // Write the current demanded sitemap in the cache analyzer folder $fileWritten = JFile::write($pathForFile, $xmlSitemap); // Response JSON object $jsAppResponse = new stdClass (); $jsAppResponse->result = $fileWritten; $document->setMimeEncoding('application/json'); echo json_encode($jsAppResponse); } elseif ($metainfoJsClient) { $pathForFile = JPATH_COMPONENT_ADMINISTRATOR . '/cache/metainfo/sitemap_' . $format . $langString . $datasetFilter . $ItemidFilter . '.xml'; // Write the current demanded sitemap in the cache analyzer folder $fileWritten = JFile::write($pathForFile, $xmlSitemap); // Response JSON object $jsAppResponse = new stdClass (); $jsAppResponse->result = $fileWritten; $document->setMimeEncoding('application/json'); echo json_encode($jsAppResponse); } elseif ($seospiderJsClient) { $pathForFile = JPATH_COMPONENT_ADMINISTRATOR . '/cache/seospider/sitemap_' . $format . $langString . $datasetFilter . $ItemidFilter . '.xml'; // Write the current demanded sitemap in the cache analyzer folder $fileWritten = JFile::write($pathForFile, $xmlSitemap); // Response JSON object $jsAppResponse = new stdClass (); $jsAppResponse->result = $fileWritten; $document->setMimeEncoding('application/json'); echo json_encode($jsAppResponse); } elseif ($cronjobClient) { $fileName = 'sitemap_' . $format . $langString . $datasetFilter . $ItemidFilter . '.xml'; $pathForFile = JPATH_ROOT . '/' . $fileName; if ($cParams->get ( 'split_sitemap', false ) && $format != 'rss' && $format != 'videos') { // Split the sitemap $splitter = new JMapXmlSplitter ( $format, $langString, $datasetFilter, $ItemidFilter ); $splitter->chunkXMLString ( $xmlSitemap, 'url', $cParams->get ( 'split_chunks', 5 ), $precachedSitemapDirectFile ); // Check if chunks was generated if ($xmlChunkFiles = $splitter->getChunks ()) { if(!empty($xmlChunkFiles)) { foreach ($xmlChunkFiles as $sitemapFile) { $chunkFilePath = JPATH_ROOT . '/' . $sitemapFile['name']; $chunkFileData = $sitemapFile['data']; $fileName = $sitemapFile['name']; $pathForFile = $chunkFilePath; $fileWritten = JFile::write($chunkFilePath, $chunkFileData); } } } } else { // Write the current demanded sitemap to the website root $fileWritten = JFile::write($pathForFile, $xmlSitemap); } // XML Response to the client $document->setMimeEncoding('application/xml'); if($fileWritten) { echo JText::sprintf('COM_JMAP_CRONJOB_FILEWRITTEN_SUCCESS', $fileName, JPATH_ROOT, JUri::root(false) . $fileName, JUri::root(false) . $fileName, $pathForFile); } else { echo JText::sprintf('COM_JMAP_CRONJOB_FILEWRITTEN_ERROR', $fileName, JPATH_ROOT); } } else { if (! $model->exportXMLSitemap ( $xmlSitemap, $format, 'xml', $langString, $datasetFilter, $ItemidFilter, 'application/xml' )) { $msg = 'COM_JMAP_ERROR_EXPORTING_SITEMAP'; $this->setRedirect ( "index.php?option=$option&task=sitemap.display", JText::_ ( $msg ) ); } } } /** * Start a single iteration of a whole precaching process * This controller.task is execute by a JS App Client and the number of * iterations are managed by JS App * * @access public * @return void */ public function doPreCaching() { // Get REQUEST vars $option = $this->option; $format = $this->app->input->get ( 'format', 'xml' ); // Manage language file string naming $lang = $this->app->input->get ( 'lang', null ); $langString = $lang ? '_' . $lang : null; $Itemid = $this->app->input->getInt ( 'Itemid', null ); $ItemidFilter = null; if($Itemid) { $loadedMenuItem = JFactory::getApplication()->getMenu()->getItem($Itemid); if( $loadedMenuItem->home != 1 ) { $ItemidFilter = $Itemid ? '_menuid' . $Itemid : null; } } $dataset = $this->app->input->getInt ( 'dataset', null ); $datasetFilter = $dataset ? '_dataset' . $dataset : null; // Params from javascript application async $dataSourceID = $this->app->input->getInt('datasource_id'); $iterationCounter = $this->app->input->getInt('iteration_counter'); // Get sitemap model and view core $document = JFactory::getDocument (); $viewType = $document->getType (); $coreName = $this->getNames (); $viewLayout = $this->app->input->get ( 'layout', 'default' ); $view = $this->getView ( $coreName, $viewType, '', array ( 'base_path' => $this->basePath ) ); // Get/Create the model if ($model = $this->getModel ( $coreName, 'JMapModel', array ( 'document_format' => $format, 'iteration_counter' => $iterationCounter ) )) { // Push the model into the view (as default) $view->setModel ( $model, true ); } // Set model state $model->setState ( 'format', $format ); $model->setState ( 'datasourceid', $dataSourceID ); // Set the layout $view->setLayout ( $viewLayout ); $cParams = JComponentHelper::getParams ( 'com_jmap' ); // Start XML buffer $xmlSitemap = null; if($this->app->input->get ( 'process_status' ) != 'end') { ob_start (); $view->display ( $format, true ); $xmlSitemap = ob_get_contents (); ob_end_clean (); } // Instance and <<use>> Precacher object $fileStreamWriter = new JStream(); $preCacher = new JMapXmlPrecacher('sitemap_' . $format . $langString . $datasetFilter . $ItemidFilter . '.xml', $fileStreamWriter); $jsAppResponse = $preCacher->mergeSitemap($xmlSitemap); // Format json object for response, get exceptions from model and Precacher class $jsAppResponse->affected_rows = $model->getState( 'affected_rows' ); $document->setMimeEncoding('application/json'); echo json_encode($jsAppResponse); } /** * Class Constructor * * @access public * @return Object& */ public function __construct($config = array()) { parent::__construct ( $config ); $this->registerTask ( 'view', 'display' ); } }