Обновить
64K+

PHP *

Скриптовый язык общего назначения

64,01
Рейтинг
Сначала показывать
Порог рейтинга

Как я устал от бардака в «Избранном» Telegram и за два вечера запилил бесплатную интерактивную доску (без регистраций и СМС)

Всем привет!

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

Думаю, у многих из вас Telegram давно превратился в помойку из сотен каналов. Полезные статьи, гайды, рецепты, мемы, рабочие задачи — всё это мы обычно скидываем в «Избранное» (Saved Messages). И что происходит дальше? Правильно, «Избранное» превращается в черную дыру. Найти там что-то через неделю — это квест уровня «Индиана Джонс».

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

Мне это надоело. Я хотел простой инструмент: нашел на смартфоне -> скинул боту -> открыл на компе в виде красивых карточек. Посмотрел готовые сервисы — везде просят регистрацию, привязку карт, вылезает реклама или ограничения на 10 постов.

В итоге я психанул, выделил два вечера и написал свой костыль, который неожиданно превратился в отличный инструмент — TG-drop.ru.

Как я это устроил (без заумной архитектуры)

Система работает на связке «бот + база данных + веб-интерфейс». Всё гениальное просто:

  1. Вы листаете Telegram на телефоне и видите важный пост (гайд, чек-лист, статью).

  2. Пересылаете его моему боту. Бот мгновенно подхватывает его и сохраняет в изолированную таблицу.

  3. Вечером вы садитесь за ПК, открываете сайт, вводите свой Telegram ID (он нужен только как ключ, чтобы сайт понял, чьи посты показать) — и перед вами удобная интерактивная доска.

Почему это удобнее, чем просто Telegram?

Я делал проект для себя, поэтому сразу вырезал всё, что меня бесит в современном вебе:

  • Никаких регистраций вообще. Никаких вводов почты, подтверждений по SMS и придумывания паролей «с одной заглавной буквой и спецсимволом». Ввел ID — работаешь.

  • Живой поиск и фильтры. Когда постов становится много, вы можете искать по ключевым словам прямо в браузере. Всё фильтруется на лету, без перезагрузки страниц.

  • Личные заметки прямо на карточках. Можно дописать к посту дедлайн, свои мысли или вычеркнуть выполненные пункты. Текст сохраняется автоматически, как только вы убираете курсор из поля.

  • Конфиденциальность. Ваши посты подгружаются динамически. Никто другой вашу доску не увидит.

Кому это пригодится?

Изначально я думал о ребятах из крипты (охотники за Airdrop, тестнеты, DeFi-инвесторы), которым нужно по пунктам выполнять сложные активности с ПК, найдя их в мобильном телефоне.

Но в процессе понял, что штука закроет боли многих:

  • Контент-мейкеров и исследователей: собирать выжимки, инсайты и референсы в одном месте.

  • Студентов: скидывать материалы для курсовых и дипломов, чтобы потом структурировать на десктопе.

  • Да и вообще всех, кто использует Telegram как базу знаний и устал от хаоса в «Избранном».

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

Буду рад здоровой критике в комментариях! Чего вам не хватает в таком функционале? Что стоит добавить в первую очередь?

Теги:
+3
Комментарии13

Как связать контейнеры Nginx и PHP в Docker Compose, чтобы Nginx мог проксировать запросы?

Допустим, вы пытаетесь развернуть связку из веб-сервера и PHP. Контейнеры поднимаются, но веб-сервер выдает ошибку сети и не может достучаться до PHP-бэкенда. Разберемся, что нужно прописать в конфиге Nginx, чтобы они увидели друг друга.

Чаще всего подобная проблема возникает из-за того, что контейнеры изолированы друг от друга на сетевом уровне, либо в конфигурационном файле веб-сервера некорректно указан адрес целевого хоста. В экосистеме Docker Compose встроенный DNS-сервер автоматически сопоставляет имена сервисов с их внутренними IP-адресами. Поэтому не нужно прописывать статические IP — достаточно правильно использовать имена, заданные в манифесте. 

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

Чтобы Nginx мог передавать запросы PHP-FPM, необходимо:

  • убедиться, что оба контейнера находятся в одной сети (app_network),

  • указать в конфигурации Nginx правильный адрес PHP-контейнера (в нашем примере это php:9000, где php — имя сервиса в docker-compose.yml).

Шаг 1: Проверка манифеста docker-compose.yml

Убедитесь, что для обоих сервисов явно выделена одна общая сеть. Пример корректной структуры:

version: '3.8'
services:
  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/html:/var/www/html
    depends_on:
      - php
    networks:
      - app_network

  php:
    image: php:8.2-fpm
    container_name: php
    volumes:
      - ./php:/var/www/html
    networks:
      - app_network

networks:
  app_network:
    driver: bridge

Шаг 2: Настройка конфигурации Nginx

В блоке location, отвечающем за обработку PHP-скриптов, в директиве fastcgi_pass вместо 127.0.0.1 или localhost необходимо подставить имя сервиса PHP из файла конфигурации:

server {
    listen 80;
    server_name localhost;

    root /var/www/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass php:9000;  # Связь с PHP-контейнером
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Директива depends_on в блоке Nginx гарантирует, что веб-сервер не начнет стартовать раньше, чем поднимется контейнер с PHP. Это предотвратит падение Nginx при первичном запуске окружения, если он не сможет сразу разрешить DNS-имя php.

Если вы хотите глубже разобраться в сетевых механизмах, управлении volumes и оркестрации контейнеров, читайте наш полный материал: Docker Compose и основы работы с контейнерами.

Теги:
+11
Комментарии0

Фронтенд для души, бэкенд для людей!

Мастер по разводу холивар
Мастер по разводу холивар

Были приняты меры погрузиться под воду дабы показать серьезность моих намерений в данной щепетильной теме.

Фронтенд весь такой разносторонний, креативный, местами легкий, местами настолько сложный что ломаешь голову. Напрашивается клеймо "для любителей".

Бэкенд наоборот поддерживает порядок и структурность. Меньше экспериментов и больше проверенных решений, самое то для "сделал работу - пошел спокойно домой".

Теги:
+2
Комментарии1

Большинство объяснений машинного обучения начинаются с нейронов, весов или градиентного спуска. Но есть одна деталь, без которой вся эта конструкция вообще не работает.

Откуда модель вообще узнаёт, что ошиблась? Именно с этого, как мне кажется, и стоит начинать изучение машинного обучения. В новой части книги я попытался объяснить это максимально просто и без фраз вроде "нейросеть сама обучается". Разбираем, что такое ошибка, почему она превращается в loss-функцию, зачем вообще нужны MSE и Log Loss, и как несколько строк математики становятся тем самым сигналом, который заставляет модель становиться лучше. Loss-функции являются центральным механизмом обучения современных моделей машинного обучения.

Если давно хотели понять, что происходит "под капотом" современных AI-моделей – буду рад, если почитаете.

📖 https://apphp.gitbook.io/ai-dlya-php-razrabotchikov-intuitivno-i-na-praktike/chast-ii.-obuchenie-kak-optimizaciya/2.1-oshibka-loss-funkcii-i-zachem-oni-nuzhny

Теги:
+4
Комментарии0

За свою карьеру я успел попробовать Java, Python и ещё кучу всяких языков.

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

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

В общем, в какой-то момент эта мысль показалась настолько забавной, что я решил сделать небольшую музыкальную пародию на известную песню (старый хит 70х) – только про PHP и разработчиков, которые "ушли, но вернулись".

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

🎬 Видео: https://youtu.be/SoqAP4gSDac

Звучит знакомо?

Теги:
+9
Комментарии2

WT Max v.0.2.0. - библиотека для интеграции с Joomla

Обновление Joomla-библиотеки для API мессенджера MAX с системным плагином для настроек и диагностики подключения. Библиотека предназначена для разработчиков.

Расширение является Joomla-обёрткой над самостоятельным PHP Composer-пакетом Webtolk\Max, у которого так же состоялся релиз 0.2.0. PHP SDK разрабатывалось с учётом стандартов PSR и полностью не зависит от какого-либо фреймворка и/или пакета.

v.0.2.0. Что нового?

  • Подключена новая версия API-хоста: platform-api2.max.ru. Для корректной работы ваших чат-ботов и мини-приложений до 19 июля 2026 необходимо перенаправить HTTP-запросы с домена platform-api.max.ru на platform-api2.max.ru, а также добавить сертификат Минцифры в список доверенных. Как это сделать - ссылка на инструкция внизу поста. ‼️Если этого не сделать - вы получите уведомление об ошибке соединения и неверном сертификате.

  • Расширена публичная API-поверхность. Обновлены и дополнены методы для работы с чатами и сообщениями (включая новые сценарии по ссылкам на чат и выборке по query-id сообщения). Удалены устаревшие методы.

  • Обновлён набор публичных JSON-схем. Добавлены и синхронизированы схемы для новых и изменённых endpoint-ов. Эти схемы - снимки реальных ответов API Max, так как мы прекрасно знаем, что документация и реальное API может отличаться порой очень и очень значительно.

  • Обновление документации. README, стартовые руководства, референсы и описания сущностей/пэйлоадов приведены к текущему API-уровню.

Ссылки:

Теги:
+3
Комментарии0

Прямая Web3-монетизация без посредников (Peer-to-Peer) для артистов на радио.

Буквально вчера закончил написание сервисного бота для коммерческих нужд в мессенджере "Concord". Основной целью проекта является автоматизация процессов публикации авторского материала на интернет-радио. Бот был создан как помощник для авторов аудиоконтента: музыкантов, продюсеров, подкастеров и т. п.

Задача была непростой. Нужно было объединить возможности мессенджера с его токеномикой и реализовать передачу медиаконтента (картинок, аудиофайлов, текстовых данных) на удаленный сервер в формате JSON. Для этого я написал серверную страницу на PHP, в которой реализовал весь необходимый API.

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

function isJpeg(string $data): bool
{
    return substr($data,0,2) === "\xFF\xD8";
}

function isMp3(string $data): bool
{
    if (substr($data,0,3)==="ID3") {
        return true;
    }

    return isset($data[1])
        &&
        ord($data[0])===0xFF
        &&
        (ord($data[1]) & 0xE0)===0xE0;
}

После получения данных нужно сразу определить что именно пришло - команда или файл:

if (preg_match('/^\/(help|bio|title|tracks|done)\b/i', $data))
{
    processCommand($db, $uuid, $data);
    exit;
}

if (isBase64($data))
{
    saveBinary($db, $uuid, $data);
    exit;
}

reply("Unknown command, please use /help.", false);

Описание профиля артиста и названия его треков передаются в текстовом виде используя специальный набор команд:

  • /help - Show this help

  • /bio text - Update artist biography

  • /tracks - Show info of all tracks

  • /title text - Update current track title

  • /pay amount - Pay for service

  • /done - Finalize current track

  • Send JPG image to update artist image

  • Send MP3 audio to update current track

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

  1. артист отправляет фото профиля

  2. артист отправляет описание профиля

  3. артист загружает трек

  4. артист отправляет описание трека

  5. артист выполняет оплату сервиса

  6. артист финализирует трек

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

МОНЕТИЗАЦИЯ

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

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

схема работы блокчейна
схема работы блокчейна

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

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

Если у вас появятся предложения, буду рад подискуссировать.

Теги:
Всего голосов 6: ↑2 и ↓40
Комментарии6

Облачный сервис с безграничными возможностями: Бот или не бот - вот в чем вопрос.

Друзьям и коллегам, привет!

Недавно опубликовал на Хабр новую статью с разбором моего Web3-мессенджера. В ней описал личный кейс: как внедрить децентрализованные Web3 технологии и монетизировать внутренние функции приложения без подключения классических платежных систем. Почитать можно здесь: https://habr.com/ru/articles/1052088/

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

Создав так называемых "юзер-ботов" (user-bots), я снабдил платформу дополнительными функциями. В моей реализации такой "Бот" - это полноценный внешний сервис, который имеет точку входа - Endpoint на стороннем облаке и строгий протокол взаимодействия через его API.

В таких популярных приложениях как Telegram или WhatsApp, боты представляют собой отдельные сущности, которые привязываются к основному аккаунту пользователя. Кстати, вопреки расхожему мнению, один аккаунт в Telegram может создать через BotFather не безграничное число ботов, а строго до 20 штук (до 40 для Premium-пользователей).

В своей архитектуре я пошел совершенно другим путем. В моей схеме "Бот" по своей сути - это тот же самый пользователь, только виртуальный. Такой подход позволяет в любой момент переключить обычного юзера в бота и наоборот одним кликом.

пример бота реализующего сервис загрузки музыкального контента артиста на радио
пример бота реализующего сервис загрузки музыкального контента артиста на радио

Хотя при таком методе не получится создать «армию ботов» на один аккаунт. На каждого бота придется заводить новый. Но с точки зрения безопасности и чистоты архитектуры плюсы очевидны:

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

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

  • Готовая монетизация: в профиле каждого пользователя уже прописаны платежные данные в виде Web3-кошелька. Соответственно, они автоматически доступны и боту, если тот реализует платные услуги.

РЕАЛИЗАЦИЯ НА БЭКЕНДЕ

Ниже упрощенный код класса реализующий передачу сообщений на Endpoint:

public async Task<string> ExecuteCommand(string cmd, string uid, string token, string url)
{
    using var client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new ("Bearer", token);
    
    var body = new StringContent(JsonConvert.SerializeObject(new { data = cmd, user_id = uid }), Encoding.UTF8, "application/json");
    var res = await client.PostAsync(url, body);
    var json = JObject.Parse(await res.Content.ReadAsStringAsync());

    return json["success"]?.Value<bool>() == true 
        ? json["data"]?.ToString() 
        : $"Error: {json["error"]}";
}  

Рабочий шаблон внешнего Endpoint сервиса:

<?php
session_start();
header('Content-Type: text/html; charset=utf-8');

//AUTHENTICATION BEGIN

$allowedToken   = 'super-secret-token';
$providedToken  = '';

if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
    if (preg_match('/Bearer\s+(.+)/i', $_SERVER['HTTP_AUTHORIZATION'], $m)) {
        $providedToken = trim($m[1]);
    }
}

if (empty($providedToken) || $providedToken !== $allowedToken) {
    echo json_encode(['success' => false, 'error' => 'error token']);
    exit;
}

//AUTHENTICATION END

$rawInput = file_get_contents('php://input');
$userData = json_decode($rawInput, true); 

echo json_encode(['success' => true, 'data' => 'Bot answer: ' . $userData['data'] ?? null]);

?>

ВЫВОД

Используя описанную концепцию, можно в теории реализовать любой сервис не изменяя при этом основное приложение. Всё что нужно сделать, построить бот!

Очевидно, что для практического применения такого подхода необходимо обеспечить высокий уровень безопасности: внедрить защиту от SSRF (через валидацию URL и фильтрацию локальных хостов), настроить лимиты для предотвращения DoS-атак (проверяя размер заголовков и длину полученной строки), и так далее.

Всем успехов в разработке!

Благодарю за внимание.

Теги:
Всего голосов 2: ↑2 и ↓0+4
Комментарии0

Лучше не сохраняйте в сессии PHP объекты с защищенными или приватными свойствами, если сама сессия хранится в БД.

Оговорюсь, что не поддерживаю сохранение объектов в сессиях PHP, а пример взят из Legacy-проекта, в котором компонент рекомендованных продаж клиенту реализован в виде класса. Видимо предыдущие разработчики посчитали удобным не париться с сохранением рекомендаций в виде отдельной структуры, а сохраняли класс прямо в сессию клиента. Сами сессии хранятся в БД MySQL (тоже тема для отдельной дискуссии).

Всё это отлично работало до переезда БД на кодировку utf8mb4_general_ci. После чего начались плавающие ошибки: некоторых пользователей стало выкидывать из ПУ. Довольно быстро определили, что проблема с сессиями, чуть больше времени потребовалось, чтобы определить, что некоторые сессии внезапно становились битыми у тех клиентов, для которых срабатывал сервис подбора рекомендаций.

Немного теории. Оказалось, что PHP сохраняет свойства объектов в сессии с определенными особенностями:

  • публичные свойства `public $item` сохраняются как item

  • защищенные свойства `protected $item` сохраняются как \0*\0item

  • приватные свойства `private $item` сохраняются как \0ClassName\0item

причем \0 это нулевой байт. Главной проблемой стало то, что MySQL воспринимал этот нулевой байт как конец строки и сохранял в таблицу обрезанную строку. Сессия становилась невалидной.

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

Теги:
Всего голосов 2: ↑2 и ↓0+4
Комментарии0

Ваш худший кошмар, или простой regex, который удивит даже опытных программистов.

re.match(r"^abc$", "abc\n") # python
/^abc$/.test("abc\n") // Javascript
preg_match("/^abc$/", "abc\n"); // PHP

Не читайте дальше, попробуйте угадать какой вывод будет у каждого из вариантов?

False?

True ?

Правильный ответ:

False
True
False

Живите с этим :)

Всё дело в том, что в PCRE $ означает не "конец строки", а "конец строки, или позиция перед \n в конце строки". А в ECMAScript это не так.

Лично я думал, что должно быть False, но регулярные выражения продолжают меня удивлять спустя много лет.

Правильный regex для точного совпадения с концом строки:

re.match(r"^abc\Z", "abc\n")
// javascript идеален, нечего исправлять :)
preg_match("/^abc\p/", "abc\n")

== false

Теги:
Всего голосов 10: ↑7 и ↓3+8
Комментарии3

Паттерны проектирования еще актуальны?

Вокруг все чаще говорят, что ИИ скоро будет писать код за нас. Логичный вопрос — нужны ли тогда паттерны? Зачем разбираться в паттернах GoF, если нейросеть и так сгенерирует рабочий код по описанию?

У меня ощущение обратное.

Я плотно вошел в разработку в 2019 году. Переходил из 1С в .NET. Книги по паттернам GoF у меня были, но долго лежали как «книга на полке». Казалось, они оторваны от повседневных задач. Теорию вроде понимал, но не видел, где это реально применяется.

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

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

Из этого и вырос мой pet-project gofinsights.com. Я делаю его тренажером по паттернам проектирования. Не просто «прочитал и забыл», а через практику, сравнение решений и постепенное распознавание типовых архитектурных ходов.

Сейчас там есть интерактивный квиз, где можно проверить базу и не перепутать Factory Method с Abstract Factory. Дальше хочу развивать проект в сторону более глубокого ИИ-разбора. Чтобы можно было не только узнавать паттерн, но и разбирать кодовые запахи, причины проблем и возможную эволюцию решений.

Как вы это видите? Паттерны проектирования все еще рабочая база для разработчика? Или с появлением ИИ они станут менее важны?

Теги:
Всего голосов 6: ↑5 и ↓1+6
Комментарии1

BloggyCms v1.0.0-rc.4

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

Дашборд системы
Дашборд системы

Впереди - куча оптимизации, например вынесение всех форм шаблона админки в контроллеры, и последующий их рендеринг через render_form(). Данные контроллеров в json и так далее.

Но - текущая версия движка с последующими обновлениями уже не сломается, как это было в первых релизных версиях.

Ну и самое главное - официальный сайт. Как оказалось - это одна из тех задач, которая весьма объемна и кропотлива - это и документация, и каталог дополнений с API для разработчиков и еще много-много чего.

Приглашаю к тестированию: https://github.com/pechoradev/BloggyCms

Также буду рад видеть новых контрибьюторов CMS.

Теги:
Всего голосов 4: ↑3 и ↓1+2
Комментарии24

Мультиязычность. Ад для разработчика.

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

И понеслась...

Процесс перевода движка
Процесс перевода движка

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

Вайбкодеры меня наверняка закидали бы тапками, мол - все можно автоматизировать и перевести хоть тонну файлов за 20 минут. Но - мне это не в кайф =)

Кто хочет помочь в процессе перевода, а заодно и движок потестить - милости прошу: https://github.com/pechoradev/BloggyCms

Теги:
Всего голосов 3: ↑3 и ↓0+3
Комментарии21

Ближайшие события

Господа фрилансеры!

20 лет я жил фрилансом. Искал заказы на fl.ru, договаривался на почасовую оплату, и спокойно работал в своем темпе. Поднимал сложные проекты, немного тимлидил, рос в навыках и т.п. Казалось, так будет всегда. Начинал я с PHP 3, каши из кода, вперемешку с html. Потом писал самопальные фреймворки, ускоряющие разработку. Со временем код становился чище, я освоил yii, yii2, Laravel втянулся в solid, научился в high load и т.п

Работа никогда не была моим средством самореализации. Это просто некая "дань этому миру", чтобы обслуживать тело. Я переехал в небольшой домик у озера в лесу, разбил огород, завёл хозяйство, тренировался по 4 часа в день, а работе уделял вечера.

Так вышло, что последние 7 лет я полностью перешел на постоянных заказчиков. Просто раз в пару месяцев выставлял им счет, исходя из 1000-1500р в час потраченного времени - всех все устраивало, мне платили без лишних вопросов, доверяли на слово. Но ничто не вечно в этом мире - старые проекты себя исчерпали, и пора искать новую работу. И тут я обнаружил, что старый подход больше не работает. Fl почти умер, заказов не найти. На hh - по 500-1000 откликов к каждой вакансии. Да и не хочу я работать с 9 до 18.

Появились какие-то новые биржи, основанные на попроектной оплате (типа, вставить виджет за 1к рублей). Но так полную занятость, обеспечивающую ежемесячный доход хотя бы в 150к, не найти. Ведь на поиск заказа, обсуждение деталей, получение доступов, вкуривание в новый код и т.п. уходит целый день, и, получается, что фактическая стоимость часа - 100-200р в час. А разработку сложных проектов не оценить сразу - в процессе всегда задачи разрастаются в несколько раз.

Что делать? Как в нынешних реалиях найти работу простому кодеру, привыкшему к свободному графику и обладающему огромным "жизненным опытом"?) Чтобы просто можно было заполнить весь рабочий месяц, работать по 4-6 часов в день, без беготни по задачкам на 1-2к рублей.

P.S. в качестве пруфа, что история не выдуманная, ссылка на профиль https://www.fl.ru/users/namo/portfolio/

Теги:
Всего голосов 5: ↑4 и ↓1+5
Комментарии6

Логистическая регрессия на MNIST (0 vs 1) на PHP: простой пример

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

Разбираем классическую задачу: бинарная классификация цифр (0 vs 1) на датасете MNIST (12 666 обучающих и 2 116 тестовых примеров) с помощью логистической регрессии, обученной через gradient descent. Всего 5 эпох – но результат всё равно шокирующе высокий. :)

Что тут интересного:

  • можно наглядно посмотреть, как модель работает с изображениями (в виде векторов)

  • становится понятно, где линейные модели начинают "ломаться"

  • можно посмотреть код чистой реализации на PHP и самому покопаться в коде
    – точность: 99.91%

  • и сравнить с более практичным вариантом на RubixML
    – точность: 99.95%

Это хороший переход от теории к практике: без заумных вещей, с понятной математикой и кодом.

Разбор:
https://apphp.gitbook.io/ai-for-php-developers/chast-iii.-klassifikaciya-i-veroyatnosti/logisticheskaya-regressiya/prakticheskie-keisy/mnist-binarnaya-klassifikaciya-otlichaem-0-ot-1

Примеры:
https://aiwithphp.org/books/ai-for-php-developers/examples/part-3/logistic-regression/case-0/mnist-0-1

Теги:
Всего голосов 3: ↑1 и ↓2+1
Комментарии0

Три доклада с Backend-митапа Garage Eight

> AI в travel tech — но не ради хайпа
Спикер: Глазунов Илья, backend lead в сервисе бронирования «ЖилиБыли»
YouTube | VK Видео

> Собрать LLM-стек для PHP за один вечер и не выстрелить себе в ногу
Спикер: Якимов Андрей, backend-разработчик Garage Eight
YouTube | VK Видео

> Модульная архитектура против хаоса: как ограничить контексты в большом монолите
Спикер: Русин Иван, старший разработчик группы модернизации платформы Flowwow
YouTube | VK Видео

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

Теги:
Всего голосов 5: ↑5 и ↓0+5
Комментарии0

Выпустили бесплатный курс для PHP-разработчиков

Пример одного из уроков курса
Пример одного из уроков курса

Всем привет! Год назад рассказывал в этой статье на Хабре о том, как мы подготовили и записали курс на 30+ часов для наших PHP-разработчиков. В итоге у нас вышло 43 урока, разбитые на 5 направлений.

Сначала думали упаковать все это в коммерческий формат, но решили оставить все как есть и просто поделиться с сообществом. Надеюсь, что он принесет вам пользу.

Курс охватывает PHP от базовых механизмов до архитектуры и тестирования. В программе — устройство языка, работа с памятью и производительностью, принципы ООП и проектирования, а также взаимодействие с базами данных.

Отдельные блоки посвящены внутренностям PHP (zval, сборщик мусора, OPcache, асинхронность), архитектурным подходам (SOLID, DDD, паттерны, организация бизнес-логики) и работе с БД — от проектирования схем до оптимизации запросов и масштабирования.

В части тестирования рассматриваются TDD, структура тестов и подходы к оценке их качества.

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

Теги:
Всего голосов 6: ↑6 и ↓0+7
Комментарии2

WT CDEK library v.1.3.0 - обновление PHP SDK для Joomla + CDEK.

Небольшая нативная PHP Joomla библиотека для работы с API v.2 службы доставки CDEK. Библиотека представляет собой клиент для авторизации в CDEK API по OAuth, работы с некоторыми методами API: получения ряда данных и расчета стоимости доставки. Поддерживается Joomla 4.2.7 и выше.

В пакет входят:

  • библиотека Webtolk/Cdekapi

  • системный плагин System — WT Cdek для хранения настроек и AJAX‑интеграций

  • task‑плагин Task — Update WT Cdek data для обновления локальных копий справочников CDEK по расписанию

  • web asset с официальным JavaScript‑виджетом СДЭК

👉 v.1.3.0. Что нового?

  • Полный рефакторинг библиотеки. Библиотека переработана в entity‑based API с фасадом Cdek и отдельным слоем запросов. Обратная совместимость не нарушена, поэтому версия библиотеки — 1.3.0.

  • Добавлена поддержка новых разделов API СДЭК. Добавлена поддержка новых разделов API СДЭК: webhooks, prealert, печатные формы, payment, passport, reverse, intakes и других сущностей.

  • Улучшена интеграция с Joomla. Улучшена интеграция с Joomla: installer script для layouts, новые поля Joomla Form для тарифов и обновлённые js виджета CDEK.

  • документация библиотеки. Все методы библиотеки подробно описаны, а так же текст документации собран в отдельной папке в git репозитории.

Пример запроса — запрос информации о городе.

<?php

use Webtolk\Cdekapi\Cdek;

\defined('_JEXEC') or die;

// Вариант 1: брать credentials из настроек плагина
$cdek = new Cdek();

// Вариант 2: передать credentials явно
$cdek = new Cdek(test_mode: true, client_id: 'your_client_id', client_secret: 'your_client_secret');

$result = $cdek->location()->getCities([
    'postal_code' => '410012',
    'city'        => 'Саратов',
    'size'        => 1,
]);

Результат запроса:

Array
(
    [0] => Array
        (
            [code] => 428
            [city_uuid] => 7e54a0b3-76f0-41e2-92e0-f1e600ad84fd
            [city] => Саратов
            [fias_guid] => bf465fda-7834-47d5-986b-ccdb584a85a6
            [country_code] => RU
            [country] => Россия
            [region] => Саратовская область
            [region_code] => 47
            [fias_region_guid] => df594e0e-a935-4664-9d26-0bae13f904fe
            [sub_region] => городской округ Саратов
            [longitude] => 46.034266
            [latitude] => 51.533562
            [time_zone] => Europe/Saratov
            [payment_limit] => -1
        )

)

Библиотека эта нужна для разработчиков, создающих свои расширения для интеграции Joomla и курьерской службы CDEK.

Страница расширения

GitHub расширения

Теги:
Всего голосов 2: ↑2 и ↓0+2
Комментарии0

Особенность Joomla: json-значения для пользовательских полей и их рендер в subform и вне дочерней формы.

Опять длинное название, но куда уж без этого...

Итак, если вы делаете плагин пользовательского поля - его можно использовать через FieldsHelper. И в процессе ваши данные проходят через различные этапы обработки (недавно была статья на эту тему). И может так оказаться, что ваше поле хранит в rawvalue json (и в базе данных соответственно тоже), а в value вы на его основе рендерите значение. Это стандартный подход Joomla. Так работают, например, поля accessiblemedia. Однако, если вы поместили ваше поле в дочернюю форму (пользовательское поле типа subform и включили "Рендеринг значений = Да", то у вашего замечательного поля может появиться поломанный Json в value вместо нормального значения.

Например:

{&quot;basePath&quot;:&quot;...&quot;,&quot;layout&quot;:&quot;...&quot;}

❓ Что там под капотом Joomla происходит?

  1. В обычном потоке Joomla сначала вызывает событие onCustomFieldsBeforePrepareField, а потом onCustomFieldsPrepareField.

  2. Внутри subform же для подполей при render_values=1 вызывается только событие - onCustomFieldsPrepareField.

  3. Если преобразование значения (например, json_decode) сделано в вашем плагине только в beforePrepareField, оно не обработает данные для подполя и...

  4. В шаблоне поля строка заэкранируется (htmlentities), кавычки превратятся в тыкву в &quot; и вы получите кривой json, вместо вашего значения.

👉 Собственно полезный совет по Joomla:

Для полей, которые могут жить внутри subform, делайте нормализацию значения и в onCustomFieldsPrepareField тоже, не только в beforePrepareField.

Теги:
Рейтинг0
Комментарии0

Спустя почти год работы мой PR приняли в ядро Joomla!

[Тут должна быть победная пляска] Год назад у моих клиентов возникла необходимость во вставке видео в кастомные поля материалов в раздел портфолио. Я начал делать и увидел, что именно стандартное пользовательское поле Media не умеет вставлять в поле ничего, кроме изображений, хотя поле Joomla Form MediaField умеет выбирать и документы (pdf и иже), аудио, видео и даже папки. Я начал работу над тем, чтобы добавить этот функционал  в ядро и очень надеялся успеть к Joomla 5.3, которая выходила в апреле. В целом все сделал, сделал PR 25 февраля 2025 года, но PR не приняли, сказав, что это шибко новый функционал и ему будет хорошо в Joomla 6.0.0. Клиентам пришлось использовать  медиа-менеджер от JCE, а PR отправился ждать релиза 6.0.0, который выходил осенью. К слову сказать, эта пауза была полезна для него, так как летом, уже неспешно я получал советы по улучшению и в июле всё точно было готово.

Релизный цикл Joomla состоит из нескольких этапов: сначала выходят alpha-версии (до 3х штук), где просто фиксируются накопленные изменения, потом beta, где наступает feature freeze - заморозка новых функций, их нельзя уже добавлять. Дальше только отладка и правки  существующих новшеств. У каждого релиза есть 2 релиз-менеджера.

В работе над PR мне помогал все это время Брайан Тиман - ко-фаундер Joomla. К концу июля все было готово, проверено, PR имел 2 необходимых независимых теста. Ждём беты.

Дата беты приходилась на понедельник. Где-то в пятницу днём я отписался в PR и получил совет написать релиз+менеджерам. Как-то удалось найти их в Mattermost, где обитает международное сообщество, но пятница и выходные, а все ж волонтеры и не на зарплате... Моё сообщение прочитали после релиза беты... Сказали, что не были в курсе моего PR (ожидаемо, их около 200-250 все время открытых). И сказали, что поезд ушёл, хоть и so sorry. Зато будет хорошо увидеть PR на тестах в Pizza, Bugz and Fun и вообще welcome в 6.1.

После выхода 6.0.0 меняются релиз-менеджеры. Мы списались: да, все хорошо, но нужно кое-что подправить. Тут конец года и закрытие дедлайнов, потом Новый год и весь январь никто толком не работает. Beta для 6.1 выходит 17 февраля. Последняя alpha  недели за 3 до этого.

Незадолго до выхода альфы я-таки получаю сообщение, что реализуемый функционал сделан не по "Joomla way" и если код в ядре, то этот код является учебным пособием по тому, как ядро использовать. Резонно. А ещё у релиз-менеджера есть собственные наработки и экспертиза в этой теме и свой медиа-менеджер, в котором он тоже прошел огонь, воду и медные трубы. Согласно Joomla way мне нужно было разделить одно мега-крутое поле на 4 отдельных (картинки, аудио, видео и документы). Я подумал, что требуется сделать 4 плагина вместо одного и сказал, что не успею. Мне ответили, что beta is more important for us и время ещё есть, что мне подскажут и 4 плагина делать не нужно.

Пока суть да дело - время идёт. У меня тоже работа, трое детей, карантины, уроки... Но добить этот PR уже стало делом принципа. Я  нашел как нужно было делать, принял несколько правок и пожеланий, потом фиксы code style. Сегодня с утра был последний коммит. Сегодня вечером, 11 февраля 2026 года, PR наконец-то смержен в ядро Joomla.

Эта работа научила меня очень многому. 170 комментариев в conversation на GitHub, несколько отдельных переписок, 1 год на разработку и внедрение простой в целом фичи, "звоночек" в голове: "не забыть, успеть, сделать, найти"...

Сегодня я поднимаю кружку пенного за этот небольшой  в целом PR, за этот прошедший год, за Joomla и за Open Source.

https://github.com/joomla/joomla-cms/pull/45013

#joomla #cms #opensource #community #webdev

P.S. Фото с пивом сюда выставлять не буду, но представьте, что оно тут есть.

Теги:
Всего голосов 9: ↑9 и ↓0+11
Комментарии14