Обновить
64K+

PHP *

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

71,07
Рейтинг
Сначала показывать
Порог рейтинга
Уровень сложности

Переезд с OpenCart 2 после двадцати лет работы: что лежит в дампе и откуда берутся восемь тысяч редиректов

Уровень сложностиСредний
Время на прочтение6 мин
Охват и читатели5K

Разбираем переезд интернет-магазина с OpenCart 2 на Next.js и PostgreSQL. Магазин оптовый, электронные компоненты, сайту двадцать лет, в каталоге 4 751 товар. Если у вас OpenCart и вы думаете уезжать, то будет полезно почитать, что может всплыть в самый неожиданный момент.

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

Читать далее

Новости

SOLID в реальном мире. ISP без микроинтерфейсов

Уровень сложностиСредний
Время на прочтение14 мин
Охват и читатели4.5K

Interface Segregation Principle часто понимают как требование дробить интерфейсы до одного метода. На примере PHP-проекта разберём, почему важен не размер интерфейса, а потребности его клиентов, как разделять контракты по акторам и сценариям и при этом не создавать зоопарк лишних абстракций.

Читать далее

Symfony Workflow: как реализовать сложную бизнес-логику через состояния и переходы

Время на прочтение11 мин
Охват и читатели5.3K

Заказ в интернет-магазине редко живёт по идеальной схеме «создан → оплачен → доставлен». В реальности жизненный цикл объекта нелинейный: клиент оформляет заказ, но может передумать и отменить его; товар приходит с браком и требуется возврат; часть позиций не успела прийти и нужно отправить их отдельно. Попытка реализовать такие альтернативные сценарии, проверки прав и сопутствующие действия «в лоб» быстро превращает бизнес-логику в хаос из разрозненных if/else, проверок статусов и обработчиков по всему проекту.

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

Читать далее

150 запросов на один flush, и 4343 зелёных теста. Как я делал детектор N+1 и как он сам меня обманывал

Уровень сложностиПростой
Время на прочтение15 мин
Охват и читатели4.4K

Один open‑source тайм‑трекер на Symfony имеет 4343 теста, и все они проходят. При этом каждое сохранение записи времени отправляет в базу три дополнительных SELECT запроса: ставку самой записи, ставку проекта и ставку активности. Если в одном flush() 50 записей, а столько строк показывает страница массового редактирования, только за ставками уходит 150 запросов. Тесты этот код покрывают, но ни один не падает, в них нет ни одной проверки проблем с запросами к базе данных.

Для решения этой проблемы сделал инструмент, которого в конце августа ещё не существовало. Правда, ещё до проверок сторонних проектов на N+1, он успел несколько раз обмануть меня самого, и всегда одинаково, показывал зелёное там, где на самом деле не работал.

Читать далее

Снижение нагрузки на сервер через WAF: реальный кейс WordPress/WooCommerce

Уровень сложностиСредний
Время на прочтение16 мин
Охват и читатели9.3K

Реальный кейс снижения нагрузки WordPress/WooCommerce с помощью WAF

На WordPress/WooCommerce-сайте на shared-хостинге регулярно возникали серьёзные превышения нагрузки на веб-сервер и MySQL. Штатный антибот-фильтр хостинга проблему не решил. В этом кейсе я показываю, что изменилось после подключения внешнего WAF с индивидуальной фильтрацией трафика: какие запросы создавали лишнюю нагрузку, как отсеивались парсеры, сканеры и поведенческие боты и что происходило с поисковыми роботами.

По данным Beget, после замены фильтра суточная нагрузка сайта снизилась примерно в 45 раз, базы данных — примерно в 39 раз. При этом WordPress, WooCommerce, плагины, код и структура БД не изменялись. В статье — реальные графики, данные Яндекс Метрики, статистика WAF и разбор случаев, когда WAF, наоборот, не поможет решить проблему высокой нагрузки.

Читать далее

Бесплатный плагин для входа через VK ID на WordPress: как закрыли потребность, когда готовых решений не нашлось

Время на прочтение2 мин
Охват и читатели7.4K

Начал я делать очередной сайт на Wordpress и решил упростить регистрацию пользователям. По этому пошел по схеме вход через другие сервисы. Как стало нынче модно‑сковородно использовать авторизацию через ВК. Ее то я и решил прикрутить. Делал уже это раньше но вот сегодня столкнулся с проблемой.

И есть решение

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

Уровень сложностиСредний
Время на прочтение19 мин
Охват и читатели6.3K

Документация устаревает быстрее, чем код успевает писаться? Рассказываем, как мы построили конвейер из Python-скриптов и нейросетей, который сам находит изменения в PHP-контроллерах и обновляет документацию API Invapi.

Читать далее

Четыре CMS, один интерфейс публикации: WordPress, 1С-Битрикс, InSales и Joomla

Уровень сложностиСредний
Время на прочтение10 мин
Охват и читатели5.2K

Полгода назад я делал сервис, который генерирует статьи и сам кладёт их на сайт. Написать текст казалось сложной частью, а публикация — формальностью: ну дёрнем REST API, что там может быть.

Оказалось наоборот. Четыре CMS — четыре разных мира, и в каждом свой способ соврать вам об успехе.

Joomla возвращает 400, когда статья уже создана: плагин «Умный поиск» падает после записи в базу. Повторили запрос — получили дубль. InSales требует published_at даже у черновика, потому что черновиков там просто нет. А у 1С-Битрикс метода для создания статьи через API не существует вовсе — официальная документация прямо говорит про read-only режим.

Внутри: как выглядит общий интерфейс на четыре системы, почему CIBlockElement::Add() возвращает ошибку при успешно созданном элементе, зачем понадобилась двойная буферизация вывода и прямой SQL в обход автотранслитерации.

Читать далее!

Матрешка из Base64 и ROT13: разбираем вредоносный .sh, который пришел за FreePBX

Уровень сложностиПростой
Время на прочтение8 мин
Охват и читатели5.8K

Мне в руки попался файл с расширением .sh и, конечно же, его пришлось изучить. Открываю файл — первая половина более-менее читаемая, а дальше начинается классика: Base64, ROT13 и еще немного Base64. Вроде ничего страшного. Декодируем, смотрим результат, радуемся жизни. Но не тут-то было. Автор скрипта решил сделать небольшой квест в стиле: А что если положить один скрипт внутрь другого скрипта, а потом еще один внутрь него?

Читать далее

Когда Laravel Validator становится узким местом при импорте 50 000 строк

Уровень сложностиПростой
Время на прочтение8 мин
Охват и читатели6.4K

PHP 7.4 / Laravel 8 / PostgreSQL 13

Проблема: импорт 50 тысяч строк занимал около 45 секунд.
Первое подозрение: база данных, INSERT, UPSERT, индексы, размер batch и количество запросов.
Реальность: бОльшая часть времени уходит на валидацию.

Мы начали разбираться, почему проверка нескольких десятков обычных полей на большом массиве данных оказалась значительно дороже самой записи в PostgreSQL. В итоге удалось сократить время валидации с 42,5 секунды до 0,65 секунды, а длительность всего job — примерно с 45 до 4 секунд.

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

Читать далее

Как на ровном месте сэкономить 1000+ ядер, или Куда на самом деле уходили 80% CPU

Уровень сложностиСредний
Время на прочтение18 мин
Охват и читатели16K

Всем привет, меня зовут Миша, и я бэкенд‑разработчик в платформе Яндекс Еды. Я уже рассказывал, как мы анализировали наш PHP‑монолит и вынесли из него процессинг заказов, и с тех пор роль этого легаси заметно уменьшилась. Заодно туда стали писать гораздо меньше нового кода, релизы стали реже, и он спокойненько себе работал, не привлекая лишнего внимания. 

Так оно бы и продолжалось, но тут случилась повышенная нагрузка и необходимость зарезервировать побольше мощностей для беспроблемной обработки повышенного спроса. Монолит справился на отлично, но самое интересное случилось потом: возвращая выделение ресурсов к прежним значениям, я случайно обратил внимание, что RPS в пиковые вечерние часы как‑то подозрительно совпадает с количеством ядер CPU, выделенных на весь монолит.

Количество выделенных ядер, конечно, ещё ничего не означает, поэтому я полез смотреть реальное потребление процессорного времени, сложив CPU usage по всем подам. С помощью нехитрой арифметики я обнаружил, что 100% загрузки одного ядра приходятся на 2,5 RPS. Какое‑то время я находился в состоянии глубокого изумления, после чего решил, что это никуда не годится, и отправился в увлекательное приключение на 20 минут. 

Немного спойлеров: дело оказалось далеко не только в PHP. 

Читать далее

Пользователь придумал пароль из 100 символов. От 28 из них ваша проверка не зависит

Уровень сложностиСредний
Время на прочтение6 мин
Охват и читатели14K

Тикет пришёл от разработчика, который писал импорт учёток из старой системы. Формулировка была такая: «кажется, у нас ломается верификация, но ломается она в плюс — подходят пароли, которых не было».

Ломалось не у него. Так работает bcrypt, и работает уже двадцать семь лет.

Читать далее

Как записать ЛИД в Битрикс24 (заявка с сайта и подобное) через входящий вебхук на PHP

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели6.7K

Для простой серверной интеграции с Битрикс24 далеко не всегда требуется полноценная OAuth 2.0-авторизация.

Если задача — из внешнего сервиса создать контакт, проверить существующего клиента и записать лид в CRM, это можно сделать через входящий вебхук Битрикс24 и обычный PHP.

Я использую такую схему в интеграциях, когда внешняя система отправляет данные на наш сервер, а сервер уже решает, что именно нужно создать в CRM.

Читать далее

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

Пакуем PHP в PHP, чтобы запаковать в JS, чтобы обернуть в HTML

Время на прочтение3 мин
Охват и читатели7.1K

Прочтя недавний перевод про запаковку БД в exe, решил рассказать об идеи, которую реализовал лет 6 назад в своем домашнем проекте. Сам проект недоделал, но речь в статье об архитектуре файлов и их запаковке.

Читать далее

Как я год загружал фото в Битрикс24 и собрал все грабли файлового API

Уровень сложностиСложный
Время на прочтение12 мин
Охват и читатели8.7K

Работа с файлами в REST API Битрикс24 — та задача, где документация заканчивается ровно там, где начинаются проблемы. Официальные примеры показывают, как загрузить один файл в одно поле. А дальше выясняется, что у crm.item.update и crm.deal.update разные несовместимые форматы, что вложенный base64 через http_build_query уходит в никуда, а сервер при этом честно отвечает «result».

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

Собрал всё в один разбор — шесть подходов с кодом и восемь граблей:

два формата файлового значения, которые нельзя смешивать, и почему при смешении затираются уже прикреплённые файлы;

тихий провал: HTTP 200, в ответе result, поле не обновилось;

useOriginalUfNames=Y, без которого UF_CRM_* молча игнорируются;

downloadUrl приходит с пустым auth= и без подстановки токена не скачивается, а при протухшем токене вместо файла отдаётся HTML-страница с кодом 200;

у одного изображения бывает несколько URL, и часть из них не работает — пришлось делать скоринг вариантов по эвристике.

В конце — таблица «что брать под какую задачу» и чеклист граблей. Двадцать блоков кода, всё из боевых проектов.

Читать далее

Автогенерация типов показала, что проблема была не в типах

Уровень сложностиСредний
Время на прочтение10 мин
Охват и читатели6.9K

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

Статья не про саму автогенерацию — с ней всё понятно, про неё и без меня написано достаточно. Мы внедрили генерацию типов из OpenAPI, и она вытащила наружу то, что с генерацией напрямую не связано: кто не хочет писать комментарии, почему у одной сущности два имени и почему у нас падал dev. По сути — про команду, эго и умение договариваться.

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

Читать далее

Публичный API у генератора QR-кодов: без ключей, лимитер на файлах и грабля Apache

Уровень сложностиСредний
Время на прочтение4 мин
Охват и читатели5.6K

У моего генератора QR-кодов листами появился публичный API: POST с JSON, в ответ сразу готовый PDF, до 1500 кодов за запрос, без регистрации и ключей. Внутри рассказ, почему я не завел ни ключи, ни Redis, как работает лимитер на файлах с flock и fail-open, и на какой грабле Apache POST молча превращался в GET.

Читать далее

Пишем свой PHP-экстеншен на Rust

Уровень сложностиСредний
Время на прочтение12 мин
Охват и читатели6.2K

Когда речь заходит о разработке PHP-расширений, многие сразу представляют C, Zend API и сложную систему сборки. Но сегодня есть более удобный путь. С помощью ext-php-rs можно создавать расширения на Rust, используя привычные инструменты Cargo и практически не сталкиваясь с низкоуровневыми деталями.

В этой статье мы с нуля напишем собственный PHP-экстеншен, подключим его к PHP, разберём, как ext-php-rs связывает Rust с Zend API, а затем посмотрим, в каких задачах такой подход действительно даёт прирост производительности, а где этого ждать не стоит.

Читать далее

Автоматическая установка Wordpress на чистый сервер Ubuntu или Debian

Уровень сложностиПростой
Время на прочтение8 мин
Охват и читатели5.3K

Ставить WordPress руками — занятие на полтора часа: веб‑сервер, PHP с десятком расширений, база данных, конфиг Nginx, права на файлы, лимиты загрузки, сертификат. Я устал повторять этот ритуал и собрал скрипт, который делает всё сам и спрашивает только то, что действительно зависит от меня.

Итог, к которому мы придём: работающий сайт с настроенной админкой, ЧПУ‑ссылками, русской локализацией, при желании — с сертификатом Let’s Encrypt, phpMyAdmin и защитой от подбора паролей. Все доступы будут лежать в одном файле на сервере.

Читать далее

OAuth 2.0 в amoCRM REST API на PHP простым языком: получение, хранение и обновление токенов

Уровень сложностиСредний
Время на прочтение6 мин
Охват и читатели5.6K

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

Основной вопрос возникает раньше:

как один раз авторизовать интеграцию, а затем поддерживать доступ к amoCRM без постоянного ручного получения ключей?

1-2 года назад я реализовывал такую интеграцию на PHP. Токены хранили в MySQL, а работу с OAuth разбили на несколько отдельных файлов.

Сейчас решил восстановить общую архитектуру этой реализации.

Если убрать детали, OAuth-интеграция выглядит довольно просто:

Authorization Code → Access Token + Refresh Token → сохранение в БД → запросы к REST API → обновление токенов → повторное сохранение в БД.

Код авторизации берется в AmoCRM:

Читать далее
1
23 ...