PageRenderTime 3ms CodeModel.GetById 18ms app.highlight 56ms RepoModel.GetById 1ms app.codeStats 1ms

/gsitemap/gsitemap.php

https://github.com/DaveBenNoah/PrestaShop-modules
PHP | 867 lines | 602 code | 83 blank | 182 comment | 89 complexity | dc6f8693f673aaa024dbdf6a07010ef6 MD5 | raw file
  1<?php
  2
  3/*
  4 *  2007-2014 PrestaShop
  5 *
  6 * NOTICE OF LICENSE
  7 * This source file is subject to the Academic Free License (AFL 3.0)
  8 * that is bundled with this package in the file LICENSE.txt.
  9 * It is also available through the world-wide-web at this URL:
 10 * http://opensource.org/licenses/afl-3.0.php* If you did not receive a copy of the license and are unable to
 11 * obtain it through the world-wide-web, please send an email
 12 * to license@prestashop.com so we can send you a copy immediately.
 13 *
 14 * DISCLAIMER
 15 *
 16 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
 17 * versions in the future. If you wish to customize PrestaShop for your
 18 * needs please refer to http://www.prestashop.com for more information.
 19 *
 20 *  @author PrestaShop SA <contact@prestashop.com>
 21 *  @copyright  2007-2014 PrestaShop SA
 22 *  @version  Release: $Revision: 7515 $
 23 *  @license    http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
 24 *  International Registered Trademark & Property of PrestaShop SA
 25 */
 26if (!defined('_PS_VERSION_'))
 27	exit;
 28
 29class Gsitemap extends Module
 30{
 31
 32	public $cron = false;
 33	private $sql_checks = array();
 34
 35	public function __construct()
 36	{
 37		$this->name = 'gsitemap';
 38		$this->tab = 'seo';
 39		$this->version = '2.3.9';
 40		$this->author = 'PrestaShop';
 41		$this->need_instance = 0;
 42
 43		parent::__construct();
 44		
 45		$this->displayName = $this->l('Google sitemap');
 46		$this->description = $this->l('Generate your Google sitemap file');
 47	}
 48
 49	/**
 50	 * Google Sitemap installation process:
 51	 *
 52	 * Step 1 - Pre-set Configuration option values
 53	 * Step 2 - Install the Addon and create a database table to store Sitemap files name by shop
 54	 *
 55	 * @return boolean Installation result
 56	 */
 57	public function install()
 58	{
 59		foreach (array(
 60			'GSITEMAP_PRIORITY_HOME' => 1.0,
 61			'GSITEMAP_PRIORITY_PRODUCT' => 0.9,
 62			'GSITEMAP_PRIORITY_CATEGORY' => 0.8,
 63			'GSITEMAP_PRIORITY_MANUFACTURER' => 0.7,
 64			'GSITEMAP_PRIORITY_SUPPLIER' => 0.6,
 65			'GSITEMAP_PRIORITY_CMS' => 0.5,
 66			'GSITEMAP_FREQUENCY' => 'weekly',
 67			'GSITEMAP_CHECK_IMAGE_FILE' => false,
 68			'GSITEMAP_LAST_EXPORT' => false
 69		) as $key => $val)
 70			if (!Configuration::updateValue($key, $val))
 71				return false;
 72
 73		return parent::install() &&
 74		Db::getInstance()->Execute('CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'gsitemap_sitemap` (`link` varchar(255) DEFAULT NULL, `id_shop` int(11) DEFAULT 0) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;') &&
 75		$this->_installOverride();
 76	}
 77
 78	private function _installOverride()
 79	{
 80		if (_PS_VERSION_ != '1.4.11.0')
 81			return true;
 82		if (!is_dir(dirname(__FILE__).'/../../override/classes/'))
 83			mkdir(dirname(__FILE__).'/../../override/classes/', 0777, true);
 84		if (file_exists(dirname(__FILE__).'/../../override/classes/Shop.php'))
 85			rename(dirname(__FILE__).'/../../override/classes/Shop.php', dirname(__FILE__).'/../../override/classes/Shop.origin.php');
 86		if (!copy(dirname(__FILE__).'/override14/classes/Shop.php', dirname(__FILE__).'/../../override/classes/Shop.php'))
 87			return false;
 88
 89		return true;
 90	}
 91
 92
 93	/**
 94	 * Google Sitemap uninstallation process:
 95	 *
 96	 * Step 1 - Remove Configuration option values from database
 97	 * Step 2 - Remove the database containing the generated Sitemap files names
 98	 * Step 3 - Uninstallation of the Addon itself
 99	 *
100	 * @return boolean Uninstallation result
101	 */
102	public function uninstall()
103	{
104		foreach (array(
105			'GSITEMAP_PRIORITY_HOME' => '',
106			'GSITEMAP_PRIORITY_PRODUCT' => '',
107			'GSITEMAP_PRIORITY_CATEGORY' => '',
108			'GSITEMAP_PRIORITY_MANUFACTURER' => '',
109			'GSITEMAP_PRIORITY_SUPPLIER' => '',
110			'GSITEMAP_PRIORITY_CMS' => '',
111			'GSITEMAP_FREQUENCY' => '',
112			'GSITEMAP_CHECK_IMAGE_FILE' => '',
113			'GSITEMAP_LAST_EXPORT' => ''
114		) as $key => $val)
115			if (!Configuration::deleteByName($key))
116				return false;
117
118		return parent::uninstall() && $this->removeSitemap();
119	}
120
121	/**
122	 * Delete all the generated Sitemap files  and drop the addon table.
123	 * @return boolean
124	 */
125	public function removeSitemap()
126	{
127		$links = Db::getInstance()->ExecuteS('SELECT * FROM `'._DB_PREFIX_.'gsitemap_sitemap`');
128		if ($links)
129			foreach ($links as $link)
130				if (!@unlink(dirname(__FILE__).'/../../'.$link['link']))
131					return false;
132		if (!Db::getInstance()->Execute('DROP TABLE `'._DB_PREFIX_.'gsitemap_sitemap`'))
133			return false;
134
135		return true;
136	}
137
138	public function getContent()
139	{
140		/* Store the posted parameters and generate a new Google Sitemap files for the current Shop */
141		if (Tools::isSubmit('SubmitGsitemap'))
142		{
143			Configuration::updateValue('GSITEMAP_FREQUENCY', pSQL(Tools::getValue('gsitemap_frequency')));
144			Configuration::updateValue('GSITEMAP_INDEX_CHECK', '');
145			Configuration::updateValue('GSITEMAP_CHECK_IMAGE_FILE', pSQL(Tools::getValue('gsitemap_check_image_file')));
146			$meta = '';
147			if (Tools::getValue('gsitemap_meta'))
148				$meta .= implode(', ', Tools::getValue('gsitemap_meta'));
149			Configuration::updateValue('GSITEMAP_DISABLE_LINKS', $meta);
150			$this->emptySitemap();
151			$this->createSitemap();
152		}
153		/* if no posted form and the variable [continue] is found in the HTTP request variable keep creating sitemap */
154		elseif (Tools::getValue('continue'))
155			$this->createSitemap();
156
157		/* Backward compatibility */
158		if (_PS_VERSION_ < 1.5)
159			require(_PS_MODULE_DIR_.'gsitemap/backward_compatibility/backward.php');
160
161		/* Empty the Shop domain cache */
162		if (method_exists('ShopUrl', 'resetMainDomainCache'))
163			ShopUrl::resetMainDomainCache();
164
165		$this->context->smarty->assign(
166			array(
167				'gsitemap_form' => './index.php?tab=AdminModules&configure=gsitemap&token='.Tools::getAdminTokenLite('AdminModules').'&tab_module='.$this->tab.'&module_name=gsitemap',
168				'gsitemap_cron' => _PS_BASE_URL_._MODULE_DIR_.'gsitemap/gsitemap-cron.php?token='.substr(Tools::encrypt('gsitemap/cron'), 0, 10).'&id_shop='.$this->context->shop->id,
169				'gsitemap_feed_exists' => file_exists(dirname(__FILE__).'/../../index_sitemap.xml'),
170				'gsitemap_last_export' => Configuration::get('GSITEMAP_LAST_EXPORT'),
171				'gsitemap_frequency' => Configuration::get('GSITEMAP_FREQUENCY'),
172				'gsitemap_store_url' => 'http://'.Tools::getShopDomain(false, true).__PS_BASE_URI__,
173				'gsitemap_links' => Db::getInstance()->ExecuteS('SELECT * FROM `'._DB_PREFIX_.'gsitemap_sitemap` WHERE id_shop = '.(int)$this->context->shop->id),
174				'store_metas' => Meta::getMetasByIdLang((int)$this->context->cookie->id_lang),
175				'gsitemap_disable_metas' => explode(',', Configuration::get('GSITEMAP_DISABLE_LINKS')),
176				'gsitemap_customer_limit' => array(
177					'max_exec_time' => (int)ini_get('max_execution_time'),
178					'memory_limit' => intval(ini_get('memory_limit'))
179				),
180				'prestashop_version' => _PS_VERSION_ >= 1.5 ? '1.5' : '1.4',
181				'prestashop_ssl' => Configuration::get('PS_SSL_ENABLED'),
182				'gsitemap_check_image_file' => Configuration::get('GSITEMAP_CHECK_IMAGE_FILE'),
183				'shop' => $this->context->shop
184			)
185		);
186
187		return $this->display(__FILE__, 'tpl/configuration.tpl');
188	}
189
190	/**
191	 * Delete all the generated Sitemap files from the files system and the database.
192	 *
193	 * @param int $id_shop
194	 *
195	 * @return bool
196	 */
197	public function emptySitemap($id_shop = 0)
198	{
199		if (!isset($this->context))
200			$this->context = new Context();
201		if ($id_shop != 0)
202			$this->context->shop = new Shop((int)$id_shop);
203		$links = Db::getInstance()->ExecuteS('SELECT * FROM `'._DB_PREFIX_.'gsitemap_sitemap` WHERE id_shop = '.(int)$this->context->shop->id);
204		if ($links)
205		{
206			foreach ($links as $link)
207				@unlink(dirname(__FILE__).'/../../'.$link['link']);
208
209			return Db::getInstance()->Execute('DELETE FROM `'._DB_PREFIX_.'gsitemap_sitemap` WHERE id_shop = '.(int)$this->context->shop->id);
210		}
211
212		return true;
213	}
214
215	/**
216	 * @param array  $link_sitemap contain all the links for the Google Sitemap file to be generated
217	 * @param array  $new_link     contain the link elements
218	 * @param string $lang         language of link to add
219	 * @param int    $index        index of the current Google Sitemap file
220	 * @param int    $i            count of elements added to sitemap main array
221	 * @param int    $id_obj       identifier of the object of the link to be added to the Gogle Sitemap file
222	 *
223	 * @return bool
224	 */
225	public function _addLinkToSitemap(&$link_sitemap, $new_link, $lang, &$index, &$i, $id_obj)
226	{
227		if ($i <= 25000 && memory_get_usage() < 100000000)
228		{
229			$link_sitemap[] = $new_link;
230			$i++;
231
232			return true;
233		}
234		else
235		{
236			$this->_recursiveSitemapCreator($link_sitemap, $lang, $index);
237			if ($index % 20 == 0 && !$this->cron)
238			{
239				$this->context->smarty->assign(
240					array(
241						'gsitemap_number' => (int)$index,
242						'gsitemap_refresh_page' => './index.php?tab=AdminModules&configure=gsitemap&token='.Tools::getAdminTokenLite('AdminModules').'&tab_module='.$this->tab.'&module_name=gsitemap&continue=1&type='.$new_link['type'].'&lang='.$lang.'&index='.$index.'&id='.($id_obj + 1).'&id_shop='.$this->context->shop->id
243					)
244				);
245
246				return false;
247			}
248			else if ($index % 20 == 0 && $this->cron)
249			{
250				header('Refresh: 5; url=http'.(Configuration::get('PS_SSL_ENABLED') ? 's' : '').'://'.Tools::getShopDomain(false, true).__PS_BASE_URI__.'modules/gsitemap/gsitemap-cron.php?continue=1&token='.substr(Tools::encrypt('gsitemap/cron'), 0, 10).'&type='.$new_link['type'].'&lang='.$lang.'&index='.$index.'&id='.($id_obj + 1).'&id_shop='.$this->context->shop->id);
251				die();
252			}
253			else
254			{
255				if ($this->cron)
256					header('location: http'.(Configuration::get('PS_SSL_ENABLED') ? 's' : '').'://'.Tools::getShopDomain(false, true).__PS_BASE_URI__.'modules/gsitemap/gsitemap-cron.php?continue=1&token='.substr(Tools::encrypt('gsitemap/cron'), 0, 10).'&type='.$new_link['type'].'&lang='.$lang.'&index='.$index.'&id='.($id_obj + 1).'&id_shop='.$this->context->shop->id);
257				else
258				{
259					$admin_folder = str_replace(_PS_ROOT_DIR_, '', _PS_ADMIN_DIR_);
260					$admin_folder = substr($admin_folder, 1);
261					header('location: http'.(Configuration::get('PS_SSL_ENABLED') ? 's' : '').'://'.Tools::getShopDomain(false, true).__PS_BASE_URI__.$admin_folder.'/index.php?tab=AdminModules&configure=gsitemap&token='.Tools::getAdminTokenLite('AdminModules').'&tab_module='.$this->tab.'&module_name=gsitemap&continue=1&type='.$new_link['type'].'&lang='.$lang.'&index='.$index.'&id='.($id_obj + 1).'&id_shop='.$this->context->shop->id);
262				}
263				die();
264			}
265		}
266	}
267
268	/**
269	 * Hydrate $link_sitemap with home link
270	 *
271	 * @param array  $link_sitemap contain all the links for the Google Sitemap file to be generated
272	 * @param string $lang         language of link to add
273	 * @param int    $index        index of the current Google Sitemap file
274	 * @param int    $i            count of elements added to sitemap main array
275	 *
276	 * @return bool
277	 */
278	private function _getHomeLink(&$link_sitemap, $lang, &$index, &$i)
279	{
280		return $this->_addLinkToSitemap(
281			$link_sitemap, array(
282				'type' => 'home',
283				'page' => 'home',
284				'link' => Tools::getShopDomainSsl(true).$this->context->shop->getBaseURI().(method_exists('Language', 'isMultiLanguageActivated') ? Language::isMultiLanguageActivated() ? $lang['iso_code'].'/' : '' : ''),
285				'image' => false
286			), $lang['iso_code'], $index, $i, -1
287		);
288	}
289
290	/**
291	 * Hydrate $link_sitemap with meta link
292	 *
293	 * @param array  $link_sitemap contain all the links for the Google Sitemap file to be generated
294	 * @param string $lang         language of link to add
295	 * @param int    $index        index of the current Google Sitemap file
296	 * @param int    $i            count of elements added to sitemap main array
297	 * @param int    $id_meta      meta object identifier
298	 *
299	 * @return bool
300	 */
301	private function _getMetaLink(&$link_sitemap, $lang, &$index, &$i, $id_meta = 0)
302	{
303		if (method_exists('ShopUrl', 'resetMainDomainCache'))
304			ShopUrl::resetMainDomainCache();
305		$link = new Link();
306		$metas = Db::getInstance()->ExecuteS('SELECT * FROM `'._DB_PREFIX_.'meta` WHERE `id_meta` > '.(int)$id_meta.' ORDER BY `id_meta` ASC');
307		foreach ($metas as $meta)
308		{
309			$url = '';
310			if (!in_array($meta['id_meta'], explode(',', Configuration::get('GSITEMAP_DISABLE_LINKS'))))
311			{
312				if (_PS_VERSION_ >= 1.5)
313				{
314					$url_rewrite = Db::getInstance()->getValue('SELECT url_rewrite, id_shop FROM `'._DB_PREFIX_.'meta_lang` WHERE `id_meta` = '.(int)$meta['id_meta'].' AND `id_shop` ='.(int)$this->context->shop->id.' AND `id_lang` = '.(int)$lang['id_lang']);
315					Dispatcher::getInstance()->addRoute($meta['page'], (isset($url_rewrite) ? $url_rewrite : $meta['page']), $meta['page'], $lang['id_lang']);
316					$uri_path = Dispatcher::getInstance()->createUrl($meta['page'], $lang['id_lang'], array(), (bool)Configuration::get('PS_REWRITING_SETTINGS'));
317					$url .= Tools::getShopDomainSsl(true).(($this->context->shop->virtual_uri) ? __PS_BASE_URI__.$this->context->shop->virtual_uri : __PS_BASE_URI__).(Language::isMultiLanguageActivated() ? $lang['iso_code'].'/' : '').ltrim($uri_path, '/');
318				}
319				else
320					$url = $link->getPageLink($meta['page'].'.php', true, $lang['id_lang']);
321
322				if (!$this->_addLinkToSitemap(
323					$link_sitemap, array(
324						'type' => 'meta',
325						'page' => $meta['page'],
326						'link' => $url,
327						'image' => false
328					), $lang['iso_code'], $index, $i, $meta['id_meta']
329				)
330				)
331					return false;
332			}
333		}
334
335		return true;
336	}
337
338	/**
339	 * Hydrate $link_sitemap with products link
340	 *
341	 * @param array  $link_sitemap contain all the links for the Google Sitemap file to be generated
342	 * @param string $lang         language of link to add
343	 * @param int    $index        index of the current Google Sitemap file
344	 * @param int    $i            count of elements added to sitemap main array
345	 * @param int    $id_product   product object identifier
346	 *
347	 * @return bool
348	 */
349	private function _getProductLink(&$link_sitemap, $lang, &$index, &$i, $id_product = 0)
350	{
351		$link = new Link();
352		if (method_exists('ShopUrl', 'resetMainDomainCache'))
353			ShopUrl::resetMainDomainCache();
354
355		$products_id = Db::getInstance()->ExecuteS('SELECT `id_product` FROM `'._DB_PREFIX_.'product_shop` WHERE `active` = 1 AND `id_shop`='.$this->context->shop->id);
356
357		foreach ($products_id as $product_id)
358		{
359			$product = new Product((int)$product_id['id_product'], false, (int)$lang['id_lang']);
360			if (_PS_VERSION_ >= 1.5)
361			{
362				$url = $link->getProductLink($product, $product->link_rewrite, htmlspecialchars(strip_tags($product->category)), $product->ean13, (int)$lang['id_lang'], (int)$this->context->shop->id, 0, true);
363			}
364			else
365			{
366				$category = new Category((int)$product->id_category_default, (int)$lang['id_lang']);
367				$url = $link->getProductLink($product, Configuration::get('PS_REWRITING_SETTINGS') ? $product->link_rewrite : false, htmlspecialchars(strip_tags($category->name)), $product->ean13, (int)$lang['id_lang']);
368			}
369
370			$id_image = Product::getCover((int)$product_id['id_product']);
371			if (isset($id_image['id_image']))
372			{
373				$image_link = $this->context->link->getImageLink($product->link_rewrite, $product->id.'-'.(int)$id_image['id_image']);
374				$image_link = (!in_array(rtrim(Context::getContext()->shop->virtual_uri, '/'), explode('/', $image_link))) ? str_replace(
375					array(
376						'https',
377						Context::getContext()->shop->domain.Context::getContext()->shop->physical_uri
378					), array(
379						'http',
380						Context::getContext()->shop->domain.Context::getContext()->shop->physical_uri.Context::getContext()->shop->virtual_uri
381					), $image_link
382				) : $image_link;
383			}
384			$file_headers = (Configuration::get('GSITEMAP_CHECK_IMAGE_FILE')) ? @get_headers($image_link) : true;
385			$image_product = array();
386			if (isset($image_link) && ($file_headers[0] != 'HTTP/1.1 404 Not Found' || $file_headers === true))
387				$image_product = array(
388					'title_img' => htmlspecialchars(strip_tags($product->name)),
389					'caption' => htmlspecialchars(strip_tags($product->description_short)),
390					'link' => $image_link
391				);
392			if (!$this->_addLinkToSitemap(
393				$link_sitemap, array(
394					'type' => 'product',
395					'page' => 'product',
396					'lastmod' => $product->date_upd,
397					'link' => $url,
398					'image' => $image_product
399				), $lang['iso_code'], $index, $i, $product_id['id_product']
400			)
401			)
402				return false;
403
404			unset($image_link);
405		}
406
407		return true;
408	}
409
410	/**
411	 * Hydrate $link_sitemap with categories link
412	 *
413	 * @param array  $link_sitemap contain all the links for the Google Sitemap file to be generated
414	 * @param string $lang         language of link to add
415	 * @param int    $index        index of the current Google Sitemap file
416	 * @param int    $i            count of elements added to sitemap main array
417	 * @param int    $id_category  category object identifier
418	 *
419	 * @return bool
420	 */
421	private function _getCategoryLink(&$link_sitemap, $lang, &$index, &$i, $id_category = 0)
422	{
423		$link = new Link();
424		if (method_exists('ShopUrl', 'resetMainDomainCache'))
425			ShopUrl::resetMainDomainCache();
426
427		$categories_id = Db::getInstance()->ExecuteS(
428			'SELECT c.id_category FROM `'._DB_PREFIX_.'category` c
429				INNER JOIN `'._DB_PREFIX_.'category_shop` cs ON c.`id_category` = cs.`id_category`
430				WHERE c.`active` = 1 AND c.`id_category` != 1 AND c.id_parent > 0 AND c.`id_category` > 0 AND cs.`id_shop` = '.(int)$this->context->shop->id.' ORDER BY c.`id_category` ASC'
431		);
432
433		foreach ($categories_id as $category_id)
434		{
435			$category = new Category((int)$category_id['id_category'], (int)$lang['id_lang']);
436			$url = $link->getCategoryLink($category, urlencode($category->link_rewrite), (int)$lang['id_lang']);
437
438			if ($category->id_image)
439			{
440				$image_link = $this->context->link->getCatImageLink($category->link_rewrite, (int)$category->id_image, 'category_default');
441				$image_link = (!in_array(rtrim(Context::getContext()->shop->virtual_uri, '/'), explode('/', $image_link))) ? str_replace(
442					array(
443						'https',
444						Context::getContext()->shop->domain.Context::getContext()->shop->physical_uri
445					), array(
446						'http',
447						Context::getContext()->shop->domain.Context::getContext()->shop->physical_uri.Context::getContext()->shop->virtual_uri
448					), $image_link
449				) : $image_link;
450			}
451			$file_headers = (Configuration::get('GSITEMAP_CHECK_IMAGE_FILE')) ? @get_headers($image_link) : true;
452			$image_category = array();
453			if (isset($image_link) && ($file_headers[0] != 'HTTP/1.1 404 Not Found' || $file_headers === true))
454				$image_category = array(
455					'title_img' => htmlspecialchars(strip_tags($category->name)),
456					'link' => $image_link
457				);
458
459			if (!$this->_addLinkToSitemap(
460				$link_sitemap, array(
461					'type' => 'category',
462					'page' => 'category',
463					'lastmod' => $category->date_upd,
464					'link' => $url,
465					'image' => $image_category
466				), $lang['iso_code'], $index, $i, (int)$category_id['id_category']
467			)
468			)
469				return false;
470
471			unset($image_link);
472		}
473
474		return true;
475	}
476
477	/**
478	 * return the link elements for the manufacturer object
479	 *
480	 * @param array  $link_sitemap    contain all the links for the Google Sitemap file to be generated
481	 * @param string $lang            language of link to add
482	 * @param int    $index           index of the current Google Sitemap file
483	 * @param int    $i               count of elements added to sitemap main array
484	 * @param int    $id_manufacturer manufacturer object identifier
485	 *
486	 * @return bool
487	 */
488	private function _getManufacturerLink(&$link_sitemap, $lang, &$index, &$i, $id_manufacturer = 0)
489	{
490		$link = new Link();
491		if (method_exists('ShopUrl', 'resetMainDomainCache'))
492			ShopUrl::resetMainDomainCache();
493		$manufacturers_id = Db::getInstance()->ExecuteS(
494			'SELECT m.`id_manufacturer` FROM `'._DB_PREFIX_.'manufacturer` m
495			INNER JOIN `'._DB_PREFIX_.'manufacturer_lang` ml on m.`id_manufacturer` = ml.`id_manufacturer`'.
496			($this->tableColumnExists(_DB_PREFIX_.'manufacturer_shop') ? ' INNER JOIN `'._DB_PREFIX_.'manufacturer_shop` ms ON m.`id_manufacturer` = ms.`id_manufacturer` ' : '').
497			' WHERE m.`active` = 1  AND m.`id_manufacturer` > '.(int)$id_manufacturer.
498			($this->tableColumnExists(_DB_PREFIX_.'manufacturer_shop') ? ' AND ms.`id_shop` = '.(int)$this->context->shop->id : '').
499			' AND ml.`id_lang` = '.(int)$lang['id_lang'].
500			' ORDER BY m.`id_manufacturer` ASC'
501		);
502		foreach ($manufacturers_id as $manufacturer_id)
503		{
504			$manufacturer = new Manufacturer((int)$manufacturer_id['id_manufacturer'], $lang['id_lang']);
505			$url = $link->getManufacturerLink($manufacturer, $manufacturer->link_rewrite, $lang['id_lang']);
506
507			$image_link = 'http://'.Tools::getMediaServer(_THEME_MANU_DIR_)._THEME_MANU_DIR_.((!file_exists(_PS_MANU_IMG_DIR_.'/'.(int)$manufacturer->id.'-medium_default.jpg')) ? $lang['iso_code'].'-default' : (int)$manufacturer->id).'-medium_default.jpg';
508			$image_link = (!in_array(rtrim(Context::getContext()->shop->virtual_uri, '/'), explode('/', $image_link))) ? str_replace(
509				array(
510					'https',
511					Context::getContext()->shop->domain.Context::getContext()->shop->physical_uri
512				), array(
513					'http',
514					Context::getContext()->shop->domain.Context::getContext()->shop->physical_uri.Context::getContext()->shop->virtual_uri
515				), $image_link
516			) : $image_link;
517
518			$file_headers = (Configuration::get('GSITEMAP_CHECK_IMAGE_FILE')) ? @get_headers($image_link) : true;
519			$manifacturer_image = array();
520			if ($file_headers[0] != 'HTTP/1.1 404 Not Found' || $file_headers === true)
521				$manifacturer_image = array(
522					'title_img' => htmlspecialchars(strip_tags($manufacturer->name)),
523					'caption' => htmlspecialchars(strip_tags($manufacturer->short_description)),
524					'link' => $image_link
525				);
526			if (!$this->_addLinkToSitemap(
527				$link_sitemap, array(
528					'type' => 'manufacturer',
529					'page' => 'manufacturer',
530					'lastmod' => $manufacturer->date_upd,
531					'link' => $url,
532					'image' => $manifacturer_image
533				), $lang['iso_code'], $index, $i, $manufacturer_id['id_manufacturer']
534			)
535			)
536				return false;;
537		}
538
539		return true;
540	}
541
542	/**
543	 * @param array  $link_sitemap contain all the links for the Google Sitemap file to be generated
544	 * @param string $lang         language of link to add
545	 * @param int    $index        index of the current Google Sitemap file
546	 * @param int    $i            count of elements added to sitemap main array
547	 * @param int    $id_supplier  supplier object identifier
548	 *
549	 * @return bool
550	 */
551	private function _getSupplierLink(&$link_sitemap, $lang, &$index, &$i, $id_supplier = 0)
552	{
553		$link = new Link();
554		if (method_exists('ShopUrl', 'resetMainDomainCache'))
555			ShopUrl::resetMainDomainCache();
556		$suppliers_id = Db::getInstance()->ExecuteS(
557			'SELECT s.`id_supplier` FROM `'._DB_PREFIX_.'supplier` s
558			INNER JOIN `'._DB_PREFIX_.'supplier_lang` sl ON s.`id_supplier` = sl.`id_supplier` '.
559			($this->tableColumnExists(_DB_PREFIX_.'supplier_shop') ? 'INNER JOIN `'._DB_PREFIX_.'supplier_shop` ss ON s.`id_supplier` = ss.`id_supplier`' : '').' 
560			WHERE s.`active` = 1 AND s.`id_supplier` > '.(int)$id_supplier.
561			($this->tableColumnExists(_DB_PREFIX_.'supplier_shop') ? ' AND ss.`id_shop` = '.(int)$this->context->shop->id : '').' 
562			AND sl.`id_lang` = '.(int)$lang['id_lang'].' 
563			ORDER BY s.`id_supplier` ASC'
564		);
565		foreach ($suppliers_id as $supplier_id)
566		{
567			$supplier = new Supplier((int)$supplier_id['id_supplier'], $lang['id_lang']);
568			$url = $link->getSupplierLink($supplier, $supplier->link_rewrite, $lang['id_lang']);
569
570			$image_link = 'http://'.Tools::getMediaServer(_THEME_SUP_DIR_)._THEME_SUP_DIR_.((!file_exists(_THEME_SUP_DIR_.'/'.(int)$supplier->id.'-medium_default.jpg')) ? $lang['iso_code'].'-default' : (int)$supplier->id).'-medium_default.jpg';
571			$image_link = (!in_array(rtrim(Context::getContext()->shop->virtual_uri, '/'), explode('/', $image_link))) ? str_replace(
572				array(
573					'https',
574					Context::getContext()->shop->domain.Context::getContext()->shop->physical_uri
575				), array(
576					'http',
577					Context::getContext()->shop->domain.Context::getContext()->shop->physical_uri.Context::getContext()->shop->virtual_uri
578				), $image_link
579			) : $image_link;
580
581			$file_headers = (Configuration::get('GSITEMAP_CHECK_IMAGE_FILE')) ? @get_headers($image_link) : true;
582			$supplier_image = array();
583			if ($file_headers[0] != 'HTTP/1.1 404 Not Found' || $file_headers === true)
584				$supplier_image = array(
585					'title_img' => htmlspecialchars(strip_tags($supplier->name)),
586					'link' => 'http'.(Configuration::get('PS_SSL_ENABLED') ? 's' : '').'://'.Tools::getMediaServer(_THEME_SUP_DIR_)._THEME_SUP_DIR_.((!file_exists(_THEME_SUP_DIR_.'/'.(int)$supplier->id.'-medium_default.jpg')) ? $lang['iso_code'].'-default' : (int)$supplier->id).'-medium_default.jpg'
587				);
588			if (!$this->_addLinkToSitemap(
589				$link_sitemap, array(
590					'type' => 'supplier',
591					'page' => 'supplier',
592					'lastmod' => $supplier->date_upd,
593					'link' => $url,
594					'image' => $supplier_image
595				), $lang['iso_code'], $index, $i, $supplier_id['id_supplier']
596			)
597			)
598				return false;
599		}
600
601		return true;
602	}
603
604	/**
605	 * return the link elements for the CMS object
606	 *
607	 * @param array  $link_sitemap contain all the links for the Google Sitemap file to be generated
608	 * @param string $lang         the language of link to add
609	 * @param int    $index        the index of the current Google Sitemap file
610	 * @param int    $i            the count of elements added to sitemap main array
611	 * @param int    $id_cms       the CMS object identifier
612	 *
613	 * @return bool
614	 */
615	private function _getCmsLink(&$link_sitemap, $lang, &$index, &$i, $id_cms = 0)
616	{
617		$link = new Link();
618		if (method_exists('ShopUrl', 'resetMainDomainCache'))
619			ShopUrl::resetMainDomainCache();
620		$cmss_id = Db::getInstance()->ExecuteS(
621			'SELECT c.`id_cms` FROM `'._DB_PREFIX_.'cms` c INNER JOIN `'._DB_PREFIX_.'cms_lang` cl ON c.`id_cms` = cl.`id_cms` '.
622			($this->tableColumnExists(_DB_PREFIX_.'supplier_shop') ? 'INNER JOIN `'._DB_PREFIX_.'cms_shop` cs ON c.`id_cms` = cs.`id_cms` ' : '').
623			'INNER JOIN `'._DB_PREFIX_.'cms_category` cc ON c.id_cms_category = cc.id_cms_category AND cc.active = 1
624				WHERE c.`active` =1 AND c.`id_cms` > '.(int)$id_cms.
625			($this->tableColumnExists(_DB_PREFIX_.'supplier_shop') ? ' AND cs.id_shop = '.(int)$this->context->shop->id : '').
626			' AND cl.`id_lang` = '.(int)$lang['id_lang'].
627			' ORDER BY c.`id_cms` ASC'
628		);
629
630		foreach ($cmss_id as $cms_id)
631		{
632			$cms = new CMS((int)$cms_id['id_cms'], $lang['id_lang']);
633			$cms->link_rewrite = urlencode((is_array($cms->link_rewrite) ? $cms->link_rewrite[(int)$lang['id_lang']] : $cms->link_rewrite));
634			$url = $link->getCMSLink($cms, null, null, $lang['id_lang']);
635
636			if (!$this->_addLinkToSitemap(
637				$link_sitemap, array(
638					'type' => 'cms',
639					'page' => 'cms',
640					'link' => $url,
641					'image' => false
642				), $lang['iso_code'], $index, $i, $cms_id['id_cms']
643			)
644			)
645				return false;
646		}
647
648		return true;
649	}
650
651	/**
652	 * Create the Google Sitemap by Shop
653	 *
654	 * @param int $id_shop Shop identifier
655	 *
656	 * @return bool
657	 */
658	public function createSitemap($id_shop = 0)
659	{
660		if (@fopen(dirname(__FILE__).'/../../test.txt', 'w') == false)
661		{
662			$this->context->smarty->assign('google_maps_error', $this->l('An error occured while trying to check your file permissions. Please adjust your permissions to allow PrestaShop to write a file in your root directory.'));
663
664			return false;
665		}
666		else
667			@unlink(dirname(__FILE__).'/../../test.txt');
668
669		if ($id_shop != 0)
670			$this->context->shop = new Shop((int)$id_shop);
671
672		/* Backward compatibility */
673		if (_PS_VERSION_ < 1.5)
674			require(_PS_MODULE_DIR_.'gsitemap/backward_compatibility/backward.php');
675
676		$type = Tools::getValue('type') ? Tools::getValue('type') : '';
677		$languages = Language::getLanguages();
678		$lang_stop = Tools::getValue('lang') ? true : false;
679		$id_obj = Tools::getValue('id') ? (int)Tools::getValue('id') : 0;
680		$type_array = array('home', 'meta', 'product', 'category', 'manufacturer', 'supplier', 'cms');
681		//$type_array = array('product', 'manufacturer', 'supplier', 'cms');
682		foreach ($languages as $lang)
683		{
684			$i = 0;
685			$index = (Tools::getValue('index') && Tools::getValue('lang') == $lang['iso_code']) ? (int)Tools::getValue('index') : 0;
686			if ($lang_stop && $lang['iso_code'] != Tools::getValue('lang'))
687				continue;
688			elseif ($lang_stop && $lang['iso_code'] == Tools::getValue('lang'))
689				$lang_stop = false;
690
691			$link_sitemap = array();
692			foreach ($type_array as $type_val)
693			{
694				if ($type == '' || $type == $type_val)
695				{
696					$function = '_get'.ucfirst($type_val).'Link';
697					if (!$this->$function($link_sitemap, $lang, $index, $i, $id_obj))
698						return false;
699					$type = '';
700					$id_obj = 0;
701				}
702			}
703			$this->_recursiveSitemapCreator($link_sitemap, $lang['iso_code'], $index);
704			$page = '';
705			$index = 0;
706		}
707
708		$this->_createIndexSitemap();
709		Configuration::updateValue('GSITEMAP_LAST_EXPORT', date('r'));
710
711		Tools::file_get_contents('http://www.google.com/webmasters/sitemaps/ping?sitemap='.urlencode('http'.(Configuration::get('PS_SSL_ENABLED') ? 's' : '').'://'.Tools::getShopDomain(false, true).$this->context->shop->physical_uri.$this->context->shop->virtual_uri.$this->context->shop->id.'_index_sitemap.xml'));
712
713		if ($this->cron)
714			die();
715		header('location: ./index.php?tab=AdminModules&configure=gsitemap&token='.Tools::getAdminTokenLite('AdminModules').'&tab_module='.$this->tab.'&module_name=gsitemap&validation');
716		die();
717	}
718
719	/**
720	 * Store the generated Sitemap file to the database
721	 *
722	 * @param string $sitemap the name of the generated Google Sitemap file
723	 *
724	 * @return bool
725	 */
726	private function _saveSitemapLink($sitemap)
727	{
728		if ($sitemap)
729			return Db::getInstance()->Execute('INSERT INTO `'._DB_PREFIX_.'gsitemap_sitemap` (`link`, id_shop) VALUES (\''.pSQL($sitemap).'\', '.(int)$this->context->shop->id.')');
730
731		return false;
732	}
733
734	/**
735	 * @param array  $link_sitemap contain all the links for the Google Sitemap file to be generated
736	 * @param string $lang         the language of link to add
737	 * @param int    $index        the index of the current Google Sitemap file
738	 *
739	 * @return bool
740	 */
741	private function _recursiveSitemapCreator($link_sitemap, $lang, &$index)
742	{
743		if (!count($link_sitemap))
744			return false;
745
746		$sitemap_link = $this->context->shop->id.'_'.$lang.'_'.$index.'_sitemap.xml';
747		$write_fd = fopen(dirname(__FILE__).'/../../'.$sitemap_link, 'w');
748
749		fwrite($write_fd, '<?xml version="1.0" encoding="UTF-8"?>'."\r\n".'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">'."\r\n");
750		foreach ($link_sitemap as $key => $file)
751		{
752			fwrite($write_fd, '<url>'."\r\n");
753			$lastmod = (isset($file['lastmod']) && !empty($file['lastmod'])) ? date('c', strtotime($file['lastmod'])) : null;
754			$this->_addSitemapNode($write_fd, htmlspecialchars(strip_tags($file['link'])), $this->_getPriorityPage($file['page']), Configuration::get('GSITEMAP_FREQUENCY'), $lastmod);
755			if ($file['image'])
756			{
757				$this->_addSitemapNodeImage(
758					$write_fd, htmlspecialchars(strip_tags($file['image']['link'])), isset($file['image']['title_img']) ? htmlspecialchars(
759						str_replace(
760							array(
761								"\r\n",
762								"\r",
763								"\n"
764							), '', strip_tags($file['image']['title_img'])
765						)
766					) : '', isset($file['image']['caption']) ? htmlspecialchars(
767						str_replace(
768							array(
769								"\r\n",
770								"\r",
771								"\n"
772							), '', strip_tags($file['image']['caption'])
773						)
774					) : ''
775				);
776			}
777			fwrite($write_fd, '</url>'."\r\n");
778		}
779		fwrite($write_fd, '</urlset>'."\r\n");
780		fclose($write_fd);
781		$this->_saveSitemapLink($sitemap_link);
782		$index++;
783
784		return true;
785	}
786
787	/**
788	 * return the priority value set in the configuration parameters
789	 *
790	 * @param string $page
791	 *
792	 * @return float|string|bool
793	 */
794	private function _getPriorityPage($page)
795	{
796		return Configuration::get('GSITEMAP_PRIORITY_'.Tools::strtoupper($page)) ? Configuration::get('GSITEMAP_PRIORITY_'.Tools::strtoupper($page)) : 0.1;
797	}
798
799	/**
800	 * Add a new line to the sitemap file
801	 *
802	 * @param resource $fd       file system object resource
803	 * @param string   $loc      string the URL of the object page
804	 * @param string   $priority
805	 * @param string   $change_freq
806	 * @param int      $last_mod the last modification date/time as a timestamp
807	 */
808	private function _addSitemapNode($fd, $loc, $priority, $change_freq, $last_mod = null)
809	{
810		fwrite($fd, '<loc>'.(Configuration::get('PS_REWRITING_SETTINGS') ? '<![CDATA['.$loc.']]>' : $loc).'</loc>'."\r\n".'<priority>'."\r\n".number_format($priority, 1, '.', '').'</priority>'."\r\n".($last_mod ? '<lastmod>'.date('c', strtotime($last_mod)).'</lastmod>' : '')."\r\n".'<changefreq>'.$change_freq.'</changefreq>'."\r\n");
811	}
812
813	private function _addSitemapNodeImage($fd, $link, $title, $caption)
814	{
815		fwrite($fd, '<image:image>'."\r\n".'<image:loc>'.(Configuration::get('PS_REWRITING_SETTINGS') ? '<![CDATA['.$link.']]>' : $link).'</image:loc>'."\r\n".'<image:caption><![CDATA['.$caption.']]></image:caption>'."\r\n".'<image:title><![CDATA['.$title.']]></image:title>'."\r\n".'</image:image>'."\r\n");
816	}
817
818	/**
819	 * Create the index file for all generated sitemaps
820	 * @return boolean
821	 */
822	private function _createIndexSitemap()
823	{
824		$sitemaps = Db::getInstance()->ExecuteS('SELECT `link` FROM `'._DB_PREFIX_.'gsitemap_sitemap` WHERE id_shop = '.$this->context->shop->id);
825		if (!$sitemaps)
826			return false;
827
828		$xml = '<?xml version="1.0" encoding="UTF-8"?><sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"></sitemapindex>';
829		$xml_feed = new SimpleXMLElement($xml);
830
831		foreach ($sitemaps as $link)
832		{
833			$sitemap = $xml_feed->addChild('sitemap');
834			$sitemap->addChild('loc', 'http://'.Tools::getShopDomain(false, true).__PS_BASE_URI__.$link['link']);
835			$sitemap->addChild('lastmod', date('c'));
836		}
837		file_put_contents(dirname(__FILE__).'/../../'.$this->context->shop->id.'_index_sitemap.xml', $xml_feed->asXML());
838
839		return true;
840	}
841
842	private function tableColumnExists($table_name, $column = null)
843	{
844		if (array_key_exists($table_name, $this->sql_checks))
845			if (!empty($column) && array_key_exists($column, $this->sql_checks[$table_name]))
846				return $this->sql_checks[$table_name][$column];
847			else
848				return $this->sql_checks[$table_name];
849
850		$table = Db::getInstance()->ExecuteS('SHOW TABLES LIKE \''.$table_name.'\'');
851		if (empty($column))
852			if (count($table) < 1)
853				return $this->sql_checks[$table_name] = false;
854			else
855				$this->sql_checks[$table_name] = true;
856
857		else
858		{
859			$table = Db::getInstance()->ExecuteS('SELECT * FROM `'.$table_name.'` LIMIT 1');
860
861			return $this->sql_checks[$table_name][$column] = array_key_exists($column, current($table));
862		}
863
864		return true;
865	}
866
867}