2011-12-29

В преддверии 2012



 Итак, подходит к концу 2011 год. Не хотелось бы просто брать и закрывать молча эту страницу. Уже весьма скоро мы все соберемся за столами семьями, поднимем бокалы шампанского, выслушаем нашего гаранта конституции и начнется новая итерация. Хочется взглянуть на итоги того, что же принес этот год. Во-первых, лично мне он принес огромное количество опыта и хорошую работу. Благодаря опыту, ко многим вещам при разработке я стал относиться куда более серьезнее и осмысленнее. Скорость изучения новых технологий подскочила на новый уровень. В следующем году буду стремиться продолжать расширять свои познания.


В этом году я освоил следующие программные / серверные / девелоперские вещи: PhpStorm, Membase, MongoDB, Gearman, nginx, реализовал свой первый RESTful API, начал использовать различные веб-сервисы Amazon (чудные облачные технологии, должен признаться), попробовал разработку под Android... Что ж, перечислять можно долго, но это уже весьма малозначимые вещи.

Что же случилось с миром веба в 2011 году? Постараюсь бегло взглянуть на события уходящего года.


Вспоминается начало 2011. Не знаю, кто как, но я почему-то ждал тогда IE9. Надежда умирает последней? Да, оказалось так. Да, он стал лучше, да, он стал чертовски быстрым, но некоторые проблемы как были, так и остались. Ныне ходят слухи, да и не только слухи про IE10. Любой желающий уже может взглянуть на превью версию. Но как-то верится в него с трудом, если честно.

Mozilla перевела свои продукты Firefox и Thunderbird на крайне короткие итерации разработки (как я понял, чуть больше месяца), последовав примеру Google. Теперь как у Firefox, так и у Thunderbird версии обновляются синхронно. К тому же Firefox теперь обновляется довольно тихо и обыватель этого даже и не замечает. Считаю этот шаг для Mozilla крайне правильным. Так браузер будет развиваться динамичнее и различные новые фишки будут доходить до пользователя куда быстрее, пусть и маленькими порциями. Хочется также отметить, что Mozilla, как бы то ни было парадоксально, продолжает жить за счет своего главного конкурента на браузерном рынке Google. Не так давно был продлен весьма дорогостоящий контракт на то, что в Firefox поиском по умолчанию будет оставаться Google.

Opera Labs продолжают экспериментировать с различными новейшими технологиями, которые позволяет стандарт HTML5. Если мне не изменяет память, то недавно они выпустили первую 64-битную версию браузера. Хочется пожелать команде Opera великих свершений в их ожиданиях с экспериментами.

Chrome. Не могу говорить не предвзято об этом браузере лишь потому, что я его недолюбливаю. Но попробую. В 2011 этот браузер как всегда продолжает радовать своих пользователей скоростью. Ближе к концу года он даже обогнал Firefox по популярности. Теперь это самый популярный браузер в мире. Что в нем стало серьезно лучше? Хм, навскидку и не скажешь. Хотя да, в нем появились приложения (так называемые hosted apps). Но пожалуй это все.

А что Safari? Наверное, это один из самых консервативных браузеров в этом году. Честно говоря, Safari обновляю на своем десктопе регулярно, но каких-либо серьезных изменений я не заметил. Хотя наверняка Apple продолжает обновлять внутренний движок Webkit до последней версии перед каждым релизом Safari. И это не может не радовать.

PHP 5.4? Пожалуй вторая вещь которую я очень ждал и которую так и не дождался. Будем надеяться. В конце концов, 25 декабря уже вышла RC4, так что ждать осталось совсем недолго. Нам обещают еще больше производительности, mb_string вшитый по умолчанию, traits (aka mixins) и много других здоровских мелочей.

Очень многое еще хочется написать, но уже день 31-го числа и просто физически не остается времени на это. На этом все.

Желаю всем счастливого Нового Года!

2011-05-23

Standard PHP Library (SPL) Exceptions

Как известно, в PHP помимо стандартного класса Exception имеются также и унаследованные от них (собственно SPL-исключения). Иерархию наследования на официальном мануале любезно предоставил Dawid Krysiak. Всем PHP-кодерам советую с ней ознакомиться:
  • Exception
    • LogicException
      • BadFunctionCallException
        • BadMethodCallException
      • DomainException
      • InvalidArgumentException
      • LengthException
      • OutOfRangeException
    • RuntimeException
      • OutOfBoundsException
      • OverflowException
      • RangeException
      • UnderflowException
      • UnexpectedValueException
Кидайте SPL-исключения, наиболее подходящие по контексту причины потенциальной ошибки или неверных входных данных. Этим вы помогаете людям, которые будут в будущем разбираться в вашем коде или использовать его.

2011-05-15

Проблема времени Windows / Ubuntu на одном компьютере


Я думаю, если у вас на разных [разделах] жесткого диска установлены Windows и Ubuntu, вы сталкивались с проблемой, что Ubuntu интерпретирует время BIOS как UTC и учитывает ваш часовой пояс, тем самым выставляя в BIOS время как UTC и отображая его правильно (+7 часов для Новосибирска). Windows, в свою очередь интерпретирует время BIOS'а как локальное и не "мучается" со всякими UTC.

Проблема возникает в случае, когда вы загружаете Windows после Ubuntu. Время получается смещенным на 7 часов назад. Это очень раздражает, не так ли? Очень долго я жил с этим.
Но, оказалось, от этого естественно есть лекарство. Лезем в /etc/default/rcS и меняем опцию UTC на no. Это решает все проблемы, описанные выше.

Приятного всем кодинга на выходных дома! :)

2011-03-04

Форматирование JSON


Сейчас работаю над проектом, в котором клиентские JavaScripts получают много JSON ответов от сервера. Я же занимаюсь разработкой back-end PHP скриптов и чтобы упростить жизнь своим коллегам по разбору JSON в браузерных консолях (будь то хоть Firebug, хоть Chrome), мне захотелось отдавать в debug режиме отформатированный читабельные JSON данные. Погуглив на эту тему, я сразу же натолкнулся на необходимую функцию, которой и хочу с вами сегодня поделиться:

/**
 * Indents a flat JSON string to make it more human-readable.
 * @param string $json The original JSON string to process.
 * @return string Indented version of the original JSON string.
 */
function indent($json) {

 $result = '';
 $pos = 0;
 $strLen = strlen($json);
 $indentStr = '  ';
 $newLine = "\n";
 $prevChar = '';
 $outOfQuotes = true;

 for ($i = 0; $i <= $strLen; $i++) {

  // Grab the next character in the string.
  $char = substr($json, $i, 1);

  // Are we inside a quoted string?
  if ($char == '"' && $prevChar != '\\') {
   $outOfQuotes = !$outOfQuotes;

   // If this character is the end of an element, 
   // output a new line and indent the next line.
  } else if (($char == '}' || $char == ']') && $outOfQuotes) {
   $result .= $newLine;
   $pos--;
   for ($j = 0; $j < $pos; $j++) {
    $result .= $indentStr;
   }
  }

  // Add the character to the result string.
  $result .= $char;

  // If the last character was the beginning of an element, 
  // output a new line and indent the next line.
  if (($char == ',' || $char == '{' || $char == '[') && $outOfQuotes) {
   $result .= $newLine;
   if ($char == '{' || $char == '[') {
    $pos++;
   }

   for ($j = 0; $j < $pos; $j++) {
    $result .= $indentStr;
   }
  }

  $prevChar = $char;
 }

 return $result;
}

Эта функция сразу же была внедрена в проект и теперь коллегам разбирать JSON куда более удобно. :)

2011-02-20

Как работают сервисы типа "shorten URL"?

Не так давно мне понадобилось реализовать свою генерацию коротких URL. Существует масса сервисов по укорачиванию URL: bit.ly, is.gd... Продолжать можно очень долго.
Возник вопрос, а как же работает этот алгоритм? В коротком URL, как правило, могут присутствовать символы a-z, A-Z, 0-9, возможно, еще какие-то спецсимволы.

Таким образом, попытаемся представить, что на выходе у нас получается 62-ричное число. На вход же подается очень большая строка, которую также можно представить в виде N-ричного числа, где N, очевидно, заведомо больше 62.

Тут точного ответа по поводу, как именно работают эти сервисы, дать невозможно. Но можно предположить, что у них есть глобальный счетчик 10-ричных чисел, его числа они и переводят в 62-ричную систему счисления. И существует таблица, ставящая в соответствие URL - short URL. Таким образом, до 3 символов включительно могут соответствовать количеству URL:

62 * 62 * 62 = 238328

Применительно к практике, не всегда можно использовать столь небольшие числа. Например, при переводе MD5 хеша в 62-ричное число, разрядность числа превосходит разрядность регистров процессора и обычными инструкциями оперировать уже не получается. Поэтому на помощь приходит так называемая Длинная арифметика и модуль для PHP BC Math.

Немного погуглив, я натолкнулся на такую функцию, которая и выполняет всю работу (жаль, автор был немец и пришлось рефакторить названия переменных):

function bc_base_convert($value, $frombase, $tobase)
{
 $stock = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
 if (max($frombase, $tobase) > strlen($stock)) {
  trigger_error('Bad Format max: ' . strlen($stock), E_USER_ERROR);
 }
 if (min($frombase, $tobase) < 2) {
  trigger_error('Bad Format min: 2', E_USER_ERROR);
 }
 $decimal = '0';
 $level = 0;
 $result = '';
 $value = trim((string) $value, "\r\n\t +");
 $sign = '-' === $value[0] ? '-' : '';
 $value = ltrim($value, "-0");
 $len = strlen($value);
 for ($i = 0; $i < $len; $i++) {
  $temp = strpos($stock, $value[$len - 1 - $i]);
  if (false === $temp) {
   trigger_error('Bad Char in input 1', E_USER_ERROR);
  }
  if ($temp >= $frombase) {
   trigger_error('Bad Char in input 2', E_USER_ERROR);
  }
  $decimal = bcadd($decimal, bcmul(bcpow($frombase, $i), $temp));
 }
 if (10 == $tobase) {
  return $sign . $decimal;
 }
 while (1 !== bccomp(bcpow($tobase, $level++), $decimal)) {
 }
 for ($i = $level - 2; $i >= 0; $i--) {
  $factor = bcpow($tobase, $i);
  $number = bcdiv($decimal, $factor, 0);
  $decimal = bcmod($decimal, $factor);
  $result .= $stock[$number];
 }
 $result = empty($result) ? '0' : $result;
 return $sign . $result;
}

Первым параметром подается число (может быть и строка с MD5, например). Второй и третий параметры используются для указания из какой в какую систему счисления переводить число.
Массив $stock может быть модифицирован, например, если вы хотите использовать 63 или более -ричную систему счисления. Эта функция по умолчанию поддерживает переводы чисел в систему счисления до 62-ричных включительно.

Надеюсь, что смог помочь ищущим истину людям. :)

2011-02-19

Сравнение последних сборок браузеров в SunSpider

Сегодня решил снова провести тестирование браузеров в, наверное, всеми известном бенчмарке SunSpider. Были взяты следующие подопытные:
  • Mozilla Firefox 4.0 beta 12 pre (2011-02-18)
  • Google Chrome 11.0.672.2 beta
  • Opera 11.10 build 2005 alpha
  • Internet Explorer 9.0.8080.16413 RC
Safari в этот раз не вошел в результаты тестирования. Но я его также протестировал с целью нормализации последствий разгона своего процессора и памяти.
Тесты проводились в наиболее нейтральном и одинаковом рабочем окружении. Тестовая кофигурация:
  • Intel Core 2 Quad Q6600  @ 3.10GHz
  • DDR2 @ 516MHz (5-5-5-18)
Результаты тестирования:
 
Результаты тестирования браузеров в SunSpider 0.9.1
В этот раз перед моими глазами предстала довольно интересная картина. Несмотря на разгон процессора и памяти на моей машине (30% производительности, если сравнивать по старой версии Safari), результаты позволяют сделать вывод, что, например, Mozilla сделала свой браузер приблизительно в 1.2-1.5 раза быстрее. Эти 2 месяца разработчики браузеров не сидели просто так.
Впечатляют результаты IE9 в этом бенчмарке, хотя ходят слухи, что он просто заточен под быстрое прохождение этого теста.
Opera удалось обогнать Chrome, что должно послужить стимулом инженерам гуглобраузера. По сути, Chrome практически никак не сдвинулся в плане скорости исполнения JavaScript. И если так пойдет и дальше, то ему в спину скоро будет дышать даже неповоротливый некогда Firefox.
 
На этом все, будем ждать следующей итерации этапа развития современных браузеров.

2011-01-18

Множественные формы в Yii

Да, вам не показалось, в этот раз речь пойдет о PHP фреймворке Yii. И да простит меня домен третьего уровня... :)

Когда я работал с Zend Framework, мне очень понравилась их реализация множественных форм, о которых я уже когда-то рассказывал. Перейдя в свое время на Yii, я огорчился, узнав, что там подобной удобностью и не пахнет. Нет, я, разумеется, знал про CChoiceFormat, который позволял использовать множественные формы примерно следующим образом:

CChoiceFormat::format('n%10==1 && n%100!=11#раз|n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20)#раза|#раз', $data->views);

Но согласитесь, это ни разу не эстетично. И этой записи не было бы, если бы не случился выход Yii 1.1.6, в котором и появилась долгожданная и аккуратная, прописанная в файлах интернационализации, поддержка множественных форм. Теперь и в Yii все стало куда симпатичнее и "правильнее". Аналог вышеописанного использования теперь выглядит так:

Yii::t('yii', 'раз|раза|раз', $data->views);

Приятного вам кодинга! :)

2011-01-15

Очередные приколы imagick в PHP под Windows

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

Premature end of script headers, 500 ошибка возврата от Apache.

Проколупавшись в итоге несколько часов, я набрел на интересный комментарий на блоге Mikko. Для тех, кто не знает английский — с тех пор как ImageMagick (собственно, сам движок обработки изображений) стал собираться в Visual Studio 2010 (компилятором VC10), под PHP в Windows у всех проблемы. Последняя работоспособная версия ImageMagick, собранная VC9 — 6.6.4-1. Ее вы можете скачать по этому адресу:

http://image_magick.veidrodis.com/image_magick/binaries/ImageMagick-6.6.4-1-Q16-windows-dll.exe

Удалите все другие, установленные у вас версии и установите эту. Если вы разрабатываете на PHP в Windows, другие версии вам и не понадобятся. Но если вам вдруг потребуется какая-нибудь иная версия из архивов, то поищите ее по следующему адресу:

http://image_magick.veidrodis.com/image_magick/binaries/

В этот раз у меня был установлен PHP 5.3.5 non thread safe (VC9, x86) и аналогичное расширение imagick non thread safe (VC9, x86). Apache работал в режиме FastCGI. Больше ошибок с 500 статусом по поводу imagick у меня не возникает.

Так и в этот раз я победил imagick. :)