<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Веб-программирование</title>
<link href="https://www.jelu.ru"></link>
<id>urn:uuid:32f8ffe6-136f-0d24-90f0-57dfddd0711c</id>
<description type="html"><![CDATA[<p>Статьи на тему веб-программирования и всего что связано с сайто-строением</p>

]]></description>
<updated>2026-09-14T21:21:54+03:00</updated>
<entry>
<title>Используйте безопасные COOKIE.</title>
<author>Jelu</author>
<published>2019-02-25T00:00:00+03:00</published>
<updated>2019-02-25T00:00:00+03:00</updated>
<summary type="html"><![CDATA["
<p>Во время разработки, мы часто используем COOKIE для хранения важной информации, такой как токены авторизации, разные ключи и т.&nbsp;д. Но даже в самых защищенных системах, из-за человеческого фактора, можно допустить возможность выполнения XSS-атак, что может привести к утечке важных данных.</p>

<p>Классическая атака, когда через XSS похищается токен авторизации и потом злоумышленник может войти в систему. Для этих целей, в современных браузерах существует защита: атрибут httponly &mdash; который указывает, что cookie с таким атрибутом нельзя передавать скриптовому языку, например Javascript.</p>

<p>Подробно о XSS и похищении данных можно почитать:</p>

<p><a href="https://developer.mozilla.org/ru/docs/Web/HTTP/%D0%9A%D1%83%D0%BA%D0%B8#%D0%91%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D0%BE%D1%81%D1%82%D1%8C">https://developer.mozilla.org/ru/docs/Web/HTTP/Куки#Безопасность</a></p>

<p>Как использовать:</p>

<p>во время установки COOKIE указывать атрибут httpOnly.</p>

<p>PHP</p>

<pre class="brush: php;  toolbar: false; hljs php hljs">
setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
setrawcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
</pre>

<p>устанавливать 7 атрибут в true</p>

<pre class="brush: php;  toolbar: false; hljs php hljs">
setcookie(&#39;Foo&#39;,&#39;Bar&#39;,0,&#39;/&#39;, &#39;www.sample.com&#39; , false, true);
</pre>

<p>или в заголовке</p>

<pre class="brush: php;  toolbar: false; hljs php hljs">
header(&quot;Set-Cookie: name=value; httpOnly&quot;);</pre>

<p>Так же, можно принудительно ставить все COOKIE с httpOnly через глобальные настройки, но тогда вы не сможете сами работать с COOKIE через Javascript.</p>

<p></p>

<pre class="brush: php;  toolbar: false; hljs php hljs">
&lt;?php
ini_set(&#39;session.cookie_httponly&#39;, 1);
</pre>

<p>&nbsp;</p>

<p>В заключение хочется напомнить, что данная мера не является 100% гарантией защиты от кражи данных, по-этому лучше проверять все данные вводимые пользователями и относиться к любым внешним данным с подозрением, валидируя и проверяя их.</p>

<p>PS: COOKIE тоже являются внешними данными и их тоже необходимо проверять и валидировать!</p>

<p>&nbsp;</p>
]]></summary>
<link href="https://www.jelu.ru/post/ispolzuyte-bezopasnye-cookie.html"></link>
<id>urn:uuid:dbff64fe-fb91-007f-6556-e9365f234dc2</id>
</entry>
<entry>
<title>1С-Битрикс убираем ошибку валидации html5 «The type attribute is unnecessary for JavaScript resources.»</title>
<author>Jelu</author>
<published>2018-02-09T00:00:00+03:00</published>
<updated>2018-02-09T00:00:00+03:00</updated>
<summary type="html"><![CDATA["
<p>В html5 убрали атрибут type у тэга script. Теперь чтобы&nbsp;ваш код был валидным, нужно убрать его&nbsp;из кода. В Битриксе библиотека скриптов генерируется автоматически&nbsp;и нет настроек которые бы позволили убрать этот атрибут в административной панеле.</p>
<p>&nbsp;</p>
<p><img alt="" src="/upload/image/7af489679bb18203d4a95fcf76d64167.jpg" style="width: 800px; height: 375px;" /></p>

<p>&nbsp;</p>

<p>Для решения этой проблемы, можно воспользоваться предобработчиком, встроенным в ядро системы. Для этого надо добавить следующий код в <strong>bitrix/php_interface/init.php</strong> (Если у вас в системе нет такого файла, создайте его, он автоматически будет подгружен системой. init.php служит для того, что бы подключать к системе пользовательские функции, скрипты и обработчики):</p>

<p>&nbsp;</p>

<pre class="brush: php;  toolbar: false; hljs php hljs">
AddEventHandler(&quot;main&quot;, &quot;OnEndBufferContent&quot;, &quot;delete_type&quot;);
function delete_type(&amp;$content) {
	$content = str_replace(&quot; type=\&quot;text/javascript\&quot;&quot;, false, $content);
}
</pre>
]]></summary>
<link href="https://www.jelu.ru/post/bitrix-html5-remove-type-attribute.html"></link>
<id>urn:uuid:b6010039-54f7-9b52-ea28-12357bf1a864</id>
</entry>
<entry>
<title>Запрет переноса javascript в Bitrix.</title>
<author>Jelu</author>
<published>2017-03-11T00:00:00+03:00</published>
<updated>2017-03-11T00:00:00+03:00</updated>
<summary type="html"><![CDATA["
В Битрикс есть полезная опция, перенос всех javascript в конец страницы, которая позволяет ускорить отображение важного контента. Это является одной из рекомендаций PageSpeed Insights
<p><img alt="" src="/upload/image/4b3248e0753323aeb22d03a0fed1332b.jpg" style="width: 589px; height: 208px;" /></p>

<p>Но бывают ситуации, когда перенос скриптов бывает лишним, например вставленная карта сайта или html5shiv, который подгружается для старых браузеров Internet Explorer.</p>

<p>Так вот, если вам нужно запретить перенос скрипта, добавьте ему аттрибут <strong>data-skip-moving=&quot;true&quot;</strong></p>

<pre class="brush: php;  toolbar: false; hljs php">
&lt;!--[if lt IE 9]&gt;
&lt;script data-skip-moving=&quot;true&quot; src=&quot;https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js&quot;&gt;&lt;/script&gt;
&lt;![endif]--&gt;
</pre>
]]></summary>
<link href="https://www.jelu.ru/post/zapret-perenosa-javascript-skripta-v-bitrix.html"></link>
<id>urn:uuid:bd493cb7-207d-3d36-fda7-59b5171733d0</id>
</entry>
<entry>
<title>Исправление ошибки $.browser is undefined</title>
<author>Jelu</author>
<published>2017-03-11T00:00:00+03:00</published>
<updated>2017-03-11T00:00:00+03:00</updated>
<summary type="html"><![CDATA["
<p>Начиная с jquery 1.9 была удалена поддержка $.browser, из-за чего некоторые скрипты перестали функционировать. Для исправления этой ошибки добавьте в свои скрипты следующий код:</p>
<p>&nbsp;</p>
<pre class="brush: php;  toolbar: false; hljs php">
jQuery.browser = {};
jQuery.browser.mozilla=/mozilla/.test(navigator.userAgent.toLowerCase())&amp;&amp;!/webkit/.test(navigator.userAgent.toLowerCase());
jQuery.browser.webkit=/webkit/.test(navigator.userAgent.toLowerCase());
jQuery.browser.opera=/opera/.test(navigator.userAgent.toLowerCase());
jQuery.browser.msie=/msie/.test(navigator.userAgent.toLowerCase());
</pre>
<p>&nbsp;</p>
<p>Его можно вынести в отдельный фаил и подключить сразу после jquery.</p>
]]></summary>
<link href="https://www.jelu.ru/post/ispravlenie-oshibki-browser-is-undefined.html"></link>
<id>urn:uuid:21c4c377-1378-7f7e-0919-795701eb0a88</id>
</entry>
<entry>
<title>Удаление лишних пробелов в PHP.</title>
<author>Jelu</author>
<published>2016-09-25T00:00:00+03:00</published>
<updated>2016-09-25T00:00:00+03:00</updated>
<summary type="html"><![CDATA["
<p>Обрабатывая информацию, собирая ее из разных источников, например с сайта поставщика, мы часто сталкиваемся с тем, что нам надо ее привести в достойный вид, удалив лишние пробелы.</p>

<h2>Удаление пробелов в начале или конце строки.</h2>

<p>Стандартные функция trim( string $str [, string $character_mask = &quot; \t\n\r\0\x0B&quot; ]) удаляет все возможные пробелы в начале или в конце строки, так же эта функция может удалять те символы, которые вам не нужны, например точку или запятую:</p>

<pre class="brush: php;  toolbar: false;">
$str = trim($str, &quot;,&quot;);
</pre>

<p>или</p>

<pre class="brush: php;  toolbar: false;">
$str = trim($str, &quot;.&quot;);
</pre>

<p>Так же есть 2 функции, ltrim и rtrim, которые работают так же как и trim, за исключением того , что ltrim удаляет символы в начале строки, а rtrim в конце.</p>

<h3>Удаление лишних пробелов в самом тексте.</h3>

<p>Иногда нужно удалить лишние пробелы, а иногда и табы, в самом тексте, например: &laquo;Купив&nbsp; телефон&nbsp;&nbsp; сегодня вы&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; получите самый&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; лучший подарок&raquo;. В этом тексте после каждого слова стоит более 1 пробела, Попробуем заменить лишние через регулярное выражение:</p>

<pre class="brush: php;  toolbar: false;">
$str = preg_replace(&#39;/\s+/&#39;, &#39; &#39;, $str);</pre>

<p>В данном случае \s говорит что надо заменить все пробелы, а + включая табы на 1 пробел. Если вы считаете, что регулярные выражения зло, то можно использовать:</p>

<pre class="brush: php;  toolbar: false;">
$str = str_replace(&quot;	&quot;, &quot; &quot;, $str);
while( strpos($str,&quot;  &quot;)!==false){
	$str = str_replace(&quot;  &quot;, &quot; &quot;, $str);
}
</pre>

<h3>Удаление &laquo;не удаляемых&raquo; пробелов.</h3>

<p>Возможно вы столкнулись с такой проблемой, что ни одно из средств перечисленных выше не удаляет пробелы. Для начала рассмотрите внимательно текст, желательно в исходном коде, потому что текст &laquo; Купив телефон сегодня вы получите самый лучший подарок&raquo; может оказаться таким: &laquo;&amp;amp;nbsp;Купив &amp;nbsp;телефон&amp;nbsp;сегодня вы&amp;nbsp;получите самый лучший подарок&raquo;. Для начала надо заменить &amp;amp;nbsp; и &amp;nbsp; просто на пробелы:</p>

<pre class="brush: php;  toolbar: false;">
$str = str_replace(&#39;&amp;amp;&#39;, &#39;&amp;&#39;, $str);
$str = str_replace(&#39;&amp;nbsp;&#39;, &#39; &#39;, $str);
</pre>

<p>А потом, применить один из способов, о котором я писал выше.</p>

<p>Хорошо, это мы сделали, но у нас остались лишние пробелы, которые не удаляются стандартными методами. Вероятнее всего это NO-BREAK SPACE, в таблице utf-8 символов он идет как c2 a0.</p>

<p><img alt="" src="https://www.jelu.ru/upload/image/5d09a3a9d48d869ef49faa3885c1aad8.jpg" style="width: 605px; height: 107px;" /></p>

<p>Для начала попробуйте перевести ваш текст в HEX:</p>

<pre class="brush: php;  toolbar: false;">
echo bin2hex($str);
echo substr_count($str, &quot;\xc2\xa0&quot;);
</pre>

<p>и поищите там: c2a0, как видно на скриншоте, у меня аж 2 таких пробела</p>

<p><img alt="" src="https://www.jelu.ru/upload/image/98c1e9c0935fbb6256ddebc05b8fac2e.jpg" style="width: 532px; height: 71px;" /></p>

<p>Удаление через регулярное выражение:</p>

<pre class="brush: php;  toolbar: false;">
echo preg_replace(&#39;!\s++!u&#39;, &#39; &#39;, $str);
</pre>

<p>Удаление без регулярного выражения:</p>

<pre class="brush: php;  toolbar: false;">
$text = hex2bin(str_replace(&#39;c2a0&#39;, &#39;20&#39;, bin2hex($str)));
while( strpos($text,&#39;  &#39;)!==false){
	$text = str_replace(&quot;  &quot;, &quot; &quot;, $text);
}
$text = trim($text);
</pre>

<p>переводим наш текс в HEX, заменяем NO-BREAK SPACE на обычный пробел, переводим обратно в обычный текст, после этого можно сделать замену пробелов и чистку.</p>

<p>Возможно у вас есть свой способ, может более практичный, как исправлять &quot;не удаляемые&quot; пробелы, то поделитесь в комментариях.</p>
]]></summary>
<link href="https://www.jelu.ru/post/udalenie-lishnih-probelov-v-php.html"></link>
<id>urn:uuid:9f10bf17-cda2-8ef3-ca07-8aa740be2006</id>
</entry>
<entry>
<title>1С-Битрикс. Сортировка по цене в системах с разной валютой.</title>
<author>Jelu</author>
<published>2016-09-19T00:00:00+03:00</published>
<updated>2016-09-19T00:00:00+03:00</updated>
<summary type="html"><![CDATA["
<p>Долгие годы разработчики просили возможность сортировать по цене, там где используется несколько валют. Ведь система позволяет одни цены на товары хранить в рублях, другие в евро и т.&nbsp;д. Это удобно, учитывая, что многие поставщики дают цены в валюте, то проще сохранить ее сразу в валюте и потом на выходе отдавать в рублях, на текущий курс.</p>

<p>И вот случилось чудо, спустя 4-5 лет долгих костылей и просьб на сайте разработчика, в API была добавлена возможность сортировать с учетом валюты.</p>

<p><img alt="" src="/upload/image/8345586070aa7c2186e2a7a974907ceb.jpg" style="width: 600px; height: 111px;" /></p>

<h2>Использование сортировки цен с валютой в 1C-Bitrix версии 16.0.3 и старше</h2>

<p>Для того что бы использовать эту возможность, надо посмотреть в вашей системе, какой тип цены является базовы, для этого идем в Магазин &rarr; Настройки &rarr; Типы цен</p>

<p><img alt="" src="/upload/image/620d723fedbc77b3e7f6f582f303edf6.jpg" style="width: 600px; height: 499px;" /></p>

<p>В моем случае это ID = 1</p>

<p>Дальше мы добавляем в вызов компонента возможность сортировать по убыванию цены, например:</p>

<pre class="brush: php;  toolbar: false;">
		&quot;ELEMENT_SORT_FIELD&quot; =&gt; &quot;CATALOG_PRICE_SCALE_1&quot;,
		&quot;ELEMENT_SORT_ORDER&quot; =&gt; &quot;desc&quot;, 
</pre>

<p>Или возрастанию:</p>

<pre class="brush: php;  toolbar: false;">
		&quot;ELEMENT_SORT_FIELD&quot; =&gt; &quot;CATALOG_PRICE_SCALE_1&quot;,
		&quot;ELEMENT_SORT_ORDER&quot; =&gt; &quot;asc&quot;, 
</pre>

<p>Так же, вы можете добавить 2 параметр сортировки с ключем ELEMENT_SORT_FIELD2 и ELEMENT_SORT_ORDER2.</p>

<h3>Но что делать тем, у кого версия битрикса младше 16.0.3?</h3>

<p>Для этого есть разные способы, я решил использовать дополнительное свойство, в которое я пишу цену в рублях (конвертирую) и уже сортирую по ней. Сейчас я его подробно опишу.</p>

<p>Для начала, нам нужно создать свойство: PRICE_SORT, в название я написал &laquo;Цена в рублях для сортировки&raquo;, тип: число.</p>

<p><img alt="" src="https://www.jelu.ru/upload/image/7dfdcdd21f9b6ab13d22f851c6f73f24.jpg" style="width: 600px; height: 88px;" /></p>

<p>Дальше, нам необходимо заполнить его у всех товаров, я это сделал при помощи вот такого скрипта:</p>

<pre class="brush: php;  toolbar: false;">
function update_catalog_price_sort(){
	
	$count = 0;	

	try{
		$arFilter = Array( &quot;IBLOCK_ID&quot; =&gt; 2 );
		$res = CIBlockElement::GetList(Array(), $arFilter, false, false, Array(&quot;ID&quot;, &quot;PROPERTY_PRICE_SORT&quot;, &#39;CATALOG_GROUP_1&#39;) );
		while($row = $res-&gt;GetNext())
		{
			$price = $row[&#39;CATALOG_PRICE_1&#39;];

			echo &quot;Start update {$row[&#39;ID&#39;]}: {$price} {$row[&#39;CATALOG_CURRENCY_1&#39;]} to &quot;;

			if ($row[&#39;CATALOG_CURRENCY_1&#39;] != &#39;RUB&#39;){
				$price = CCurrencyRates::ConvertCurrency($price, $row[&#39;CATALOG_CURRENCY_1&#39;], &#39;RUB&#39;);
			}

			if ($price != $row[&#39;PROPERTY_PRICE_SORT_VALUE&#39;]){

				CIBlockElement::SetPropertyValuesEx($row[&#39;ID&#39;], 2, array(
					&#39;PRICE_SORT&#39;  =&gt; $price
				));

				echo &quot;{$price} {RUB} - DONE \n&quot;;

				$count++;

				sleep(0.2);

			} else {
				echo &quot;{$price} {RUB} - NOT NEED UPDATE \n&quot;;
			}
		}

	} catch(Exception $ex) {
		smail(&#39;Запуск обновления цен-сортировок&#39;, &#39;Провал - обновления:&#39; . $ex-&gt;getMessage() );
	}
	
	return $count;
}
</pre>

<p>Вначале мы запрашиваем все товары в системе, у меня около 120 тыс. Из запроса мы получаем:</p>

<ul>
	<li>ID - индификатор товара</li>
	<li>CATALOG_PRICE_1 &mdash; цена товара. Учтите, что если у вас, базовый тип цены другой (смотри выше где можно проверить), то и цифра в конце ключа, будет другой. В любом случае, вы всегда можете сделать print_r($row) и узнать правильность ID базовой цены</li>
	<li>CATALOG_CURRENCY_1 &mdash; в какой валюте сохранена цена. Так же как и с ценой, важно учитывать ID в конце ключа</li>
</ul>

<p>Дальше все просто, если валюта отличается от RUB, делаем конвертацию:</p>

<pre class="brush: php;  toolbar: false;">
$price = CCurrencyRates::ConvertCurrency($price, $row[&#39;CATALOG_CURRENCY_1&#39;], &#39;RUB&#39;);
</pre>

<p>и потом полученную цену сравниваем с тем, что у нас сохранено в PRICE_SORT (ключ в массиве: PROPERTY_PRICE_SORT_VALUE), если цены различаются, обновляем.</p>

<p>Для отладки я использую вывод информации и отлов исключения, с уведомление на почту. Дальше нам остается функцию update_catalog_price_sort() поместить в агент, который будет обновлять цены. Я его добавил в агент обновляющий валюту. Он у меня запускается раз в сутки, когда на сервере минимальная нагрузка.</p>

<p>Учтите важный момент! Это ресурсоёмкая задача, по-этому агенты должны исполняться на cron.</p>

<p>Ну и самое важное, прописываем наше поле PRICE_SORT в вызове компонента:</p>

<pre class="brush: php;  toolbar: false;">
	&quot;ELEMENT_SORT_FIELD&quot; =&gt; &#39;PROPERTY_PRICE_SORT&#39;,
</pre>

<p>Надеюсь эта статья будет вам полезна, если вы нашли ошибки или опечатки, пишите в комментариях.</p>
]]></summary>
<link href="https://www.jelu.ru/post/1s-bitriks-sortirovka-po-cene-v-sistemah-s-raznoy-valyutoy.html"></link>
<id>urn:uuid:5e3520cb-b3d3-7e4f-9fda-f9754c9aaf37</id>
</entry>
<entry>
<title>Bitrix. Исправляем ошибку «Работа с сокетами - Ошибка! Не работает»</title>
<author>Jelu</author>
<published>2016-05-21T00:00:00+03:00</published>
<updated>2016-05-21T00:00:00+03:00</updated>
<summary type="html"><![CDATA["
<p>Во время тестирования сайта, выскакивает следующая ошибка:</p>

<pre class="brush: php;  toolbar: false;">
Работа с сокетами (check_socket): Fail</pre>

<p><img alt="" src="/upload/27-02-2016/001.png" title="" /><br />
А в журнале мы видим следующий лог:</p>

<pre class="brush: php;  toolbar: false;">
2016-Feb-27 13:41:10 Работа с сокетами (check_socket): Fail
Connection to site.ru:80  Success
== Request ==
GET /bitrix/admin/site_checker.php?test_type=socket_test&amp;unique_id=83f81a8666278b68e58012ce161a1dd0 HTTP/1.1
Host:  site.ru


== Response ==
HTTP/1.1 404 Not Found
Server: nginx/1.4.6 (Ubuntu)
Date: Sat, 27 Feb 2016 12:41:10 GMT
Content-Type: text/html
Content-Length: 177
Connection: keep-alive

== Body ==
&lt;html&gt;
&lt;head&gt;&lt;title&gt;404 Not Found&lt;/title&gt;&lt;/head&gt;
&lt;body bgcolor=&quot;white&quot;&gt;
&lt;center&gt;&lt;h1&gt;404 Not Found&lt;/h1&gt;&lt;/center&gt;
&lt;hr&gt;&lt;center&gt;nginx/1.4.6 (Ubuntu)&lt;/center&gt;
&lt;/body&gt;
&lt;/html&gt;

==========
</pre>

<p>Для начала мы видим в этом логе, что при запросе система получает 404 ошибку. Нам нужно понять почему она происходит. Для этого нам нужно проверить логи веб-сервера. Так как у меня работает на nginx + apache2, я открыл логи nginx (Linux /var/log/nginx/error.log).</p>

<p>В данном логе я ищу мой запрос</p>

<pre class="brush: php;  toolbar: false;">
2016/02/27 13:41:10 [error] 2309#0: *658 openat() &quot;/usr/share/nginx/html/bitrix/admin/site_checker.php&quot; failed (2: No such file or directory), client: 127.0.0.1, server: localhost, request: &quot;GET /bitrix/admin/site_checker.php?test_type=socket_test&amp;unique_id=83f81a8666278b68e58012ce161a1dd0 HTTP/1.1&quot;, host: &quot;site.ru&quot;
</pre>

<p>И что мы тут видим? Когда скрипт обращается сам к себе, то происходит обращение вообще не понятно по какому адресу &laquo;/usr/share/nginx/html/bitrix/admin/site_checker.php&raquo;, тогда как сайт лежит: /var/www/site.ru/www/bitrix/admin/site_checker.php</p>

<p>Так же обратите внимание по какому адресу обращается скрипт:</p>

<pre class="brush: php;  toolbar: false;">
client: 127.0.0.1, server: localhost, 
</pre>

<p>Из этого мы делаем вывод что site.ru привязан к localhost и при обращении сайта к самому себе пытается найти файлы не в папке сайта, а в папке nginx по умолчанию. Открыв фаил /etc/hosts я увидел следующую запись:</p>

<pre class="brush: php;  toolbar: false;">
127.0.0.1 localhost.localdomain localhost site.ru
</pre>

<p>Изменив эту строчку на</p>

<pre class="brush: php;  toolbar: false;">
127.0.0.1 localhost.localdomain localhost
</pre>

<p>я успешно прошел тест, и ошибка больше не возникала!</p>
]]></summary>
<link href="https://www.jelu.ru/post/bitrix-ispravlyaem-oshibku-rabota-s-soketami-oshibka-ne-rabotaet.html"></link>
<id>urn:uuid:608b414e-3339-cf7d-2bcd-5951e64459a9</id>
</entry>
<entry>
<title>Простой способ зафиксировать блок по горизонтали или вертикали.</title>
<author>Jelu</author>
<published>2016-05-21T00:00:00+03:00</published>
<updated>2016-05-21T00:00:00+03:00</updated>
<summary type="html"><![CDATA["
<p>Как хорошо известно, свойство CSS &laquo;position:fixed&raquo; распространяется как на вертикальное, так и на горизонтальное прокручивание.</p>

<p>&nbsp;</p>

<p><strong><a href="/upload/tutorial/position/sample1.html" target="_blank">Пример 1</a></strong></p>

<p>&nbsp;</p>

<pre class="brush: php;  toolbar: false;">
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
	&lt;meta charset=&quot;utf-8&quot; /&gt;
	&lt;title&gt;&lt;/title&gt;
	&lt;script src=&quot;http://yandex.st/jquery/1.8.1/jquery.min.js&quot;&gt;&lt;/script&gt;

	&lt;style&gt;
	.wrapper{ width: 2500px; height: 2500px;}
	#menu{ width: 200px; height: 150px; background: yellow; position: fixed; top: 0px; left:0px;}
	&lt;/style&gt;
&lt;/head&gt;

&lt;body&gt;
	&lt;div class=&quot;wrapper&quot;&gt;

		&lt;div id=&quot;menu&quot;&gt;

		&lt;/div&gt;

	&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;

</pre>

<p>&nbsp;</p>

<p>Как видите, желтый квадрат всегда зафиксирован в левом верхнем углу, куда бы мы не скроллировали. Но если вам надо сделать зафиксированное меню, которое будет всегда видно по вертикали, но по горизонтали нет.</p>

<p>&nbsp;</p>

<p><strong><a href="/upload/tutorial/position/sample2.html" target="_blank">Пример 2</a></strong></p>

<p>&nbsp;</p>

<p>Но что поменялось в этом примере? Давайте глянем код</p>

<p>&nbsp;</p>

<pre class="brush: php;  toolbar: false;">
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
	&lt;meta charset=&quot;utf-8&quot; /&gt;
	&lt;title&gt;&lt;/title&gt;
	&lt;script src=&quot;http://yandex.st/jquery/1.8.1/jquery.min.js&quot;&gt;&lt;/script&gt;

	&lt;style&gt;
	.wrapper{ width: 2500px; height: 2500px;}
	#menu{ width: 200px; height: 150px; background: yellow; position: absolute; top: 0px; left:0px;}
	&lt;/style&gt;
&lt;/head&gt;

&lt;body&gt;
	&lt;div class=&quot;wrapper&quot;&gt;

		&lt;div id=&quot;menu&quot;&gt;

		&lt;/div&gt;

	&lt;/div&gt;

	&lt;script&gt;
		$(document).scroll(function(){
			$(&#39;#menu&#39;).css({
				top: $(document).scrollTop()
			});
		});
	&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>

<p>&nbsp;</p>

<p>Во втором примере, position:fixed мы заменили на position:absolute; а фиксирование по вертикали, сделали через jQuery. Скрипт обрабатывает скролл и устанавливает значение top равное $(document).scrollTop(), то есть текущее значение отступа прокрутки для всего документа.</p>

<p style="margin-bottom: 0cm; line-height: 100%;">&nbsp;</p>

<p style="margin-bottom: 0cm; line-height: 100%;">Теперь давайте сделаем тоже самое, для горизонтальной прокрутки (скроллирования).</p>

<p style="margin-bottom: 0cm; line-height: 100%;">&nbsp;</p>

<p style="margin-bottom: 0cm; line-height: 100%;"><strong><a href="/upload/tutorial/position/sample3.html" target="_blank">Пример 3</a></strong></p>

<p>&nbsp;</p>

<pre class="brush: php;  toolbar: false;">
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
	&lt;meta charset=&quot;utf-8&quot; /&gt;
	&lt;title&gt;&lt;/title&gt;
	&lt;script src=&quot;http://yandex.st/jquery/1.8.1/jquery.min.js&quot;&gt;&lt;/script&gt;

	&lt;style&gt;
	.wrapper{ width: 2500px; height: 2500px;}
	#menu{ width: 200px; height: 150px; background: yellow; position: absolute; top: 0px; left:0px;}
	&lt;/style&gt;
&lt;/head&gt;

&lt;body&gt;
	&lt;div class=&quot;wrapper&quot;&gt;

		&lt;div id=&quot;menu&quot;&gt;

		&lt;/div&gt;

	&lt;/div&gt;

	&lt;script&gt;
		$(document).scroll(function(){
			$(&#39;#menu&#39;).css({
				left: $(document).scrollLeft()
			});
		});
	&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>

<p>&nbsp;</p>

<p>В этом скрипте, мало что изменилось, за исключением одного, в javascript мы обрабатываем не отступ сверху, а отступ слева, и устанавливаем в стили не top значение, а left.</p>

<p><strong>left: $(document).scrollLeft()</strong></p>
]]></summary>
<link href="https://www.jelu.ru/post/prostoy-sposob-zafiksirovat-blok-po-gorizontali-ili-vertikali.html"></link>
<id>urn:uuid:903b846f-1ed0-f7a5-adad-d6116bea7e25</id>
</entry>
<entry>
<title>Решение проблемы с обрезанными массивами в PHP 5</title>
<author>Jelu</author>
<published>2016-05-21T00:00:00+03:00</published>
<updated>2016-05-21T00:00:00+03:00</updated>
<summary type="html"><![CDATA["
<p style="text-align: justify;">Хотел сегодня написать небольшую статью о 2х параметрах которые появились в PHP, это post_max_size и post_max_vars.</p>

<p>&nbsp;</p>

<p><strong>post_max_size</strong></p>

<p style="text-align: justify;">Устанавливает максимально допустимый размер данных, отправляемых методом POST. Этот параметр влияет на вес передаваемых данных методом POST, так же важно учитывать его при реализации загрузки файлов через скрипты. По умолчанию данный параметр стоит 8Мб.</p>

<p><a href="http://www.php.net/manual/ru/ini.core.php#ini.post-max-size">http://www.php.net/manual/ru/ini.core.php#ini.post-max-size</a> <strong>&nbsp;</strong></p>

<p>&nbsp;</p>

<p><strong>post_max_vars</strong></p>

<p style="text-align: justify;">Если про post_max_size все хорошо описано в мануале и он есть по умолчанию в конфигурации php, то про параметр post_max_vars глухая тишина. Так что же это такой за параметр. Post_max_vars указывает интерпретатору сколько будет обрабатываться строк в POST запросе, ограничение стоит по умолчанию 200 строк.</p>

<p style="text-align: justify;">Для крупных проектов, особенно реализованных на таких тяжеловесах как Битрикс это довольно мало.</p>

<p style="text-align: justify;">Поэтому, если вы столкнулись с проблемой, когда при сохранении данных вы получается обрезанный POST массив или массив в котором только часть передаваемых строк, значит вам нужно не искать ошибку в вашем скрипте, а менять параметры на сервере. Если такой возможности нет, значит надо переделывать скрипт так, что бы он не превышал лимитов.</p>

<p style="text-align: justify;">&nbsp;</p>

<p style="text-align: justify;">Меняем значения <strong>post_max_size и post_max_vars</strong></p>

<p style="text-align: justify;">Если у вас в .htaccess разрешено переобъявление php параметров, то можно указать их там, например так:<br />
<br />
<em>php_value post_max_size 128M</em><br />
<em>php_value post_max_vars 800</em></p>

<p style="text-align: justify;">&nbsp;</p>

<p style="text-align: justify;">Либо поменять в php.ini. Параметр post_max_size уже там указан, и достаточно найти его поиском и поменять, тогда как post_max_vars придется дописать, например под post_max_size.</p>
]]></summary>
<link href="https://www.jelu.ru/post/reshenie-problemy-s-obrezannymi-massivami-v-php-5.html"></link>
<id>urn:uuid:8f0c22f8-6e8e-f7df-7758-f0f62aac3b6e</id>
</entry>
<entry>
<title>Пишем свой простой вариант &quot;живого поиска&quot;.</title>
<author>Jelu</author>
<published>2016-05-21T00:00:00+03:00</published>
<updated>2016-05-21T00:00:00+03:00</updated>
<summary type="html"><![CDATA["
<p style="margin-bottom: 0cm;">Сегодня я напишу статью, о том как сделать простую версию так называемого &laquo;живого поиска&raquo;. Для тех кто не в курсе, живой поиск &mdash; это когда при вводе искомого текста, появляется подсказка, с возможными вариантами. Примером тому служит Яндекс и Google.</p>
<p>&nbsp;</p>
<p>По сути &laquo;живой поиск&raquo; это обычный AJAX скрипт, который обращается к базе данных, производит в ней поиск, и возвращает ответ скрипту. Для работы поиска я буду использовать Jquery.</p>
<p>&nbsp;</p>
<p><strong>Итак, создадим простую форму поиска:</strong></p>
<p>&nbsp;</p>
<pre class="brush: html;  toolbar: false;">

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Простой живой поиск&lt;/title&gt;
    &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;
    &lt;script src=&quot;//yandex.st/jquery/1.7.2/jquery.min.js&quot;&gt;&lt;/script&gt;

    &lt;style&gt;
		.search_area{
			width: 350px;
			margin: 0px;
			position: relative;
		}

		#search_box{
			width:200px;
			padding:2px;
			margin:1px;
			border:1px solid #000;
		}

		#search_advice_wrapper{
			display:none;
			width: 350px;
			background-color: rgb(80, 80, 114);
			color: rgb(255, 227, 189);
			-moz-opacity: 0.95;
			opacity: 0.95;
			-ms-filter:&quot;progid:DXImageTransform.Microsoft.Alpha&quot;(Opacity=95);
			filter: progid:DXImageTransform.Microsoft.Alpha(opacity=95);
			filter:alpha(opacity=95);
			z-index:999;
			position: absolute;
			top: 24px; left: 0px;
		}

		#search_advice_wrapper .advice_variant{
			cursor: pointer;
			padding: 5px;
			text-align: left;
		}
		#search_advice_wrapper .advice_variant:hover{
			color:#FEFFBD;
			background-color:#818187;
		}
		#search_advice_wrapper .active{
			cursor: pointer;
			padding: 5px;
			color:#FEFFBD;
			background-color:#818187;
		}

    &lt;/style&gt;

&lt;/head&gt;

&lt;body&gt;
	&lt;div class=&quot;search_area&quot;&gt;
		&lt;form action=&quot;&quot; method=&quot;GET&quot;&gt;
			&lt;input type=&quot;text&quot; name=&quot;query&quot; id=&quot;search_box&quot; value=&quot;&quot; autocomplete=&quot;off&quot;&gt;
			&lt;input type=&quot;submit&quot; value=&quot;Поиск&quot;&gt;
		&lt;/form&gt;
		&lt;div id=&quot;search_advice_wrapper&quot;&gt;&lt;/div&gt;
	&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;


</pre>
<p>Обратите внимание на  autocomplete="off" у input'а, это для того чтобы отключить подсказки браузера, которые он показывает при повторном наборе текста в форме.</p>
<p>&nbsp;</p>
<p>Слой &lt;div id=&quot;search_advice_wrapper&quot;&gt;&lt;/div&gt; является скрытым, и будет появляться только когда будут варианты поиска.</p>
<p>&nbsp;</p>
<p>Теперь займемся созданием javascript скрипта.</p>

<pre class="brush: php;  toolbar: false;">

&lt;script type=&quot;text/javascript&quot;&gt;
var suggest_count = 0;
var input_initial_value = '';
var suggest_selected = 0;

$(window).load(function(){
	// читаем ввод с клавиатуры
	$("#search_box").keyup(function(I){
		// определяем какие действия нужно делать при нажатии на клавиатуру
		switch(I.keyCode) {
			// игнорируем нажатия на эти клавишы
			case 13:  // enter
			case 27:  // escape
			case 38:  // стрелка вверх
			case 40:  // стрелка вниз
			break;

			default:
				// производим поиск только при вводе более 2х символов
				if($(this).val().length>2){

					input_initial_value = $(this).val();
					// производим AJAX запрос к /ajax/ajax.php, передаем ему GET query, в который мы помещаем наш запрос
					$.get("/ajax/ajax.php", { "query":$(this).val() },function(data){
						//php скрипт возвращает нам строку, ее надо распарсить в массив.
						// возвращаемые данные: ['test','test 1','test 2','test 3']
						var list = eval("("+data+")");
						suggest_count = list.length;
						if(suggest_count > 0){
							// перед показом слоя подсказки, его обнуляем
							$("#search_advice_wrapper").html("").show();
							for(var i in list){
								if(list[i] != ''){
									// добавляем слою позиции
									$('#search_advice_wrapper').append('&lt;div class=&quot;advice_variant&quot;&gt;'+list[i]+'&lt;/div&gt;');
								}
							}
						}
					}, 'html');
				}
			break;
		}
	});

	//считываем нажатие клавишь, уже после вывода подсказки
	$("#search_box").keydown(function(I){
		switch(I.keyCode) {
			// по нажатию клавишь прячем подсказку
			case 13: // enter
			case 27: // escape
				$('#search_advice_wrapper').hide();
				return false;
			break;
			// делаем переход по подсказке стрелочками клавиатуры
			case 38: // стрелка вверх
			case 40: // стрелка вниз
				I.preventDefault();
				if(suggest_count){
					//делаем выделение пунктов в слое, переход по стрелочкам
					key_activate( I.keyCode-39 );
				}
			break;
		}
	});

	// делаем обработку клика по подсказке
	$('.advice_variant').live('click',function(){
		// ставим текст в input поиска
		$('#search_box').val($(this).text());
		// прячем слой подсказки
		$('#search_advice_wrapper').fadeOut(350).html('');
	});

	// если кликаем в любом месте сайта, нужно спрятать подсказку
	$('html').click(function(){
		$('#search_advice_wrapper').hide();
	});
	// если кликаем на поле input и есть пункты подсказки, то показываем скрытый слой
	$('#search_box').click(function(event){
		//alert(suggest_count);
		if(suggest_count)
			$('#search_advice_wrapper').show();
		event.stopPropagation();
	});
});

function key_activate(n){
	$('#search_advice_wrapper div').eq(suggest_selected-1).removeClass('active');

	if(n == 1 && suggest_selected < suggest_count){
		suggest_selected++;
	}else if(n == -1 && suggest_selected > 0){
		suggest_selected--;
	}

	if( suggest_selected > 0){
		$('#search_advice_wrapper div').eq(suggest_selected-1).addClass('active');
		$("#search_box").val( $('#search_advice_wrapper div').eq(suggest_selected-1).text() );
	} else {
		$("#search_box").val( input_initial_value );
	}
}
&lt;/script&gt;
</pre>
<p>Я постарался описать этот скрипт по максимуму в комментариях. По сути скрипт делется на    несколько частей:</p>
<ol>
<li>Считываем ввод с клавиатуры, получаем данные из базы данных и выводим их</li>
<li>Делаем скрытие слоя с подсказками, при нажатии на Escape и Enter</li>
<li>Делаем переход по слою с подсказками, через нажатие стрелок клавиатуры ( вверх и вниз)</li>
<li>Скрытие слоя с подсказками при клике на поле сайта и открытие его при клике на input</li>
<li>При клике на подсказку мы вписываем слово в input поиска и прячем форму подсказки.</li>
</ol>
<p>А теперь давайте посмотрим содержимое файла /ajax/ajax.php, к которому мы подключаемся за теми самыми подсказками.</p>
<pre class="brush: php;  toolbar: false;">	
	if(!empty($_GET['query'])){
		$query = (string)$_GET['query'];
		$array = array();
		$request  = $db->query("SELECT `description`, `name` FROM `prefix_name` WHERE `description` LIKE '%". $db->real_escape_string($query) . "%' OR `name` LIKE '%". $db->real_escape_string($query) . "%' LIMIT 0, 10");
		while($data =$db->fetch_assoc($request)){
			$array[] = $data['name'];
		}

		echo "['".implode("','", $array)."']";
	}
	exit();
</pre>
<p>Пример работы скрипта:  <a href="/upload/tutorial/suggest/script.html" target="_blank">https://jelu.ru/upload/tutorial/suggest/script.html</a></p>]]></summary>
<link href="https://www.jelu.ru/post/pishem-svoy-prostoy-variant-zhivogo-poiska.html"></link>
<id>urn:uuid:caac266a-71ca-308c-0dba-5514c86fbc93</id>
</entry>
</feed>