tag:blogger.com,1999:blog-51711279336859913432024-03-08T14:31:16.382+03:00Делаю интернет лучшеAnonymoushttp://www.blogger.com/profile/08360983599527609488noreply@blogger.comBlogger6125tag:blogger.com,1999:blog-5171127933685991343.post-60379668460332550442011-11-02T10:03:00.000+04:002011-11-02T10:03:03.898+04:00PHP определение языка пользователяЕсли вы делаете сайт на нескольких языках, то вы обязательно столкнётесь с задачей:<br />
<strong>Как определить язык пользователя на стороне сервера (в PHP)?</strong><br />
Один из часто используемых вариантов - использовать Geo IP и дальше уже по стране определять язык.<br />
Но на мой взгляд более правильный способ - это использовать заголовки, которые для этого предназначены, а именно <b>Accept-Language</b>, в котором перечислены с указанием приоритета предпочитаемые языки.<br />
Ниже представлена функция на PHP, которая парсит заголовок Accept-Language и находит наиболее подходящий язык для пользователя из тех, что переданы массивом (параметр $languages).<br />
При этом, если ни одного языка не нашлось в заголовке, то будет использоваться первый из массива $languages.<br />
<pre class="prettyprint">function getAcceptLanguage($languages)
{
if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ||
!$_SERVER['HTTP_ACCEPT_LANGUAGE']) {
return $languages[0];
}
/*
* Разбираем заголовок Accept-Language
*
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
* 14.4 Accept-Language
* Accept-Language = "Accept-Language" ":"
* 1#( language-range [ ";" "q" "=" qvalue ] )
* language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
*
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.9
* 3.9 Quality Values
* qvalue = ( "0" [ "." 0*3DIGIT ] )
* | ( "1" [ "." 0*3("0") ] )
*/
preg_match_all("/([a-z]{1,8})(?:-([a-z]{1,8}))?(?:\s*;\s*q\s*=\s*(1|1\.0{0,3}|0|0\.[0-9]{0,3}))?\s*(?:,|$)/i",
$_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
// Результат по умолчанию - первый из доступных языков
$result = $languages[0];
$max_q = 0;
for ($i = 0; $i < count($matches); $i++) {
// Выделяем очередной язык
$lang = $matches[1][$i];
if (!empty($matches[2][$i])) {
// Переводим ru-RU в ru_RU (т.к. локаль ru_RU)
$lang .= '_'.$matches[2][$i];
}
// Определяем приоритет
if (!empty($matches[3][$i])) {
$q = (float)$matches[3][$i];
} else {
$q = 1.0;
}
// Проверяем есть ли проверяемый язык в массиве доступных
if (in_array($lang, $languages) && ($q > $max_q)) {
$result = $lang;
$max_q = $q;
}
// Если язык только из первой части (например, просто ru, а не ru-RU) и более приоритетный язык еще не найден,
// то пробуем найти в массиве доступых языков тот, который начинается так же
elseif (empty($matches[2][$i]) && ($q * 0.8 > $max_q)) {
$n = strlen($lang);
foreach ($languages as $l) {
if (!strncmp($l, $lang, $n)) {
$result = $l;
// Поскольку не точное совпадение, то уменьшаем q на 20%
$max_q = $q * 0.8;
break;
}
}
}
}
return $result;
}
</pre>
Пример использования:
<br />
<pre class="prettyprint">$locale = getAcceptLanguage(array('en_US', 'ru_RU', 'de_DE'));
</pre>Anonymoushttp://www.blogger.com/profile/08360983599527609488noreply@blogger.com0tag:blogger.com,1999:blog-5171127933685991343.post-69727307100256791792011-09-26T12:22:00.001+04:002011-09-26T12:22:48.252+04:00Git удаление файла или папки из историиЕсли вы случайно закоммитили ненужный файл или папку в git-репозиторий и уже сделали push, то чтобы удалить все следы этого файла или папки в том числе и из истории, достаточно выполнить команду:<br />
<pre class="prettyprint">git filter-branch --tree-filter "rm -rf PATH" HEAD</pre>
где PATH - это относительный путь до файла или папки.<br />
После этого выполните (чтобы перезаписать историю изменений):
<pre class="prettyprint">git push origin master --force</pre>Anonymoushttp://www.blogger.com/profile/08360983599527609488noreply@blogger.com0tag:blogger.com,1999:blog-5171127933685991343.post-72295226975033179632011-09-22T10:43:00.002+04:002011-09-22T11:03:28.444+04:00Подсказки в input и textarea (placeholder)Еще одна довольно частая задача в веб-проектах - это показывать подсказки в input и textarea, чтобы сэкономить место, да и просто для красоты.<br />
Например, такие:<br />
<input onblur="if (!this.value) {this.style.color= '#ccc';this.value = this.defaultValue}" onfocus="if (this.value == this.defaultValue) {this.value = ''; this.style.color= '#ccc'}" style="color: #cccccc;" type="text" value="Поиск" /><br />
До HTML5 это приходилось решать примерно так:<br />
<pre class="prettyprint"><input onblur="if (!this.value) {this.style.color= '#ccc';this.value = this.defaultValue}" onfocus="if (this.value == this.defaultValue) {this.value = ''; this.style.color= '#ccc'}" style="color: #ccc;" type="text" value="Поиск" />
</pre>
Для тех, кто не знает про замечательный атрибут defaultValue, поясню - в нём сохраняет то значение, которое было у поля при загрузке страницы.<br />
На самом деле уже заметно, что делается это нетривиально, но на этом сложности не заканчиваются.<br />
При сабмите формы нужно тоже смотреть, если у поля this.value == this.defaultValue, то нужно сбрасывать это значение, чтобы оно не было отправлено на сервер.<br />
В итоге получаем, что для решения задачи нам нужно написать несколько строк javascript, которые ну никак не красят код страницы + без JS это работать не будет.<br />
<br />
К счастью, в HTML5 позаботились об этом и ввели атрибут <strong>placeholder</strong> <a href="http://dev.w3.org/html5/spec/common-input-element-attributes.html#the-placeholder-attribute">http://dev.w3.org/html5/spec/common-input-element-attributes.html#the-placeholder-attribute</a><br />
И теперь достаточно указать этот атрибут, чтобы получить подсказки для полей:<br />
<pre class="prettyprint"><input <b>placeholder="Подсказка"</b> type="text" />
</pre>
Рабочие примеры: <br />
<input placeholder="Подсказка" type="text" /><br />
<textarea placeholder="Подсказка"></textarea>Anonymoushttp://www.blogger.com/profile/08360983599527609488noreply@blogger.com0tag:blogger.com,1999:blog-5171127933685991343.post-34828799354414182292011-09-09T14:59:00.000+04:002011-09-22T11:06:49.347+04:00Множественная загрузка файлов с помощью HTML5В некоторых формах, хочется позволять загружать сразу несколько файлов.<br />
<div>
Раньше были только следующие варианты сделать это:</div>
<div>
<ol>
<li>Использовать флэш + js <a href="http://swfupload.org/">http://swfupload.org/</a><br />Тут возникает много всяких трудностей и появляются всякие подводные камни, начиная с того, что флэш установлен не у всех, а заканчивая тем, что если вы хотите позволять загружать файлы только авторизованным пользователям, то вам нужно еще как-то передавать PHPSESSID (ну или другой идентификатор сессии), однако нужная сессия может не стартануть из-за настроек безопасности сервера (в частности из-за Suhosin). Поэтому этот вариант всегда требует альтернативного способа.</li>
<li>Есть еще один вариант: сначала показывать один <input type="file" name="files[]" />, а рядом добавить кнопочку еще один файл, по которой с помощью javascript создавать новый элемент input и добавлять его на страницу. Тут всё прозрачно, но не очень юзабельно для пользователя, ведь намного удобнее сразу выбрать несколько файлов и один раз нажать кнопку ОК.</li>
</ol>
<div>
Возможно есть и другие достаточно извращённые варианты реализации массовой загрузки файлов, но все они либо доставляют проблемы разработчикам/админам, либо неудобства пользователю.</div>
</div>
<div>
<br /></div>
<div>
С появлением HTML5 эта задача сильно упростилась, потому что у <input type="file" /> появился новый атрибут <b>multiple</b> (<a href="http://dev.w3.org/html5/markup/input.file.html">http://dev.w3.org/html5/markup/input.file.html</a>).</div>
<div>
Чтобы реализовать множественную загрузку файлов, достаточно прописать этот атрибут у нужного элемента.</div>
<div>
<br /></div>
<div>
Простейший пример:</div>
<div>
<pre class="prettyprint">
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="files[]" <b>multiple=""</b> />
<br />
<input type="submit" />
</form>
</pre>
<span class="Apple-style-span" style="background-color: white; color: #444444; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px;">
</span>Это будет работать во всех современных браузерах: Google Chrome, Firefox, Opera.</div>
Anonymoushttp://www.blogger.com/profile/08360983599527609488noreply@blogger.com0tag:blogger.com,1999:blog-5171127933685991343.post-78293945203734232742011-09-08T23:10:00.001+04:002011-09-22T11:17:20.331+04:00Лучшая минификация javascript с помощью Closure CompilerПрактически в любом веб-проекте возникает необходимость минификации javascript.<br />
На мой взгляд, на сегодняшний день лучше всех остальных с этой задачей справляется <b>Closure Compiler</b> <a href="http://closure-compiler.appspot.com/">http://closure-compiler.appspot.com</a><br />
Помимо онлайн-инструмента, есть также REST API, которое позволяет автоматизировать процесс.<br />
Но проще всего использовать скрипт, написанный на Java, который можно скачать здесь:<br />
<a href="http://code.google.com/intl/ru-RU/closure/compiler/docs/gettingstarted_app.html">http://code.google.com/intl/ru-RU/closure/compiler/docs/gettingstarted_app.html</a><br />
В простейшем случае (SIMPLE_OPTIMIZATIONS) достаточно выполнить команду:<br />
<pre class="prettyprint">java -jar compiler.jar --js file1.js file2.js --js_output_file file.min.js</pre>
Более подробно об уровнях сжатия и оптимизации можете прочитать здесь: <a href="http://code.google.com/intl/ru-RU/closure/compiler/docs/compilation_levels.html">http://code.google.com/intl/ru-RU/closure/compiler/docs/compilation_levels.html</a><br />
Anonymoushttp://www.blogger.com/profile/08360983599527609488noreply@blogger.com0tag:blogger.com,1999:blog-5171127933685991343.post-73907905237874755122011-07-09T11:40:00.004+04:002011-09-22T11:03:13.665+04:00Функции json_encode() и json_decode() на PHPЯ занимаюсь разработкой разработкой веб-приложений на PHP, которые пользователи могут скачать и поставить у себя на хостинге. А поскольку на виртуальных хостингах в России PHP обновляется очень медленно, то нет возможности пользоваться многими полезными расширениями PHP, т.к. их может не быть.<br />
Один из таких примеров - это функции для работы с JSON: json_encode() и json_decode(). Подробнее об этих функциях можно прочитать в документации <a href="http://www.php.net/manual/ru/ref.json.php">http://www.php.net/manual/ru/ref.json.php</a><br />
Проблема в том, что JSON extension входит в состав PHP по умолчанию только, начиная с версии 5.2.0<br />
В реальности на сегодняшний день до сих пор на многих хостингах в рунете установлен PHP 5.1.6<br />
<br />
Довольно сложно представить современное веб-приложение/сайт без использования ajax, и функция json_encode() становится просто необходимой для формирования JSON.<br />
И если у вас нет json extension вы получите одну из ошибок:<br />
<pre class="prettyprint">
Fatal error: Call to undefined function json_encode() in ...
Fatal error: Call to undefined function json_decode() in ...
</pre>
<b>Что же делать?</b><br />
Нужно реализовать эти функции на PHP!<br />
Можно, конечно, использовать уже готовое, например: <a href="http://pear.php.net/package/Services_JSON/">http://pear.php.net/package/Services_JSON/</a><br />
Но! Я встретил уже два сервера, где Service_JSON работал некорректно с русским языком. Тогда не было времени разбираться с причинами и было решено написать свою функцию json_encode() собрав воедино все полезное из комментариев на php.net.<br />
<br />
Чтобы не приходилось думать о наличии json в PHP лучше всего делать так:<br />
<pre class="prettyprint">
if (!function_exists('json_encode')) {
function json_encode($value)
{
// Тут реализация функции json_encode на PHP
}
}
if (!function_exists('json_decode')) {
function json_encode($json, $assoc = false)
{
// Тут реализация функции json_encode на PHP
}
}
</pre>
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">
После этого вы можете спокойно везде использовать функции json_encode() и json_decode() вне зависимости от версии PHP и наличия json extension.</div>
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">
<br /></div>
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">
Все исходники выложены на гитхабе:
<span class="Apple-style-span" style="font-family: arial, sans-serif; font-size: 13px; line-height: 18px;"><a class="ot-anchor" href="https://github.com/alexmuz/php-json" style="color: #3366cc; cursor: pointer; text-decoration: underline;">https://github.com/alexmuz/php-json</a></span><br />
</div>
Функции реализованы как по отдельности в процедурном стиле (файлы json_encode.php и json_decode.php - можно подключать только то, что нужно), так и отдельным статическим классом phpJson.<br />
<br />
Простейший вариант использования:<br />
<pre class="prettyprint">
require_once("phpJson.class.php");
</pre>
<div>
<i>После этого функции json_encode и json_decode станут доступны.</i><br />
</div>Anonymoushttp://www.blogger.com/profile/08360983599527609488noreply@blogger.com0