Разработка, HowTo

Часть 7: PHPUnit (Тестирование ПО)

php-unit-logo-bigОглавление

Продолжаем цикл статей по разработке веб-приложений с использованием методологии TDD.

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

В предыдущей части мы попытались создать собственный минималистичный код, который осуществляет тестирование проекта. Если продолжать и дальше, то в конечном счете можно довести имеющиеся наработки до вида, годного для использования в маленьких или не очень проектах. Но так делать не стоит ибо современная индустрия разработки требует высокой скорости создания продуктов и высокого их качества. Тратить усилия на поддержание уже не раз придуманного и реализованного, но своего — это не совсем хорошая идея. Поэтому в этой главе мы познакомимся с PHPUnit и научимся правильно его применять вместе с yii.

Читать далее

Разработка, HowTo

Часть 6: Самописный тестовый фреймворк (Тестирование ПО)

00-introОглавление

Продолжаем цикл статей Тестирование ПО в котором рассказывается о разработке программного обеспечения с применением методологии TDD.

Прежде всего, равно как и в одной из предыдущих лекции, нам надо разобраться как тесты работают изнутри. И только лишь после этого мы сможем их успешно применять.

Читать далее

Разработка, HowTo

Часть 5: Подготовка базы данных, миграции (Тестирование ПО)

00-titleОглавление

Перед вами очередная часть цикла Тестирование ПО. В предыдущей части мы развернули инфраструктуру для работы с проектом на базе Yii2-advanced-template. В этой части мы разберемся как работать с базой данных и что такое миграции.

Читать далее

Разработка, HowTo

Часть 4: Подготовка окружение (vagrant + PuPHPet) (Тестирование ПО)

Снимок экрана от 2017-05-02 16-36-41Оглавление

Это очередная часть проекта Тестирование ПО который рассказывает о разработке веб-приложений с использованием методологии TDD. Конкретно  в этой главе мы развернем рабочее окружение и создадим шаблон проекта для последующей разработки.

Для создания окружения многие используют для этого ту же машину на которой и пишут код. Нельзя однозначно сказать, хорошо это или плохо. В нашем случае это плохо. Поскольку рабочая система засоряется пакетами и приложениями, которые нужны лишь на один раз. Плюс к этому нельзя взять окружение, удалить его и начать заново если что-то не понравилось или из-за игры с настройками все пошло не так. И конечно же, не стоит забывать разработчиков, которые пользуются отличными от *nix операционными системами, так как многие из дальнейших операций будут им попросту либо недоступны, либо доступны со множеством ограничений.

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

Читать далее

Разработка, HowTo

PHP: дело о загадачном пробеле

%d0%b2%d1%8b%d0%b4%d0%b5%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5_103Или история о том, как побились картинки.

Однажды от пользователей пришла жалоба, что новые картинки, которые они на проект грузят не отображаются. Только если полностью обновить страницу.

Проверил данные в кеше — картинки были. Все как положено — пережатые и с водяными знаками. После ряда танце с бубном удалось выяснить, что скрипт, который картинку генерирует пока ее в кеше нет отдает пробел в каждой картинке — на скриншоте это хорошо выдно. Идет пробел, а после стандартный заголовок jpeg.

Чтож. Очень вероятно, что какой-то вредный скрипт оказался с пробелом. Мы же помним вро стандартные открывающиеся и закрывающиеся теги php, которые принесли много головной боли.

Но как среди тысяч строк кода выяснить, где начинается вывод злобного пробела?

  1. отключить вывод самой картинки и убедится, что пробел все еще выводится.
  2. отключить буферизацию вывода на стороне сервера — убедится, что пробел есть
  3. в самом конце скрипта поставить setcookie или header — в логах пояится сообщение вида «Warning: Cannot modify header information — headers already sent by (output started at file.php:XXX)». Где file.php — это соответсвенно файл, а XXX — номер строки, где начался вывод.

Чтобы отключить буферизацию нужно прописать в конфигах php.ini

output_buffering=0

Или в конфигах апача или htaccess

php_flag "output_buffering" Off
HowTo, linux

OpenWRT: блокировка рекламы

1280px-openwrt_logo-svgЕсть отличная прошивка на базе всеми любимого линупса для всякой разной техники вроде роутеров и микрокомпьютеров — это OpenWRT.

А поскольку эта штука работает в качестве локального днс-сервера, то грех не научить ее блокировать на корню всякие даблклик.нет и другое непотребство.

Рассматривать будем ситуацию при которой у нас установлена дефолтная конфигурация c dnsmasq.

Сначала нам потребуется поставить пакет dnsmasq-full взамен стандартного (он чуть больше по объему и тянет больше зависимостей, и предоставляет больше возможностей по настройке).

# opkg update
# opkg remove dnsmasq
# opkg install dnsmasq-full
# /etc/init.d/dnsmasq restart

Посмотрим на файл /tmp/etc/dnsmasq.conf. Нас будут интересовать следующие два параметра.

addn-hosts=/tmp/hosts
conf-dir=/tmp/dnsmasq.d

Буквально это значит, что дополнительные файлы в формате /etc/hosts хранятся в /tmp/hosts, а дополнительные конфиги — в /tmp/dnsmasq.d.

Теперь нам потребуется скрипт, который будет скачивать листы. Поместим его в /root/bin/adblock.sh

#!/bin/sh
echo "download adblock rules"

if [ ! -d /tmp/dnsmasq.d ]; then
 mkdir /tmp/dnsmasq.d
fi

if [ ! -d /tmp/hosts ]; then
 mkdir /tmp/hosts
fi

touch /tmp/dnsmasq.d/adblock.conf

wget -O /tmp/dnsmasq.d/adblock.conf "http://pgl.yoyo.org/adservers/serverlist.php?hostformat=dnsmasq&showintro=0&mimetype=plaintext"

echo "" > /tmp/hosts/adblock

wget -O /tmp/adblock https://hosts-file.net/ad_servers.txt
sed 's/^\(.*\).$/\1/' /tmp/adblock >> /tmp/hosts/adblock
wget -O /tmp/adblock https://adaway.org/hosts.txt
sed 's/^\(.*\).$/\1/' /tmp/adblock >> /tmp/hosts/adblock
wget -O /tmp/adblock http://winhelp2002.mvps.org/hosts.txt
sed 's/^\(.*\).$/\1/' /tmp/adblock >> /tmp/hosts/adblock

if [ -f /tmp/adblock ]; then
 rm /tmp/adblock
fi

/etc/init.d/dnsmasq enabled && /etc/init.d/dnsmasq restart

Первым мы скачиваем файл с блокировками в формате dnsmasq, а последующие запросы — это блокировки в формате hosts. Соответственно раскладываем их по разным папкам и рестартим сервис.

Не забываем поставить +x на файл.

Теперь нужно добавить этот скрипт в крон дабы он обновлялся.

 # crontab -e

и пишем туда что-то вроде

* */12 * * *  /bin/sh /root/bin/adblock.sh

Это означает, что раз в 12 часов списки будут обновляться.

Естественно, что надо включить крон. По дефолту он выключен.

# /etc/init.d/cron enable
# /etc/init.d/cron enabled && /etc/init.d/cron start

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

А для этого нам потребуется создать файл /etc/hotplug.d/iface/50-adblock примерно следующего вида.

#!/bin/sh
[ ifup = "$ACTION" -a "$DEVICE" = eth1 ] && {
	/bin/sh /root/bin/update_adblock.sh
}

Где eth1 — это ваш wan-интерфейс.

Все. Можно перезагрузить роутер для проверки что все настроено корректно.

Рекламные домены вроде doubleclick.de должны резолвиться либо на 0.0.0.0, либо на 127.0.0.1.

$ nslookup  doubleclick.de
Server:		192.168.0.1
Address:	192.168.0.1#53

Name:	doubleclick.de
Address: 127.0.0.1

Чтобы точно убедиться, что все работает как надо — проверяйте что сразу после поднятия wan появились файлы /tmp/dnsmasq.d/adblock.conf и /tmp/hosts/adblock.

Учтите, что в сумме размер списков блокировки составит более 100 тысяч записей. И если роутер слабоват, то придется какой-то из списков отключать.

И да — это не панацея. Это просто хороший способ обезопасить электронные читалки, телефоны и разную мелкую технику, которая ходит в инет от баннеров и прочего добра.

Источники:

Разработка, HowTo

PHP: array_map и ключи массива

Интересно, почему такой вопрос часто всплывает на форумах или где-то еще?

Сначала постараюсь ответить на вопрос «нафига?», а потом на вопрос «как?».

Мы привыкли, что в в питоне, js и множестве других языков и фреймворков есть функция map, которая применяет некоторую функцию-обработчик к каждому элементу в списке данных и возвращающую результат в том же порядке. Пруф.

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

Этот постыдный момент из жизни структуры привел к тому, что одним из самых частых применений массивов (в пхп конечно же) стало создание отображений категория=>какое-то значение.

А после того как у вас появилось отображение вы, вероятно, захотите это где-нибудь на сгенерированной странице отобразить.

Т.е. показать пользователю сам параметр, а скобках его категорию.

Как мы делаем это в языках (фреймворках), которые разделяют понятие массива и хеш-таблицы? Перебираем объект, который содержит категории и формируем по нему массив выводимых данных. Наверное так.

И тут мы открываем руководство по php и видим, что она применяет некий колбек ко всем элементам массива и после этого возвращает новый массив.

Удобно же! Применили колбек к массиву и получили обработанный.

$array = [
  'category1' => 'first category',
  'category2' => 'second category',
];

var_dump(array_map(function(....

И что-то не заладилось. 🙂 Ключи в колбек не попадают. Можно сделать все через foreach, но тогда нам потребуется еще одна переменная. А тут все было просто и наглядно.

И мы идем в гугель: «php array_map with keys».

А зачем гуглить-то?

$array = [
  'category1' => 'first category',
  'category2' => 'second category',
];

var_dump(array_map(function($key, $value) {
  return "{$key} => {$value}";
}, array_keys($array), $array));

И все отлично работает. И притом правильно. Относительно конечно же. И никаких вам лишних переменных.

А тем временем в коде вновь и вновь появляются конструкции вида

$array = [
  'category1' => 'first category',
  'category2' => 'second category',
];

$description = [];

foreach ($array as $key => $value) {
  $description[] = "{$key} => {$value}";
}

Или еще хуже.

$array = [
  'category1' => 'first category',
  'category2' => 'second category',
];

$description = [];

array_walk($array, function($value, $key) {
  $description[] = "{$key} => {$value}";
});

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

Вариант же с array_walk на понятность никак не претендует (как и решение подобной задачи при помощи .each в jquery).