Ошибка при обращении к несуществующему

Часто в JavaScript мы пытаемся обращаться к каким-то свойствам объектов. Часто гоняем их в массивах. Иногда мы пытаемся использовать обращения к несуществующим ключам в условиях или функциях.

И однажды возникнет такая ситуация, при которой всё сломается. Мы не специально, просто так получается. Как быть?

В чём проблема с ключами объектов? Что именно ломается?

Представим, что у нас есть объекты:

let car = {
  brand: 'Audi',
  color: 'Red'
}

let car2 = { 
   brand: 'BMW', 
   color: 'Black', 
   model: 'Model:X10'
}

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

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

Если мы сейчас попытаемся обратиться к свойству model у объекта car то нам вернётся undefined. И это правильно, потому что ключ марки автомобиля не объявлен. Значения тоже нет.

Но если мы переименовываем по шаблону все названия моделей авто, то случается это:

car.model.replace('Model:','')

Обратились к несуществующему свойству объекта в JavaScript и всё сломалось - ошибка

Обратились к несуществующему свойству объекта в JavaScript и всё сломалось — ошибка

Вывалится ошибка. Программа перестанет работать. Рухнет вообще всё т. к. в среду выполнения кода вывалилась ошибка. Что делать?

Можно, конечно, пытаться «ловить» ошибку блоком try|catch, но это громоздко и не всегда уместно.

Решение проблемы

В JavaScript у нас есть возможность «попытаться обратиться» к свойству объекта БЕЗОПАСНО. Оформляется это при помощи знака вопроса перед точкой:

car.model?.replace('Model:','')

В нашем случаем мы не знаем как метод replace() отреагирует на «пустые» значения по ключам model.

Поэтому мы должны оформить обращение к методу при помощи двух символов — «?.» (вопрос и точка).

Если ключ model окажется несуществующим, то мы НЕ провалимся в ошибку.

Избежали ошибки при обращении к несуществующему свойству объекта в JavaScript

Избежали ошибки при обращении к несуществующему свойству объекта в JavaScript

Пример преобразования в массиве:

// С ОШИБКОЙ

[{brand: ‘Audi’,color: ‘Red’},{brand: ‘BMW’, color: ‘Black’, model: ‘Model:X10’}, {brand: ‘Volvo’, color: ‘White’, model: ‘Model:Finne’}].map(i=>{i.model=i.model.replace(‘Model:’,»); return i})

// Без ОШИБКИ

[{brand: ‘Audi’,color: ‘Red’},{brand: ‘BMW’, color: ‘Black’, model: ‘Model:X10’}, {brand: ‘Volvo’, color: ‘White’, model: ‘Model:Finne’}].map(i=>{i.model=i.model?.replace(‘Model:’,»); return i})

Преобразовали все объекты в массиве и не упали в ОШИБКУ из-за несуществующего свойства у объекта JavaScript

Преобразовали все объекты в массиве и не упали в ОШИБКУ из-за несуществующего свойства у объекта JavaScript

Имена марок автомобилей были успешно заменены. В объектах без ключа «model» прописался этот ключ со значением undefined.

Информационные ссылки

Стандарт ECMAScript — https://tc39.es/ecma262/multipage/

Раздел «13.3 Left-Hand-Side Expressions» — https://tc39.es/ecma262/#sec-left-hand-side-expressions

Производство «OptionalChain» — https://tc39.es/ecma262/#prod-OptionalChain

У меня есть небольшой класс в котором я использую внутреннюю константу (массив) для получения имени метода по классу объекта:

class Synchronize implements ObserverInterface
{
    /**
     * Observable class names with corresponding methods.
     */
    const CLASS_MAPPER = [
        'MagentoSalesModelOrder' => 'syncOrderData',
        'MagentoSalesModelOrderInvoice' => 'syncInvoiceData',
        'MagentoSalesModelOrderShipmentTrack' => 'syncShipmentTrackData',
        'MagentoSalesModelOrderShipment' => 'syncShipmentData',
        'MagentoSalesModelOrderAddress' => 'syncAddressData',
        'MagentoSalesModelOrderItem' => 'syncItemsData',
        'MagentoSalesModelOrderTax' => 'syncTaxData'
    ];

    /**
     * @param Observer $observer
     * @return $this
     */
    public function execute(Observer $observer)
    {
        $event = $observer->getEvent();
        /** @see MagentoFrameworkModelAbstractModel::_getEventData() */
        $object = $event->getDataObject();
        if (!is_object($object) || empty(static::CLASS_MAPPER[get_class($object)])) {
            return $this;
        }

        $this->{static::CLASS_MAPPER[get_class($object)]}($object);

        return $this;
    }

    //...
}

Проблема возникает когда в $object приходит объект с классом которого нет в списке static::CLASS_MAPPER. Возникает нотис примерно следующего содержания:

Notice: Undefined index: MageWorxOrderEditorModelOrderItem in /home/asys/web/m212ee2/app/code/MageWorx/OrdersGrid/Observer/Synchronize.php on line 80

Сама ошибка в принципе мне понятна, и альтернативные пути решения проблемы существуют, но я не могу разобраться, по какой причине вызов empty(get_class($object)) вызывает нотис если такого элемента не существует?

Судя из описания на php.net нотис не должен возникать при вызове empty():

Проверяет, считается ли переменная пустой. Переменная считается пустой, если она не существует или её значение равно FALSE. empty() не генерирует предупреждение, если переменная не существует.


Если переменная не существует, предупреждение не генерируется. Это значит, что empty() фактически является точным эквивалентом конструкции !isset($var) || $var == false

Буду признателен, если кто-нибудь сможет прояснить для меня такое поведение php.

PS: Версия php 5.6

PPS: Вот линк для проверки кода онлайн, где на версии 5.6 падает нотис, но на версии >= 7 уже не падает:

http://sandbox.onlinephpfunctions.com/code/43ef701f65c5137a10ffae32bfa7e3a2c564a651

PPPS: каких-либо ограничений для версии 5.6 отличных от версии >= 7 в описании empty() я не нашел :( Возможно причина в других изменениях в php?

Код для тестов:

<?php

ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);

class Synchronize
{
    /**
     * Observable class names with corresponding methods.
     */
    const CLASS_MAPPER = [
        'MagentoSalesModelOrder' => 'syncOrderData',
        'MagentoSalesModelOrderInvoice' => 'syncInvoiceData',
        'MagentoSalesModelOrderShipmentTrack' => 'syncShipmentTrackData',
        'MagentoSalesModelOrderShipment' => 'syncShipmentData',
        'MagentoSalesModelOrderAddress' => 'syncAddressData',
        'MagentoSalesModelOrderItem' => 'syncItemsData',
        'MagentoSalesModelOrderTax' => 'syncTaxData'
    ];

    public function execute()
    {
        $objClass = 'MageWorxOrderEditorModelOrderItem';
        if (empty(static::CLASS_MAPPER[$objClass])) {
            echo 'A';
        } else {
            echo 'B';
        }
    }
}

echo 'Start >>> ';

$a = new Synchronize();
$a->execute();

echo ' >>> End';

В моем тесте ответ php 7.0:

Start >>> A >>> End

Ответ php 5.6:

Ответ php 5.6

Js ошибка если нет свойства

Обработка ошибок в JavaScript при отсутствии свойства

JavaScript — мощный, гибкий язык программирования, который используется для создания интерактивных веб-страниц. Однако, как и любой другой язык, он не без недостатков. Одной из распространенных проблем, с которыми сталкиваются разработчики, является ошибка при обращении к свойству, которого не существует.

Что происходит при обращении к несуществующему свойству?

В JavaScript, когда мы обращаемся к свойству, которого нет, вместо того чтобы вызвать ошибку, код просто возвращает значение undefined. Например:

let obj = {};
    console.log(obj.nonExistingProperty); // Вывод: undefined
    

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

Как обрабатывать ошибки отсутствия свойства?

Существует несколько способов обработки таких ситуаций в JavaScript.

1. Оператор «in»

Оператор «in» позволяет проверить, существует ли свойство в объекте:

let obj = {};
    if ('nonExistingProperty' in obj) {
        console.log(obj.nonExistingProperty);
    } else {
        console.log('Свойство не существует');
    }
    

2. Метод «hasOwnProperty»

Метод «hasOwnProperty» проверяет, есть ли у объекта указанное свойство:

let obj = {};
    if (obj.hasOwnProperty('nonExistingProperty')) {
        console.log(obj.nonExistingProperty);
    } else {
        console.log('Свойство не существует');
    }
    

3. Оператор «try/catch»

Можно также использовать оператор «try/catch», чтобы перехватить ошибку при обращении к несуществующему свойству:

let obj = {};
    try {
        console.log(obj.nonExistingProperty);
    } catch (e) {
        console.log('Свойство не существует');
    }
    

Заключение

Обработка ошибок — важная часть программирования на JavaScript. Ошибки при обращении к несуществующим свойствам могут привести к неожиданному поведению программы. Однак

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

4. Оператор «?.», или optional chaining

В JavaScript также есть возможность использовать оператор «?.», или optional chaining, который возвращает undefined, если свойство не существует, вместо выбрасывания ошибки:

let obj = {};
console.log(obj?.nonExistingProperty); // Вывод: undefined

Это может быть полезно, когда мы хотим просто пропустить отсутствующие свойства, а не обрабатывать их как ошибки.

Заключение

Работа со свойствами объектов в JavaScript может быть сложной, но, понимая, как обрабатывать ошибки отсутствия свойства, вы можете писать более надежный и устойчивый код. Всегда имейте в виду, что лучше предотвратить ошибку, чем исправлять ее последствия.

js ошибка если нет свойства

This looks to me like a classic case of trying to shoehorn one language into the paradigms of another — better IMHO to change your coding style to follow how Javascript does things than try to make it conform to C++ concepts and expectations.

That said, if you want to throw an error as you suggest, you’ll need to define some sort of custom getProperty function, either on the object you’re trying to access or in the global scope. An implementation might look like this:

function getProperty(o, prop) {
    if (o.hasOwnProperty(prop)) return o[prop];
    else throw new ReferenceError('The property ' + prop + 
        ' is not defined on this object');
}

var o = {
    foo: 1,
    bar: false,
    baz: undefined
};

getProperty(o, 'foo'); // 1
getProperty(o, 'bar'); // false
getProperty(o, 'baz'); // undefined
getProperty(o, 'foobar'); 
// ReferenceError: The property baz is not defined on this object

But this is ugly, and now you’ve got this custom language construct in all of your code, making it less portable (if, for example, you wanted to copy any part of your code into another script, you’d have to copy your new function too) and less legible to other programmers. So I’d really recommend working within the Javascript paradigm and checking for undefined before accessing the properties you need (or setting up your code so that false-y values are expected and don’t break things).

As to your second question, why Javascript throws an error for undefined variables but not for undefined object properties, I can’t give any better answer than «Because that’s what’s in the language specification.» Objects return undefined for undefined property names, but undefined variable references throw an error.

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);
}

Понравилась статья? Поделить с друзьями:
  • Ошибка при обращении к модулю
  • Ошибка при обращении к ккт неверный формат
  • Ошибка при обращении к ккт исчерпан ресурс кс фн
  • Ошибка при обращении к ккт 122
  • Ошибка при обращении к игровым серверам fortnite ps4