HEX
Server: LiteSpeed
System: Linux php-prod-3.spaceapp.ru 5.15.0-151-generic #161-Ubuntu SMP Tue Jul 22 14:25:40 UTC 2025 x86_64
User: sarli3128 (1010)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //home/retile.ru/public_html/admin/model/extension/module/seo_url_generator.php
<?php

/**
 * @category   OpenCart
 * @package    SEO URL Generator
 * @copyright  © Serge Tkach, 2017 - 2020, http://sergetkach.com/
 */
class ModelExtensionModuleSeoUrlGenerator extends Model {
	private $stdelog;

	function __construct($registry) {
		parent::__construct($registry);

		if ($registry->get('stdelog')) {
			$this->stdelog = $registry->get('stdelog');
		} else {
			// Для методов модели, которые вызываны из контроллера сущностей, а не модуля
			$this->stdelog = new StdeLog('seo_url_generator');
			$this->stdelog->setDebug($this->config->get('module_seo_url_generator_debug'));
		}
	}

	

	/*
	 * Фильтрация названия сущности
	 * Данная функция вызывается перед транслитом
	 * То есть, тут можно сокращать название товаров до заданного кол-ва слов
	 */

	public function essenceNameFilter($name, $essence, $setting) {
		// Put your code here
		if ('product' == $essence) {
			if (mb_strlen($name) > 100) {
				// Укоротить название товара, если в его названии содержится больше 100 символов
			}
		}

		return $name;
	}




	/*
	------------------------------------------------------------------------------
	GENERATING
	------------------------------------------------------------------------------
	*/

	public function generateProductKeyword($a_data, $setting) {
		$this->stdelog->write(3, 'generateProductKeyword() is called');
		$this->stdelog->write(4, $a_data, 'generateProductKeyword() : $a_data');
		$this->stdelog->write(4, $setting, 'generateProductKeyword() : $setting');

		$keyword = '';

		$search = array(
			'[product_name]',
			'[product_id]',
			'[model]',
			'[sku]',
			'[manufacturer_name]'
		);

		$replace = array();

		$replace[] = isset($a_data['name']) ? trim($a_data['name']) : '';
		$replace[] = isset($a_data['essence_id']) ? trim($a_data['essence_id']) : '';
		$replace[] = isset($a_data['model']) ? trim($a_data['model']) : '';
		$replace[] = isset($a_data['sku']) ? trim($a_data['sku']) : '';
		//$replace[] = isset($a_data['manufacturer_name']) ? trim($a_data['manufatrurer_name']) : '';
		$replace[] = isset($a_data['manufacturer_id']) ? trim($this->getManufacturerNameById($a_data['manufacturer_id'])) : '';
		
		$this->stdelog->write(4, $search, 'generateProductKeyword() : $search');
		
		$this->stdelog->write(4, $replace, 'generateProductKeyword() : $replace');

		$keyword = str_replace($search, $replace, $setting['formula']);

		$this->stdelog->write(3, $keyword, 'generateProductKeyword() : return $keyword');

		return $keyword;
	}

	public function generateOtherSystemsEssenceKeyword($a_data, $setting) {
		$this->stdelog->write(3, 'generateOtherSystemsEssenceKeyword() is called');
		$this->stdelog->write(4, $a_data, 'generateOtherSystemsEssenceKeyword() : $a_data');
		$this->stdelog->write(4, $setting, 'generateOtherSystemsEssenceKeyword() : $setting');

		$keyword = '';

		if ('category' == $a_data['essence']) {
			$essence_name_var = '[category_name]';
		} elseif ('manufacturer' == $a_data['essence']) {
			$essence_name_var = '[manufacturer_name]';
		} elseif ('information' == $a_data['essence']) {
			$essence_name_var = '[information_title]';
		}

		$essence_id_var = '[' . $a_data['essence'] . '_id]';

		$search = array(
			$essence_name_var,
			$essence_id_var
		);

		$replace = array();
		$replace[] = isset($a_data['name']) ? trim($a_data['name']) : ''; // !important - even if information
		$replace[] = isset($a_data['essence_id']) ? trim($a_data['essence_id']) : '';

		$keyword = str_replace($search, $replace, $setting['formula']);

		$this->stdelog->write(3, $keyword, 'generateOtherSystemsEssenceKeyword() : return $keyword');

		return $keyword;
	}

	public function generateNotSystemsEssenceKeyword($a_data, $setting) {
		$this->stdelog->write(3, 'generateNotSystemsEssenceKeyword() is called');
		$this->stdelog->write(4, $a_data, 'generateNotSystemsEssenceKeyword() : $a_data');
		$this->stdelog->write(4, $setting, 'generateNotSystemsEssenceKeyword() : $setting');
		
		// TMP
		$setting['formula'] = '[essence_name]';

		$keyword = '';

		$search = array(
			'[essence_name]',
			'[essence_id]'
		);

		$replace = array();
		$replace[] = isset($a_data['name']) ? trim($a_data['name']) : '';
		$replace[] = isset($a_data['essence_id']) ? trim($a_data['essence_id']) : '';

		$keyword = str_replace($search, $replace, $setting['formula']);

		$this->stdelog->write(3, $keyword, 'generateNotSystemsEssenceKeyword() : return $keyword');

		return $keyword;
	}
	
	/*
	 * Is different from 2.x! ...
	 */
	public function getEssenceNames($essence, $primary_key, $essence_id) {
		$this->stdelog->write(3, 'getEssenceName() is called');

		$column_name = 'name';

		// Warning I (!)
		if ('information' == $essence) {
			$column_name = 'title';
		}

		$sql = "SELECT `language_id`, `$column_name` FROM `" . DB_PREFIX . $essence . "_description` WHERE `" . $primary_key . "` = '" . (int)$essence_id . "'";
		
		$this->stdelog->write(4, $sql, 'getEssenceName() : $sql');

		$query = $this->db->query($sql);

		$names = array();
		
		if ($query->num_rows > 0) {
			foreach ($query->rows as $row) {
				$names[$row['language_id']] = $row[$column_name];
			}			
			
			$this->stdelog->write(3, $names, 'getEssenceName() : return $names');
			return $names;
			
		} else {
			$this->stdelog->write(3, false, 'getEssenceName() : NO RESULT');
			return array();
		}
	}

	public function getURLs($primary_key, $essence_id) {
		$this->stdelog->write(3, 'getURLs() is called');

		$sql = "SELECT * FROM `" . DB_PREFIX . "seo_url` WHERE `query` = '" . $this->db->escape($primary_key) . "=" . (int)$essence_id . "'";

		$this->stdelog->write(4, $sql, 'getURLs() : $sql');

		$res = $this->db->query($sql);

		$this->stdelog->write(4, $res, 'getURLs() : $res');
		
		$urls = array();
		
		if ($res->num_rows > 0) {
			foreach ($res->rows as $row) {
				// check doubles here!
				if (!isset($urls[$row['store_id']][$row['language_id']])) {
					// It is first SEO URL for this store & language - ok
					$urls[$row['store_id']][$row['language_id']] = $row['keyword'];
				} else {
					// It's not first SEO URL - bad					
					$this->stdelog->write(1, 'getURLs() : essence already has more than 1 SEO URL for store & language! Delete it!!!');
					
					$sql_delete = "DELETE FROM `" . DB_PREFIX . "seo_url` WHERE `query` = '" . $this->db->escape($primary_key) . "=" . (int)$essence_id . "' AND `store_id` = '" . $row['store_id'] . "' AND `language_id` = '" . $row['language_id'] . "'";
					
					$res_delete = $this->db->query($sql_delete);
					
					$this->stdelog->write(4, $res_delete, 'getURLs() : $res_delete DOUBLES');
					
					unset($urls[$row['store_id']][$row['language_id']]);				
				}				
			}
			
			$this->stdelog->write(4, $urls, 'getURLs() : $urls');		
			
			return $urls;
		} else {
			$this->stdelog->write(4, 'getURLs() : $res->num_rows 0');
			return array();
		}
	}
	
	public function setURL($primary_key, $essence_id, $keyword, $store_id, $language_id) {
		$this->stdelog->write(3, 'setURL() is called');
		
		$sql = "INSERT INTO `" . DB_PREFIX . "seo_url` SET `store_id` = '" . (int)$store_id . "', `language_id` = '" . (int)$language_id . "', `query` = '" . $this->db->escape($primary_key) . "=" . (int)$essence_id . "', `keyword` = '" . $this->db->escape($keyword) . "'";
		
		$this->stdelog->write(4, $sql, 'setURL() is called : $sql');

		$this->db->query($sql);

		$res = $this->db->getLastId();
		
		$this->stdelog->write(3, $res, 'setURL() is called : $res');

		if ($res > 0) {
			return true;
		}
	}
	
	public function deleteURL($essence, $essence_id, $store_id, $language_id) {
		$this->stdelog->write(3, 'deleteURL() is called');
		
		$sql = "DELETE FROM `" . DB_PREFIX . "seo_url` WHERE `query` = '" . $this->db->escape($essence) . "_id=" . (int)$essence_id . "' AND `store_id` = '" . (int)$store_id . "' AND `language_id` = '" . (int)$language_id . "'";

		$query = $this->db->query($sql);
		
		$this->stdelog->write(4, $query, 'deleteURL() : $query');

		return false;
	}

	public function setRedirect($keyword_actual, $keyword_old, $primary_key, $essence_id, $store_id, $language_id) {
		$this->stdelog->write(3, 'setRedirect() is called');
		
		if ($this->issetUrlByEssence($primary_key, $essence_id, $store_id, $language_id)) {
			$this->stdelog->write(4, 'setRedirect() : $this->issetUrlByEssence() returned true');
			
			// if was changed repeatedly
			$sql_0 = "DELETE FROM `" . DB_PREFIX . "seo_url_generator_redirects` WHERE `seo_url_old` = '" . $this->db->escape($keyword_actual) . "' AND `store_id` = '" . (int)$store_id . "' AND `language_id` = '" . (int)$language_id . "'";

			$this->stdelog->write(4, $sql_0, 'setRedirect() : $sql_0');
			
			$res = $this->db->query($sql_0);
			
			$this->stdelog->write(4, $res, 'setRedirect() : $res for $sql_0');

			$sql_1 = "UPDATE `" . DB_PREFIX . "seo_url_generator_redirects` SET " . "`seo_url_actual` = '" . $this->db->escape($keyword_actual) . "' " . "WHERE `query` = '" . $this->db->escape($primary_key) . "=" . (int)$essence_id . "' AND `store_id` = '" . (int)$store_id . "' AND `language_id` = '" . (int)$language_id . "'";
			
			$this->stdelog->write(4, $sql_1, 'setRedirect() : $sql_1');

			$this->db->query($sql_1);
		} else {
			$this->stdelog->write(4, 'setRedirect() : $this->issetUrlByEssence() returned false');
		}

		// insert second
		$sql_2 = "INSERT INTO `" . DB_PREFIX . "seo_url_generator_redirects` SET `store_id` = '" . (int)$store_id . "', `language_id` = '" . (int)$language_id . "', `seo_url_old`= '" . $this->db->escape($keyword_old) . "', " . "`seo_url_actual` = '" . $this->db->escape($keyword_actual) . "', " . "`query` = '" . $this->db->escape($primary_key) . "=" . (int)$essence_id . "'";
		
		$this->stdelog->write(4, $sql_2, 'setRedirect() : $sql_2');

		$query = $this->db->query($sql_2);

		$res = $this->db->getLastId();

		if ($res > 0) {
			$this->stdelog->write(3, $res, 'setRedirect() : $res');
			
			return true;
		}
		
		$this->stdelog->write(1, $res, 'setRedirect() : $res');

		return false;
	}
	
	public function getRedirects($primary_key, $essence_id) {
		$this->stdelog->write(3, 'getRedirects() is called');

		$sql = "SELECT * FROM `" . DB_PREFIX . "seo_url_generator_redirects` WHERE `query` = '" . $this->db->escape($primary_key) . "=" . (int)$essence_id . "' ";
		
		$this->stdelog->write(4, $sql, 'getRedirects() : $sql');
		
		$query = $this->db->query($sql);

		$this->stdelog->write(4, $query, 'getRedirects() : $query');
		
		$redirects = array();

		if ($query->num_rows > 0) {
			foreach ($query->rows as $row) {
				$redirects[$row['store_id']][$row['language_id']][] = $row['seo_url_old'];
			}
			
			$this->stdelog->write(4, $redirects, 'getRedirects() : $redirects');

			return $redirects;
		} else {
			$this->stdelog->write(4, 'getRedirects() : $res->num_rows 0');
			return false;
		}
		
		return array();
	}

	public function issetUrlByEssence($primary_key, $essence_id) {
		$this->stdelog->write(3, 'issetUrlByEssence() is called');
		
		$sql = "SELECT `seo_url_id` FROM `" . DB_PREFIX . "seo_url_generator_redirects` WHERE `query` = '" . $this->db->escape($primary_key) . "=" . (int)$essence_id . "' ";

		$query = $this->db->query($sql);

		if ($query->num_rows > 0) {
			$this->stdelog->write(3, true, 'issetUrlByEssence() : return true');
			
			return true;
		}
		
		$this->stdelog->write(3, false, 'issetUrlByEssence() : return false');

		return false;
	}
	
	public function isUnique($keyword, $primary_key, $essence_id, $store_id) {
		$this->stdelog->write(3, 'isUnique() is called');
		
		$sql = "SELECT * FROM `" . DB_PREFIX . "seo_url` WHERE `keyword`='" . $this->db->escape($keyword) . "' AND `store_id` = '" . (int)$store_id . "' AND `query` !='" . $primary_key . "=" . $essence_id . "'";

		$this->stdelog->write(4, $sql, 'isUnique() : $sql');

		$query = $this->db->query($sql);

		if (0 == $query->num_rows) {
			$this->stdelog->write(3, 'getUniqueUrl() : return true');
			return true;
		}
		
		$this->stdelog->write(3, 'getUniqueUrl() : return false');
		return false;
	}

	public function makeUniqueUrl($keyword, $store_id) {
		$this->stdelog->write(3, 'makeUniqueUrl() is called');
		
		$valid = false;
		$i = 0;
		
		$delimiter_char = '-';
			
		if ('underscore' == $this->config->get('seo_url_generator_delimiter_char')) {
			$delimiter_char = '_';
		}

		while (false === $valid) {
			$unique_keyword = $keyword;
			
			if ($i > 0) {
				$unique_keyword .= $delimiter_char . $i;
			}

			$sql = "SELECT * FROM `" . DB_PREFIX . "seo_url` WHERE `keyword`='" . $this->db->escape($unique_keyword) . "' AND `store_id` = '" . (int)$store_id . "'";

			$this->stdelog->write(4, $sql, 'makeUniqueUrl() : $sql');
			
			$query = $this->db->query($sql);
			
			$this->stdelog->write(4, $query, 'makeUniqueUrl() : $query');
			
			if (0 == $query->num_rows) {
				$valid = true;
				break;
			}

			$i++;
		}
		
		$this->stdelog->write(3, $unique_keyword, 'makeUniqueUrl() : return $unique_keyword');

		return $unique_keyword;
	}

	public function getProductData($product_id) {
		$this->stdelog->write(3, 'getProductData() is called');

		$query = $this->db->query("SELECT `sku`, `model`, `manufacturer_id` FROM `" . DB_PREFIX . "product` WHERE `product_id` = '" . (int)$product_id . "'");

		if ($query->row) {
			return $query->row;
		} else {
			$this->stdelog->write(1, $query->row, 'getProductData() : $query->row is empty');
		}

		return false;
	}

	public function getManufacturerNameById($manufacturer_id) {
		$this->stdelog->write(3, 'getManufacturerNameById() is called');

		if (!$manufacturer_id) {
			$this->stdelog->write(1, $manufacturer_id, 'getManufacturerNameById() : $manufacturer_id');
			return false;
		}
		
		$query = $this->db->query("SELECT `name` FROM `" . DB_PREFIX . "manufacturer` WHERE `manufacturer_id` = '" . (int)$manufacturer_id . "'");

		if (isset($query->row['name'])) {
			$this->stdelog->write(3, $query->row['name'], 'getManufacturerNameById() : return $query->row["name"]');
			
			return $query->row['name'];			
		} else {
			$this->stdelog->write(1, $query->row['name'], 'getManufacturerNameById() : return $query->row["name"]');
		}	

		return false;
	}




	/*
	------------------------------------------------------------------------------
	TRANSLIT
	------------------------------------------------------------------------------
	*/

	public function getFunctionsList() {
		$array = array();
		
		$target_dir = DIR_SYSTEM . 'library/seo_url_generator/translit/';

		$files = scandir($target_dir);
		
		foreach ($files as $file) {
			if ('.' != $file && '..' != $file) {
				if (is_file($target_dir . '/' . $file)) {
					$basename = basename($file, '.php');
					
					if (is_file($target_dir . '/' . $file)) {
						require_once $target_dir . '/' . $file;			
					
						$function = 'sug_translit_' . $basename;
						$function_title = 'sug_translit_' . $basename . '_title';					

						if (is_callable($function) && is_callable($function_title)) {
							$array[$function] = $function_title();
						} else {
							$this->log->write('ERROR -- SEO URL Generator: Not callable function ' . $function . '() or ' . $function_title . '()'
								. ' in admin/model/extension/module/seo_url_generator_translit.php on line ' . ( __LINE__ - 4) . '.'
								. ' Code: if (is_callable($function) && is_callable($function_title)) {');
						}
					}
				}
			}
		}
		
		return $array;
	}

	/*
	 * Вырезает все лишние символы, в том числе кириллицу...
	 * TODO: как сделать так, чтобы кириллицу не вырезало?
	 */
	public function translit($string, $setting) {
		$this->stdelog->write(3, '$this->model_extension_module_seo_url_generator->translit() is called');
		
		$this->stdelog->write(3, $string, '$this->model_extension_module_seo_url_generator->translit() : $string on start');

		$string = trim($string);
		$string = mb_strtolower($string); // Attention 1!

		// custom_replace
		$custom_replace_from = str_replace(array("\r\n", "\n"), '<br>', $setting['custom_replace_from']);
		$custom_replace_from_array = explode('<br>', $custom_replace_from);
		
		$custom_replace_to = str_replace(array("\r\n", "\n"), '<br>', $setting['custom_replace_to']);
		$custom_replace_to_array = explode('<br>', $custom_replace_to);
		
		$this->stdelog->write(4, $custom_replace_from, '$this->model_extension_module_seo_url_generator->translit() : $custom_replace_from');
		$this->stdelog->write(4, $custom_replace_to, '$this->model_extension_module_seo_url_generator->translit() : $custom_replace_to');
		$this->stdelog->write(4, $custom_replace_from_array, '$this->model_extension_module_seo_url_generator->translit() : $custom_replace_from_array');
		$this->stdelog->write(4, $custom_replace_to_array, '$this->model_extension_module_seo_url_generator->translit() : $custom_replace_to_array');
		
		$this->stdelog->write(3, $string, '$this->model_extension_module_seo_url_generator->translit() : $string BEFORE custom_replace');
		
		// for NON ASCII as ø
		$string = htmlentities($string, ENT_QUOTES, 'UTF-8');
		
		$this->stdelog->write(3, $string, '$this->model_extension_module_seo_url_generator->translit() : $string custom_replace NON ASCII');
		
		foreach ($custom_replace_from_array as $key => $value) {
			// some values were changed by htmlspecialchars in time of saving $this->request-post!
			$custom_replace_from_array[$key] = mb_strtolower(htmlentities(html_entity_decode($value, ENT_QUOTES, 'UTF-8'), ENT_QUOTES, 'UTF-8'));
			
			$custom_replace_from_array[$key] = mb_strtolower($custom_replace_from_array[$key]); // Attention 1!
		}
		
		$this->stdelog->write(4, $custom_replace_from_array, '$this->model_extension_module_seo_url_generator->translit() : $custom_replace_from_array AFTER htmlentities()');
		
		$string = str_replace($custom_replace_from_array, $custom_replace_to_array, $string);
		
		$this->stdelog->write(3, $string, '$this->model_extension_module_seo_url_generator->translit() : $string AFTER custom_replace');

		// Take attention
		// OpenCart save name with htmlspecialchars in $this->request->post
		// so " is saved as &quot;
		// It was converted again with htmlentities in time of custom_replace 
		// and &quot; is as &amp;quot; now
		
		// that's why we need html_entity_decode()
		$string = html_entity_decode($string, ENT_QUOTES, 'UTF-8');
				
		// ++
		// htmlspecialchars
		$string = str_replace(array('&nbsp;', '&quot;', '&lt;', '&gt;', '&amp;'), ' ', $string);
		
		// translit function
		$translit_function = $setting['translit_function'];
		
		$this->stdelog->write(3, $translit_function, '$this->model_extension_module_seo_url_generator->translit() : $translit_function');

		if ($translit_function) {
			$string = $this->translitExecute($string, $translit_function);
			
			$this->stdelog->write(3, $string, '$this->model_extension_module_seo_url_generator->translit() : $string after call $translit_function()');
		}

		// Remove all not allowed chars
		if ('sug_translit_none' != $translit_function) {
				$string = preg_replace('/[^a-zA-Z0-9\-_]/', ' ', $string);
			} else {
				$string = str_replace(array(
					'ʼ', '`', '~', '@', '#', '№', '$', '%', '^', '&', '*', '(', ')', '+', '-', '=',
					'.', ':', ',', ';', '!', '?', '—', '\'', '"',
					'\\', '/', '{', '}', '[', ']', '<', '>',
					'°', '•', '″', '×', '÷', 'ø', '²'
				), ' ', $string);
			}
		
		// delimiter_char
		if ('underscore' == $setting['delimiter_char']) {
			$string = preg_replace('| |', '_', $string);
			$string = preg_replace('/\s+/', '_', $string);
			$string = preg_replace('|-_|', '_', $string);
			$string = preg_replace('|_-|', '_', $string);
			$string = preg_replace('|_+|', '_', $string);
		}

		if ('hyphen' == $setting['delimiter_char']) {
			$string = preg_replace('| |', '-', $string);
			$string = preg_replace('/\s+/', '-', $string);
			$string = preg_replace('|-_|', '-', $string);
			$string = preg_replace('|_-|', '-', $string);
			$string = preg_replace('|-+|', '-', $string);
		}

		// change_delimiter_char
		if ('underscore_to_hyphen' == $setting['change_delimiter_char']) {
			$string = preg_replace('|_|', '-', $string);
		}

		if ('hyphen_to_underscore' == $setting['change_delimiter_char']) {
			$string = preg_replace('|-|', '_', $string);
		}

		// Remove delimeter char from beginning and end of a string
		$string = preg_replace(
			array('|^-|', '|-$|', '|^_|', '|_$|'),
			array('', '', '', ''),
			$string
		);

		$this->stdelog->write(3, $string, '$this->model_extension_module_seo_url_generator->translit() : return $string');
		
		return $string;
	}
	
	public function translitExecute($string, $translit_function) {
		$inc_file = DIR_SYSTEM . 'library/seo_url_generator/translit/' . str_replace('sug_translit_', '', $translit_function) . '.php';
		
		if (is_file($inc_file)) {
			require_once $inc_file;
			
			if (is_callable($translit_function)) {
				return $translit_function($string);
			} else {
				$this->log->write('ERROR -- SEO URL Generator: function  ' . $translit_function . '() is not calable'
					. ' in admin/model/extension/module/seo_url_generator.php on line ' . ( __LINE__ - 4) . '. Code: if (is_callable($translit_function)) {');
			}
		} else {
			$this->log->write('ERROR -- SEO URL Generator: No file  '. $inc_file . ' required'
				. ' in admin/model/extension/module/seo_url_generator.php on line ' . ( __LINE__ - 11) . '. Code: require_once $inc_file;');
		}
	}
}