ZeroNet Blogs

Static ZeroNet blogs mirror

BORS©.Blog

Блог PHP-фреймворка и просто разной DevOps всячины

Жена на сайте делает ссылки на разделы в виде картинок. И накладывает на них надписи вручную в графическом редакторе:

2018-12-08_13-37-47.png (0x0)

Сейчас ей, похоже, надоело и она спросила, нельзя ли это как-то автоматизировать :)

Пишет страницы она в Grav'е в разметке Markdown. Понятно, что при этом можно делать вставки на чистом HTML и написать что угодно, но это не спортивно! Мне давно интересно реализовывать что-то расширенное в рамках синтаксиса и идеологии Markdown.

Картинки в Markdown вставляются с таким синтаксисом:

![](http://ссылка)

Или, в неурезанном варианте:

![Alt-текст](http://ссылка)

Ага! Первое же, что приходит в голову, использовать Alt-текст для визуального вывода поверх картинки. Ну и сама картинка может быть произвольного формата, а выводить нужно в фиксированном размере, в нашем случае 250x200px. Укажем всю эту обработку, задав CSS-класс картинки:

![Лабораторные животные](lab-mouse.jpg){.cover}

Транслируется оно в HTML вида:

<img src="lab-mouse.jpg" alt="Лабораторные животные" title="" class="cover">

Оформление

Сперва опишем лимит размера картинки. Делаем её без полей, вписывая и обрезая лишнее в 250x500. Это сегодня совсем просто:

img.cover {
    width: 250px;
    height: 200px;
    object-fit: cover;
}

А вот дальше — сложнее. Вытащить поле alt из img средствами CSS невозможно. Нужно переходить к JavaScript. На том же jQuery поле alt достаётся в одно действие. И, раз мы уже это делаем, то оформим картинку с подписью в рамках современных стандартов. Сегодня это рекомендуется делать примерно так:

<figure>
  <img src="image.jpg" alt="Картинка">
  <figcaption>Заголовок картинки</figcaption>
</figure>

Поехали:

$('img.cover').each(function()
{
    var img=$(this);
    var alt = img.attr('alt');
    img.wrap("<figure class=\"cover\"></figure>");
    img.after("<figcaption>"+alt+"</figcaption>");
});

Готово. Теперь после загрузки страницы текст из поля alt рисуется под картинкой в виде:

<figure class="cover">
    <img src="lab-mouse.jpg" alt="Лабораторные животные" title="" class="cover"> 
    <figcaption>Лабораторные животные</figcaption>
</figure>

Осталось только раскрасить надпись и наложить её поверх картинки:

figure.cover {
    position: relative;
    width: fit-content;
    display: inline-block;
}

figure.cover figcaption {
    position: absolute;
    bottom: 0;
    color: white;
    font-size: 24px;
    padding: 0 4px 4px 4px;
    display: block;
    width: 100%;
    text-align: center;
    text-shadow: 2px 2px 8px rgba(0, 0, 0, 0.9), 0 0 2em rgba(0, 0, 0, 0.7);
    line-height: 1.0;
}

Результат:

​​​​​​​​​​​​​​2018-12-08_14-13-45.jpg (786x215)

YAML to PHP

- Posted in BORS©.Blog by with comments

Обнаружил у себя сегодня ещё один заповедник с YAML-классами :) Переконвертировал…

Поскольку в этот блог давно ничего не писал, и предыстория осталась за кадром, вкратце:

  • Раньше в движке были «YAML-классы». С виду удобная фигня, когда можно было в .yaml кратко описать основные поля и методы. При работе класслоадера такой файл компилировался в кеш и оттуда брался как .php

  • На практике оказалось часто неудобно. Когда это были файлы в 1-2 строчки, то и на PHP описать то же самое в 4-5 строк не обломишься. А вот когда потом это всё требовалось расширять, можно было застрелиться :) Начинались костыли из PHP-вставок в отдельном файле и т.п. Кроме того, класслоадер в Composer стал стандартом и собственный колхоз стал терять смысл.

  • Посему в утилитку bors была добавлена команда yaml2php для конвертации первого во второе и YAML-класслоадер снесён из фреймворка. Кажется, вообще с механизмом своих класслоадеров.

Пример такой миграции: https://bitbucket.org/Balancer/balancer-board-bors/commits/b26cda898ad61c096dbd0994ef3ff252f5489877

По случаю тут вспомнилось. Тесты «мат-фильтра» пришлось сразу пополнить «словами-исключениями». А то, типа, как на известном военном авиафоруме долгое время слово «истребитель» писалось со звёздочккми: «истр*тель». Военная авиация! :D Но со временем стали попадаться более редкие и изысканные обороты, требующие пополнения матфильтра с обоих сторон. «Разрешённые» слова из юнит-теста привожу тут для прикола :)

    static function __unit_test($test)
    {
        // Список нормальных слов с выглядещами обсценно подстроками.
        $allowed = ['ансамбля Джебат дебаты колебания колебать колебаться постебаться дебилов учёба'];
        $allowed[] = 'Усугубляясь истребители застрахуйте рубля Хулиганы потребляет потреблять тихую психуют психующим';
        $allowed[] = 'оскорблять уподобляться Усугубляясь Олеговна плохую лихую употребляющих сухую глухую';
        $allowed[] = 'хребтами Глеб Глеба небу сабля гребля корабля лапидарий скипидар туебень залужью';
        $allowed[] = 'абляция'; // В начале строки!
        $allowed[] = 'аббляционного веба потребляемого стеблями констебля';
        $allowed[] = 'небу ещёб ещеб нёбу хлебом Пиебалгс деблокировать хлебнуло хулит';
        $allowed[] = 'ибупрофен Ибашники';
        $allowed[] = 'хребтом хребтами хребту сердцебиение досудебную колеблется беби мразеблоггерша';
        $allowed[] = 'дирижабля дубля волшебную внеблоковый пищеблоку хребта ассеблеров';
        $allowed[] = 'заштрихуйте Хулиан Хулио потребную Хулимсунт'; // Хулимсунт — посёлок такой.
        $allowed[] = 'хулахуп ибо хулению служебную Себу'; // Себу — провинция на Филиппинах.

// ...

Похоже, нужно возвращаться к идее индивидуальных серверов БД в LXC-контейнерах. С одной стороны, это заметный оверхед по памяти/кешам, из-за которых я и пришёл к идее использования общей БД на хосте для всех контейнеров, с другой стороны, начинается каша при попытке многосторонней репликации баз данных и лишний геморрой при переносе контейнера на другой сервер. Когда всё в локальной БД контейнера, то этот контейнер можно тупо запаковать и перебросить куда надо целиком.

Единственное, над чем надо ещё подумать, делать ли LXC-контейнер полностью автономным или держать два отдельных контейнера для БД и для сайта. Во втором случае получаются лишние сущности, но процесс переноса можно разделить на этапы.

Смотрю тут движки форумов. Вижу на официальном сайте одного из них в новостях вот такое чудо :D

wtf-developers.png (647x258)

Яндекс...

- Posted in BORS©.Blog by with comments

Что-то Яндекс совсем опустился. Вот, к примеру, подобные записи в блоге:

http://www.zites.cf/2016/03/6-new-troubles

Уникальный для Интернета контент. Никаких копипаст. Однако, из поиска выбрасывается: «Недостаточно качественный контент». И такое — сотнями. Ну и какого им ещё нужно, блин?

yandeks-hernya.jpg (300x200)

Возвращаясь к старому спору :)

У меня тут образовался новый и пока пустой сервер на Scaleway. Решил сравнить свежим взглядом и посмотреть, что изменилось с последних моих тестов. Использую всё тот же sysbench, тест complex на 1 млн строк. Три варианта:

  • host через сокет
  • host через 127.0.0.1
  • docker с мапингом на 127.0.0.1

Условия:

  • Конфиги идентичны (оптимизированы)
  • MariaDB-10.2.7. На хосте — Ubuntu xenial, в Docker — официальный образ на jessie.
  • Сам каталог базы контейнера смонтирован в хост
  • Параметры docker по умолчанию, запуск через docker-compose

Результат, итоговый, минимальные значения из небольшой серии.

Тип transactions/30s min time avg time 95 percentile
сокет 39506 3.1мс 6.2мс 9.6мс
127.0.0.1 32856 3.9мс 7.3мс 10.9мс
docker 17622 6.4мс 13.6мс 20.4мс

В общем, если без хитростей, то docker по-прежнему вдвое медленнее. Если с хитростями, то я пока не знаю, куда копать :)

WTF-Code

- Posted in BORS©.Blog by with comments

Кидал тут в группу в Telegram примеры WTF-кода, которые встречал в своей практике. Решил и тут поделиться :)

Миграции БД

- Posted in BORS©.Blog by with comments

Уже писал ранее в одном из блогов (когда же я их объединю? :) ) о проблеме выбора места для хранения миграций composer-пакетов. Пока у нас один только набор миграций для приложения, проблемы нет. Когда же надо поддерживать отдельно пакеты composer, то нельзя их миграции хранить в общей базе. Они могут обновляться независимо! Значит, или по отдельной таблицей на каждый пакет в общем базе в MySQL (как правило) или, чтобы не засорять базу, по отдельному файлу sqlite для каждого пакета в composer/data. Склонялся ко второму варианту, но (отчасти из-за лени) реализовывал первый. Это меня и спасло, когда пришлось при отладке постоянно перегружать старые дампы сторонней БД. Если бы история миграций хранилась отдельно, в локальном sqlite, был бы облом из-за несоответствия БД и истории миграций. А тут, поскольку и история и БД хранятся вместе и консистентны, просто делаем phinx migrate после каждой загрузки дампа. И всё прекрасно обновляется.

Так что отныне — всегда отдельная таблица для отдельного пакета!

Я много лет использовал PEAR Image_GraphViz и не знал бед. Но теперь этот пакет устарел, не поддерживается, его нет в Composer и так далее. Вчера потребовалось по-быстрому вывести на PHP пару диаграмм из БД. Решил сделать современно/модно/молодёжно. Полез в libraries.io, отсортировал по популярности пакеты Composer с подстрокой Graphviz и... Завис. Есть монолитные пакеты, генерирующие готовые изображения, но с очень куцыми функциями, не реализующими многое из возможностей GraphViz. Есть в большом ассортименте более гибкие пакеты, создающие GraphViz-скрипты (для dot), но нет средств рендерить их. Два часа угрохал, но так ничего штатными средствами и не добился. Плюнул, быстро слепил костыль с прямой генерацией строками скрипта и вызов dot через exec, сделав задачу за 10 минут. А с библиотеками придётся разбираться позже :-/