jqModal – модальные окна и jQuery

Опубликовано в рубрике Анонсы 2007.11.21 korchasa – 3 комментов

Потребовалось найти гибкое решение, для рисования модальных окон. Один из критериев – библиотека должна быть основана на jQuery, ибо она уже используется в системе. Damn! :( .

ThickBox не устроил своей жесткостью, ибо рысканье по коду обнаружило нехватку настроек, а именно, невозможность навесить свой callback для AJAX-запросов.

Поискал немного, и наткнулся на jqModal, маленький и гибкый. Его хоть ковырять проще, ибо меньше он.

Меньше кода ?== больше ям

Опубликовано в рубрике Статьи 2007.11.15 korchasa – Комментариев пока нет

Вроде бы все всё знают, но почему не все всё используют? Меньше кода, хорошего и разного? Или читаемость все таки теряется?

1. Присвоение в сравнениях

Больше:

$id = $request->getId();
if(!$id) {
 return false;
}

Меньше:

if(!$id = $request->getId()) {
 return false;
}

Немного снижает читаемость кода. Если переменная используется за пределами ветвления (после него), то применять такой подход не стоит.

2. Тернарный оператор, вместо if

Больше:

if($id) {
 return $id;
} else {
 return false;
}

Меньше:

return ($id) ? $id : false;

Читаемость нисколько не снижается. ИМХО их и объединять можно:

$a = ($a) ? a : ($b) ? $b : 'default';

3. “Вытаскивание” элементов массива в текущий контекст

Больше:

function resolveArray($params) {
 if(array_key_exists('foo', $params)) {
   return $params['bar'];
 }
}

Меньше:

function resolveArray2($params) {
 extract($params);
 if(isset($foo)) {
   return $bar;
 }
}

или

function resolveArray3($params) {
 list($foo, $bar) = $params;
 if(isset($foo)) {
   return $bar;
 }
}

Использование extract – несколько порочная практика, ибо непонятно откуда переменные берутся. Использование list’а в этом плане лучше, но он завязан на порядок следования элементов…гад.

Поэтому в больших методах лучше все таки вытаскивать “ручками”:

function resolveSomeArrayInformation3($params) {
 $foo = array_key_exists('foo', $params) ? $params['foo'] : false;
 $bar = array_key_exists('bar', $params) ? $params['bar'] : false;
 if(isset($foo)) {
   return $bar;
 }
}

, ибо можно нормальные значения по умолчанию задавать и наглядность не теряется. А если писать влом, то используйте возможности вашей IDE (она же позволяет использовать шаблоны, правда?).

4. Инициализация в объявлении цикла

Больше:

$count = count($array);
for($i = 0; $i < $count; $i++) {}

Меньше:

for($i = 0, $count = count($array); $i < $count; $i++) {}

Вполне нормально для меня, для остальных, говорят, не очень.

5. Операции в объявлении цикла

Больше:

for($i = 0; $i < 10; $i++) {
 $str .= $i;
}

Меньше:

for($i = 0; $i < 10; $str .= $i++);

Тоже самое, что и в предыдущем.

6. Простое позиционирование в строке

Больше:

$current_letter = substr($str, $i, 1);

Меньше:

$current_letter = $str{$i};

Читаемость лучше, однозначно стоит применять.

И так далее...

Функциональное тестирование (FunctionalTesting) и Web

Опубликовано в рубрике Статьи 2007.10.15 korchasa – Комментариев пока нет

Функциональное тестирование – процесс, в ходе которого, готовая программа проверяется на соответствие требованиям того на чьи деньги мы пьем кофе. Главная задача функционального тестирования – говорить, либо “странно, но ты ничего не сломал”, либо “я так и знал, теперь чини”.

Функциональное тестирование называют также тестированием “черного ящика”, то есть тесты, в идеале, не должны ничего знать про тестируемую систему. Это позволит менять разработчиков архитектуру, язык приложения, базу данных.

Что тестировать?

Функциональное тестирование для web-сайтов подразумевает эмуляцию работы конечного пользователя: открытие страниц, переход по ссылкам, заполнение и отправка форм, проверка значений полей форм, наличие определённого текста на страницах, получение почты, отправку файлов, а также попытки взлома, и кривизну рук.

Например, есть форма регистрации. Для каждого из заполняемых полей мы должны проверить все граничные условия, даже самые извращённые. В итоге получается по 2-3 проверки на поле.

  • email (заполнен, соответствует паттерну, уникален на сайте)
  • пароль (заполнен, не содержит “нехороших” символов)
  • подтверждение пароля (заполнен, соответствует паролю)
  • псевдоним (заполнен, не содержит “нехороших” символов, уникален на сайте)

После этого мы должны проверить, что нам пришло “правильное” письмо, не пришло неправильных.

Из за использования метода addRecipient(), вместо setRecipient(), у класса PHPMailer, мы однажды разослали 15 000 писем нашим пользователям. По 50-70 штук на каждую невинную жертву. Если бы тест проверял наличие лишних писем, то все бы было хорошо, а так – по башке получили. Хорошо хоть в спам-лист не попали.

Часто функциональное тестирование выполняется специально натренированным человеком со стойкой психикой и любовью к механической работе. Его вооружают листочком с описанием теста и ограждают от окружающего мира, так как не понятно, как он отнесётся к программисту, из-за ошибки которого, ему пришлось опять полностью обходить весь сайт. Ошибаться этот тестер не должен, так как если ошибка пройдет в релиз, ее увидят все, и время ее исправления будет зависеть от ее близости к основным пользовательским “маршрутам”. Такой подход с легкой руки сослуживца получил название wiki-тестирование.

Чем тестировать?

Есть два больших лагеря продуктов для функционального тестирования:

  • Эмуляторы браузера, написанные на языке высокого уровня: httpUnit, JWebUnit, WebTester из SimpleTest
  • Продукты использующие API браузера (например через JavaScript), и и управляющие его поведением: Watir и Selenium

Первые немного ущербны даже идеологически, так как браузер это неотъемлемая часть веб-приложений. То есть то, что тесты проходят, совершенно не гарантирует, что приложение будет работать у конечных пользователей. Но их высокая скорость позволяет использовать их для простых задач, типа определения “битых” ссылок.

Среди вторых хочется отметить Selenium, который уже стал стандартом де факто, для автоматизации функционального тестирования веб-приложений, ибо:

  • для описания тестов используется HTML
  • поддерживаются все популярные браузеры
  • распространяется под лицензией Apache 2
  • начинался проект под патронажем ThoughtWorks, владельцем которой является, некто, Мартин Фаулер

Продолжение следует…

Враг не пройдет. Как остановить спам боты.

Опубликовано в рубрике Статьи 2007.06.06 korchasa – 7 комментов

То ли мне спам-боты надоели, толи просто решил сделать что-то большое и чистое. В итоге размышлений родились мысли. Первая, о том, что хочется есть, а вторая, что думать надо усердней. Стал думать усердней, и набросал несколько вариантов защиты:

Защита от ботов, ориентированных на CMS, и названия полей

Тут все относительно просто. Достаточно выделиться из серой массы, и количество ботов снижается почти до нуля. Пример: на странице регистрации можно присваивать id-шникам input’ов случайные значения, подписи к ним выводить с помощью JavaScript, и между некоторыми вставлять поддельные input’ы. Дополнительно можно проверять время заполнения формы, и нажатие клавиш.

Защита от ботов, которых пишут “под вас”

Вот несколько способов пришедших на ум.

Различение формы предметов, и их цвета

Найти на картинке, покрытой мелкими треугольниками, овалами, и прочими линиями квадрат, и указать его цвет.

Плюсы:
  • простота реализации
  • простота прохождения людьми
Минусы:
  • узкий словарь (основных цветов и форм мало, чтобы предотвратить брутфорс)
Разбор сложных образов

Указать пол человека, изображенного на фотографии.

Плюсы:
  • вряд ли боты в скором времени станут такими умными
  • простота реализации самого механизма выбора
Минусы:
  • тяжело составить такой словарь

Если придумаете, то, пожалуйста, скажите мне . Только гугловский поиск по медиа-контенту не предлагайте, так как он не очень релевантный.

Конструирование сложных образов из кусков

Собирание пазла.

Плюсы:
  • очень широкий словарь (результатом конструирования может быть что угодно).
  • тяжесть брутфорса (6 кусков – 720 вариантов)
  • возможность увеличить защиту от брутфорса, если пересылать изменения (куда какой кусок положили) на каждом шаге, а не результат
Минусы:
  • пока не придумал ничего, кроме необходимости реализации самого механизма конструирования

Заключение:

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

Перегрузка методов и свойств в PHP

Опубликовано в рубрике Тесты 2007.05.17 korchasa – Комментариев пока нет

Задача: Проверить насколько перегруженные методы и свойства медленнее явных.

Публичные методы

Набросаем небольшой класс:

class Classic {
  public $fooProp;
  public $barProp;

  public function getFooProp() {
      return $this->fooProp;
  }

  public function setFooProp($foo) {
      $this->fooProp = $foo;
  }

  public function getBarProp() {
      return $this->barProp;
  }

  public function setBarProp($bar) {
      $this->barProp = $bar;
  }
}

Проведем тест на скорость выполнения публичных методов. Исходя из

$iterations = 10000;
echo '

Доступ через прописанные сеттеры/геттеры  - ';
$time_start = microtime(1);
for ($i=0; $i < $iterations; $i++) {
  $obj = new Classic();
  $obj->setFooProp($i);
  $tmp = $obj->getBarProp();
  $tmp = $obj->getFooProp();
  $tmp = $obj->getBarProp();
  $tmp = $obj->getFooProp();
  $tmp = $obj->getBarProp();
  $tmp = $obj->getFooProp();
  $tmp = $obj->getBarProp();
  $tmp = $obj->getFooProp();
  $tmp = $obj->getBarProp();
}
$times = round($iterations / (microtime(1) - $time_start));
echo $times . ' в секунду

';

Результаты тестов на 10000 итераций:

Доступ через прописанные сеттеры/геттеры - 136552 в секунду

Перегрузка обращений к свойствам объекта (__set, __get)

Класс Overloaded реализует функционал класса Classic, с помощью перегрузки методов(__call) и доступа к свойствам(__set, __get):

Overloaded {
  protected $fields = array(
  'fooProp' => false,
  'barProp' => false
  );

  protected function _generateNoPropertyException($prop) {
      throw new Exception('Undefined property ' . $prop);
  }

  public function __get($name) {
      if(isset($this->fields[$name])) {
          return $this->fields[$name];
      } else {
          $this->_generateNoPropertyException($name);
      }
  }

  public function __set($name,$value) {
      if (isset($this->fields[$name])) {
          $this->fields[$name] = $value;
      } else {
          $this->_generateNoPropertyException($name);
      }
  }

  public function getBarProp() {
      return $this->fields['barProp'];
  }

  protected function __call($mthd, $args = array()) {
      $type = substr($mthd, 0, 3);
      if('get' == $type) {
          return $this->__set(strtolower(substr($mthd, 3, 1)).substr($mthd, 4),$args);
      } elseif('set' == $type) {
          return $this->__get(strtolower(substr($mthd, 3, 1)).substr($mthd, 4));
      }
      throw new Exception("No such method '$mthd' in " . get_class($this));
  }
}

Протестируем:

echo '

Доступ через перегруженные сеттеры/геттеры  - ';
$time_start = microtime(1);
for ($i=0; $i < $iterations; $i++) {
  $obj = new Overloaded();
  $obj->fooProp = $i;
  $tmp = $obj->barProp;
  $tmp = $obj->fooProp;
  $tmp = $obj->barProp;
  $tmp = $obj->fooProp;
  $tmp = $obj->barProp;
  $tmp = $obj->fooProp;
  $tmp = $obj->barProp;
  $tmp = $obj->fooProp;
  $tmp = $obj->barProp;
}
$times = round($iterations / (microtime(1) - $time_start));
echo $times . ' в секунду

';

Получаем результат:

Доступ через перегруженные сеттеры/геттеры - 56004 в секунду

Перегрузка методов (__call)

Тестировать будем на нашем классе Overloaded:
echo

Доступ через эмулированные сеттеры/геттеры – ‘

;
$time_start = microtime(1);
for (
$i=0; $i < $iterations; $i++) {
$obj = new Overloaded();
$obj->setFooProp($i);
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
}
$times = round($iterations / (microtime(1) – $time_start));
echo
$times . ‘ в секунду’;

highlight_file(__FILE__);
Результат:

Доступ через эмулированные сеттеры/геттеры - 27468 в секунду

Выводы

Вот результаты всех трех тестов:

Доступ через прописанные сеттеры/геттеры - 136552 в секунду
Доступ через перегруженные сеттеры/геттеры - 56004 в секунду
Доступ через эмулированные сеттеры/геттеры - 27468 в секунду

На диаграмме это выглядит следующим образом:

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

Исходники полного теста: setget.php (3,2 Кб)