Nov 28

Да, да, я знаю, что в наш век все уже давно перешли на использование utf-8 при построении веб-сайтов, но остались еще и такие, которые пользуються “допотопными”, “отстойными”, и вообще “не-тру” кодировками типа CP1251 (также известной как Windows-1251), KOI8-R и прочих.

Ни для кого ни секрет, что кодировкой получаемых через Ajax данных по-умолчанию принимается UTF-8. Не все знают, что это умолчание можно изменить, указав кодировку явно через заголовок “Content-Type: text/html; charset=cp1251″. Сегодня вот столкнулся с интересным багом, на который убил довольно много времени.

Сервер отдает некоторый текст по запросу (ajax) в кодировке CP1251, предварительно установив соответствующий заголовок - “Content-Type: text/html; charset=cp1251″. На клиенте использовалась библиотека jQuery:

$('#books').load('books.php', {action: 'list'});

Всё работало замечательно… До тех пор, пока я не открыл страничку в IE7. Как ни странно, но ничего не загрузилось. После длительных раздумий, установки alert-ов куда нужно, и куда нет код был заменен следующим кодом:

$.ajax({
  method: 'get',
  url: 'books.php',
  success: function(data) {
    $('#books').html(data);
  },
  error: function(xhr, textStatus, errorThrown) {
    alert(textStatus);
  },
  data: {action: 'list'}
});

В FF всё продолжало работать, а вот IE начал выдавать странную надпись “parsererror”. Гугление никаких результатов не дало - ни одного похожего случая… После, примерно, 10 минут попыток “запустить” страничку в IE, что-то меня дернуло посмотреть на серверный код. Глаза сразу упали на строку установки Content-Type-а. Недолго думая, я поставил charset=utf-8, и, о чудо, IE загрузил всё как положено (правда в неправильной кодировке, но всё же - уже плюс). Догадавшись в чем может быть дело, я установил кодировку в “windows-1251″, после чего всё заработало на ура.

Собственно, мораль сей басни такова - юзайте, люди, юникод, и будет вам счастье.

written by fxposter \\ tags: , ,

Nov 28

Вышел релиз очередной версии, наверное, самой популярной СУБД - MySQL 5.1. Качаем и читаем нововведения. А я пойду ставить.

written by fxposter \\ tags:

Oct 13

Начинаю писать Data Mapper на PHP. На вопрос “почему” всего лишь 2 ответа - “хочется” и “нужен по работе простой, но удобный ORM”. Кто захочет присоединиться и в свободное время помогать мне его развивать - милости прошу.

На данный момент это всё находится в ОЧЕНЬ начальной стадии - ничего не работает, да и как будут работать некоторые вещи я еще не решил. Сейчас работа с бд строиться через mysqli, переход на PDO или поддержка других СУБД не планируется (но если кто-нибудь захочет - сделаем, там не так уж и много работы).

Текущее состояние можно будет посмотреть в SVN. Тем, кто захочет помочь, нужно будет зарегистрироваться на Assembla и сказать мне свой логин.

Буду ОЧЕНЬ рад обсудить технические стороны проекта, а также его нужность.

written by fxposter \\ tags: , ,

Aug 26

Вопрос, так, невзначай. Хотели бы вы аналог получить в Symfony аналог наследования шаблонов из Django?

PS. Палюсь… Ой как палюсь. :)

written by fxposter \\ tags: , ,

Aug 25

В Zend Framework всё замечательно! …пока не начинаешь его использовать на полную катушку…

Сегодня я просто приведу пример трех абсолютно различных синтаксисов, которые используются в Zend_Db для фетчинга, добавления и удаления записей.

В Zend_Db везде можно использовать array в качестве where, только нигде не сказано, как этот array должен выглядеть, а аналогий не прослеживается…

$productsTable = new Products();

Обычная вставка нового продукта:

$productsTable->insert(array(
    'name'  => 'Fucked Product!',
    'price' => 999.99,
  ));

Всё OK.

Поиск продукта по аналогии со вставкой:

$productsTable->fetchRow(array(
    'name'  => 'Fucked Product!',
    'price' => 999.99,
  ));

Выдаст SQL типа такого:

SELECT products.* FROM products WHERE (name) AND (price)

Что приведет к выдаче первого попавшегося продукта (что, естественно, нам не подходит).

Правильный вариант поиска продукта:

$productsTable->fetchRow(array(
    'name = ?'  => 'Fucked Product!',
    'price = ?' => 999.99,
  ));

Удаление продукта по аналогии с поиском:

$productsTable->delete(array(
    'product_id = ?' => 1000,
  ));

Выдаваемый SQL:

DELETE FROM products WHERE 1000

Приведет к удалению всех продуктов (sic!).

Причем самое интересное, что в случае со строкой - у вас будет ошибка, а вот в случае с числом, которое escape’ить не нужно - будут проблемы. Я с ними на днях столкнулся, и… получил пустую таблицу, в которой были важные данные. :( Благо, бэкап был.

Удаление продукта по аналогии со вставкой:

$productsTable->delete(array(
    'product_id' => 1000,
  ));

Полностью аналогично предыдущему случаю.

Правильный вариант удаления продукта:

$productsTable->delete(
    $productsTable->getAdapter()->quoteInto('product_id = ?', 1000)
  );

Вот вам и офигенный ZF. Если использовать его не постоянно, а изредка для отдельных задач - натыкаешься на подобные грабли.

written by fxposter \\ tags: ,

Aug 20

На днях вышла долгожданная новая версия достаточно популярного в узких кругах ORM - Propel 1.3.

Из интересных мне нововведений:

  • В основе Propel 1.3 лежит новый механизм работы с базами данных - PDO, который заменил Creole и привел к ощутимому повышению скорости работы.
  • Теперь не нужно вручную загружать классы Propel и свои модели - теперь это делается автоматически (через autoloading в PHP)
  • “Object Instance Pooling”, или, как его называет небезызвестный Фаулер - Identity Map. Причем, что самое интересное, это работает не только с retrieveByPk(), но и со всему doSelect*()-методами (в зависимости от переданных аргументов), что позволяет ускорить работу засчет отсутствия лишних запросов к бд, а также ненужности построения одинаковых обьектов несколько раз.
  • Связи один-к-одному теперь поддерживаются нативно (блин, хочу много-ко-многим!)
  • Куча мелких (и не очень) исправлений и улучшений

Поподробнее можно прочитать на RedoTheWeb, в также на офсайте Propel.

PS. Сам еще не юзал, но нужно будет попробовать. На мой взгляд, самый интересный момент связан с тем, можно ли переопределить фетчинг записей, например - выбирать только записи с is_hidden = false, да так, чтобы переопределять пришлось только одну функцию.

Update: Как написали на официальном блоге Symfony - “Object Instance Pooling is not an Identity Map because the database request is still needed”. Нужно будет изучить этот вопрос.

written by fxposter \\ tags: , ,

Aug 17

Если вы используете Symfony, планируете это делать или просто интересуетесь этим фреймворком - значит нам нужно поговорить. Мои контакты:

  • ICQ: 625585
  • Jabber: fxposter@gmail.com
  • Skype: fxposter

written by fxposter \\ tags: ,

Aug 15

Ссылко.

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

written by fxposter \\ tags: , ,

Aug 10

Вчера наткнулся на сайте Eric IDE (прикольная, довольно легковесная IDE для питона и руби) на достаточно интересную картину, а именно:

Eric IDE

Более подробный пример.

Думаю, проблема всем понятна - при указании размера шрифта в процентах (да и в em-ах тоже, кстати говоря) для тех элементов, которые могут быть вложенными приводит к плохим последствиям! Будьте осторожны!

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

written by fxposter \\ tags:

Jul 22

Еще немного помучал PHP 5.3 на тему Lambda-функций:

$array = array(1, 2, 3);
$array = array_map(function($v) { return $v * $v; }, $array);
var_dump($array);
array(3) {
  [0]=>
  int(1)
  [1]=>
  int(4)
  [2]=>
  int(9)
}

I like that!

written by fxposter \\ tags: , , ,