Найстрашніший простій WordPress — це той, що трапляється тихо: оновлення PHP «заради безпеки», яке проходить CI, виглядає нормально в браузері,
а потім перетворює ваш найприбутковіший процес оформлення замовлення на білий екран о 2-й ночі, поки відповідальний черговий намагається пригадати,
який пул на якому хості. У всіх є думки. Логи мають факти.
Несумісність версій PHP не є містичною. Це просто невідповідність між поведінкою рантайму і припущеннями коду —
у ядрі WordPress, у плагінах, у темах і в оперативному клеї вашого стеку (opcache, object cache, проксі). Ви можете оновити
без простоїв, якщо ставитесь до цього як до зміни в продакшні: інвентаризація, тест з реальним трафіком, безпечне перемикання
і робіть відкат нудним.
Що насправді ламається при зміні версій PHP (і чому WordPress це відчуває)
Оновлення PHP — це не «просто новий інтерпретатор». Це зміна правил мови, поведінки стандартної бібліотеки, налаштувань за замовчуванням
та розширень, від яких залежить WordPress. WordPress стоїть на перехресті спадщини коду й сучасного хостингу. Він підтримує старі сайти,
плагіни з 2012 року та розробників, які ставляться до functions.php як до сповіді. Саме тому він чутливий.
Несправності сумісності бувають чотирьох типів
-
Жорсткі помилки: фатали, помилки парсингу, відсутні функції/класи, відсутні розширення.
Це ті моменти, коли «сайт впав». -
М’які помилки: warning/notice, які стають фаталами при суворіших налаштуваннях, або зміни логіки, що змінюють поведінку
(порожній рядок vs null, порівняння, обробка масивів). -
Регресії продуктивності: відмінності в OPcache, побічні ефекти JIT або шляхи коду, що стали повільнішими
через зміни в рушії. Зазвичай проявляється як підвищення CPU і хвостова латентність, а не миттєві помилки. -
Операційні невідповідності: різні значення за замовчуванням у
php.ini, різні конфіги FPM пула,
відсутні системні пакети, змінені права на файли або один сервер оновлено, а інший — ні.
Чому оновлення WordPress «працює в staging», але все одно ламається в продакшні
Staging часто має інший набір плагінів, інше кешування і чемний трафік. Продакшн-трафік — грубіший.
Він потрапляє на дивні кінцеві точки, надсилає великі куки, запускає cron у невдалий час і виконує рідко використовувані сторінки адмін-панелі.
І більшість staging-середовищ не використовують той самий object cache, ті самі семантики файлової системи або той самий стан прогрітого opcode cache.
Операційна цитата, яку варто тримати на стікері: «Надія — це не стратегія.» — перефразована думка, часто згадувана в колах надійності.
У цьому контексті надія означає «оновимо й подивимось». Не робіть так. Вимірюйте й перемикайте з планом.
Також WordPress — це екосистема плагінів. Один плагін може підключити сторонню бібліотеку, яка очікує поведінку певної версії PHP.
Ви оновлюєте PHP і раптом залежність починає кидати TypeError, де раніше тихо приводила типи. Це не PHP злий; це PHP більш явний.
Ваш бюджет помилок може не погодитися.
Жарт №1: Оновлювати PHP, не перевіривши плагіни, — це як поміняти замок на дверях і дивуватися, що ключі перестали підходити.
Цікаві факти й історичний контекст (те, що пояснює біль)
- PHP 7.0 (2015) був великим поворотом у продуктивності після роботи PHPNG; багато WordPress-сайтів отримали драматичне пришвидшення без змін коду.
- PHP 5.6 вийшов з підтримки в 2018 році, але шаред-хостинг тримав його в живих роками, бо «ще нічого не зламалося».
- PHP 8.0 (2020) ввів JIT, але типовий робочий навантаження WordPress рідко отримує від цього суттєву користь; важливіші поліпшення рушія та сумісність.
- PHP 8 посилив типізацію і зробив так, що більше операцій кидають
TypeErrorзамість того, щоб мовчки приводити типи; багато легасі-плагінів покладалися на таке «підтягування». - Історія розширення MySQL має значення: колись WordPress використовував
mysql_*функції; сучасні стеки використовуютьmysqliабо PDO. Старі плагіни іноді цього не «помічали». - «Білий екран смерті» WordPress став мемом, бо фатали часто ховалися через
display_errors=Off; сучасний WordPress має recovery mode, але це не магічний щит. - OPcache став мейнстрімом у PHP 5.5; сьогодні більша частина стабільності продуктивності залежить від налаштування opcache і від уникнення його трешингу постійними деплоями.
- Composer не завжди був поширений у WordPress-середовищі; багато плагінів досі вручну бандлять код вендорів, що ускладнює патчинг залежностей і сумісність PHP.
- FPM замінив mod_php як стандарт для серйозних розгортань, бо управління процесами й ізоляція стали логічнішими — також тому, що запуск всього в Apache — це стиль життя.
Швидкий план діагностики: підтвердіть, що це PHP, а потім знайдіть крайову проблему
Коли сайт WordPress починає віддавати 502, порожні сторінки або дивні помилки в адмінці після «планового вікна обслуговування»,
вам потрібен короткий цикл: підтвердіть, де знаходиться помилка, звузьте шлях коду та виріште, відкатуватися чи виправляти.
Не спускайтеся в печери навмання.
По-перше: підтвердіть шар симптомів
-
Це на рівні HTTP (502/504) чи на рівні додатка (200 з битим HTML)?
502 зазвичай означає, що PHP-FPM впав, завис або апстрім неправильно налаштований. 200 з порожньою сторінкою часто означає PHP fatal із приглушеним виводом. -
Помилка на всіх вузлах чи лише на деяких?
Мішанина версій PHP у пулі з балансувальником — класичний режим «іноді працює». -
Обмежено адмінкою, cron чи конкретним шляхом плагіна?
Потоки оформлення замовлення й AJAX часто викликають інший код, ніж головна сторінка.
По-друге: перевірте два логи, що насправді важливі
- Лог помилок PHP-FPM (або журнал systemd): показує фатали, сегфолти та проблеми з конфігом пула.
-
Лог додатка WordPress/PHP:
wp-content/debug.log, якщо увімкнено, або ваша централізована система логування.
По-третє: ізолюйте, чи це несумісність чи проблема потужності
-
Якщо в помилках згадується
Call to undefined function,Class not found,Parse errorабоTypeErrorпісля оновлення: вважайте це несумісністю, поки не доведено інше. -
Якщо логи показують таймаути,
server reached pm.max_childrenабо довгі тривалості запитів: ваше оновлення змінило характеристики продуктивності, і тепер ви межуєтеся з потужністю. - Якщо помилки переривчасті й корелюють з конкретним бекендом: ймовірно, у вас має місце зміщення версій або конфігу.
По-четверте: вирішіть — відкат чи виправлення вперед
Моє правило: якщо оформлення/адмінка недоступні або рівень помилок різко зростає і у вас немає підтвердженого виправлення, спочатку відкатіться.
Відкат дає час подумати, не змушуючи клієнтів платити за вашу допитливість.
Практичні завдання (команди, виводи та рішення)
Це ті завдання, які я насправді виконую. Не тому, що вони витончені, а тому, що вони знімають неоднозначність.
Кожне завдання містить: команду, що означає її вивід, і рішення, яке ви приймаєте.
Завдання 1: Визначити версію PHP, що обслуговує сайт (CLI і FPM можуть відрізнятися)
cr0x@server:~$ php -v
PHP 8.1.2 (cli) (built: Feb 15 2025 10:41:12) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Zend OPcache v8.1.2, Copyright (c), by Zend Technologies
Значення: Це CLI-байнар. Він може не відповідати тому, що використовує Nginx/Apache через FPM.
Рішення: Якщо ви налагоджуєте поведінку вебу, не припускайте, що це рантайм. Далі перевірте FPM.
Завдання 2: Підтвердити версію та статус PHP-FPM через systemd
cr0x@server:~$ systemctl status php8.1-fpm --no-pager
● php8.1-fpm.service - The PHP 8.1 FastCGI Process Manager
Loaded: loaded (/lib/systemd/system/php8.1-fpm.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2025-12-27 10:12:33 UTC; 2h 4min ago
Docs: man:php-fpm8.1(8)
Main PID: 1234 (php-fpm8.1)
Status: "Processes active: 6, idle: 10, Requests: 24912, slow: 3, Traffic: 1.2req/sec"
Значення: FPM працює і повідомляє про повільні запити.
Рішення: Якщо ви бачите «failed» або цикли рестартів, ви в зоні інциденту. Якщо після оновлення зросла кількість повільних запитів, досліджуйте продуктивність і таймаути.
Завдання 3: Перевірити, який upstream-сокет використовує Nginx (спіймати розбіжність версій)
cr0x@server:~$ sudo nginx -T 2>/dev/null | sed -n '/fastcgi_pass/p' | head
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
Значення: Nginx підключений до сокета PHP 8.1.
Рішення: Якщо це вказує на php7.4-fpm.sock на деяких вузлах і на php8.1-fpm.sock на інших, виправте управління конфігом перед змінами коду.
Завдання 4: Підтвердити обробник PHP в Apache (mod_php vs proxy_fcgi)
cr0x@server:~$ apachectl -M 2>/dev/null | egrep 'php|proxy_fcgi|mpm'
mpm_event_module (shared)
proxy_fcgi_module (shared)
Значення: Apache ймовірно використовує FPM через proxy_fcgi, а не mod_php.
Рішення: Якщо ви бачите завантажений php_module, ви на mod_php і перемикання версій інше й ризикованіше. Віддавайте перевагу FPM для мульти-версійних налаштувань.
Завдання 5: Викликати локальний phpinfo-подібний ендпоінт без публічного доступу
cr0x@server:~$ curl -sS -H 'Host: example.com' http://127.0.0.1/wp-admin/admin-ajax.php | head
0
Значення: Це не показує версію PHP, але підтверджує, що WordPress виконується шляхом веб-запиту локально.
Рішення: Якщо це повертає 502/504 локально, проблема на сервері/шляху додатка, а не в CDN чи зовнішньому DNS.
Завдання 6: Увімкнути дебаг WordPress (тимчасово) і підтвердити запис логів
cr0x@server:~$ sudo -u www-data php -r 'echo "ok\n";'
ok
Значення: Ваш веб-користувач може запускати PHP і повинен мати змогу писати логи, якщо права дозволяють.
Рішення: Якщо веб-користувач не може виконувати чи писати куди потрібно, виправте права, перш ніж ганятися за «привидами сумісності».
Завдання 7: Підглядайте логи PHP-FPM на предмет фаталів і помилок пула під час запиту
cr0x@server:~$ sudo tail -n 30 /var/log/php8.1-fpm.log
[27-Dec-2025 12:14:22] WARNING: [pool www] server reached pm.max_children setting (20), consider raising it
[27-Dec-2025 12:14:27] ERROR: WARNING: [pool www] child 1842 said into stderr: "PHP Fatal error: Uncaught TypeError: strlen(): Argument #1 ($string) must be of type string, null given in /var/www/html/wp-content/plugins/foo/bar.php:91"
Значення: У вас одночасно тиск по потужності (pm.max_children) і реальна несумісність (TypeError).
Рішення: Виправте фатал спочатку (це — правильність). Потім вирішіть питання потужності, бо помилки можуть посилити навантаження через повторні спроби.
Завдання 8: Підтвердити встановлені модулі PHP (відсутні розширення викликають дивну поведінку)
cr0x@server:~$ php -m | egrep 'curl|gd|imagick|mbstring|mysqli|openssl|zip'
curl
gd
mbstring
mysqli
openssl
zip
Значення: Модулі, як-от imagick, можуть бути відсутніми після оновлення, змінюючи поведінку обробки медіа.
Рішення: Якщо потрібний модуль відсутній, встановіть його для цільової версії PHP і перезапустіть FPM, перш ніж звинувачувати WordPress.
Завдання 9: Перевірити версії ядра та плагінів за допомогою WP-CLI
cr0x@server:~$ cd /var/www/html
cr0x@server:/var/www/html$ sudo -u www-data wp core version
6.4.3
Значення: У вас зафіксована версія ядра.
Рішення: Якщо ядро старе відносно цільової версії PHP, спочатку оновіть ядро в staging. Сумісність ядра загалом краща, ніж сумісність плагінів, але не ризикуйте.
Завдання 10: Знайти плагіни, які найімовірніше зламаються (і відключити один без ручного редагування БД)
cr0x@server:/var/www/html$ sudo -u www-data wp plugin list --status=active
+-----------------------+----------+-----------+---------+
| name | status | update | version |
+-----------------------+----------+-----------+---------+
| woocommerce | active | available | 8.1.1 |
| elementor | active | none | 3.18.0 |
| foo-payments-gateway | active | none | 2.4.7 |
+-----------------------+----------+-----------+---------+
Значення: Тепер у вас короткий список коду, що виконується на більшості запитів.
Рішення: Якщо фатал вказує на шлях плагіна, відключіть цей плагін на тестовому вузлі або в staging спочатку. У надзвичайній ситуації відключайте в продакшні лише якщо розумієте бізнес-наслідки.
Завдання 11: Запустити синтаксичну перевірку PHP у плагіні чи темі (виявляє помилки парсингу раніше)
cr0x@server:/var/www/html$ find wp-content/plugins/foo-payments-gateway -name '*.php' -print0 | xargs -0 -n1 php -l | head
No syntax errors detected in wp-content/plugins/foo-payments-gateway/includes/api.php
No syntax errors detected in wp-content/plugins/foo-payments-gateway/foo.php
Значення: Парс-помилок немає. Це необхідна, але недостатня умова.
Рішення: Якщо ви бачите помилки парсингу, цей плагін не працює на цій версії PHP. Оновіть/замініть його або не оновлюйте PHP поки що.
Завдання 12: Виявити застарілі виклики й warning-и, запустивши сторінку з суворішою видачею помилок (staging)
cr0x@server:~$ php -d display_errors=1 -d error_reporting=E_ALL -r 'trigger_error("test", E_USER_DEPRECATED);'
Deprecated: test in Command line code on line 1
Значення: Ви можете примусово зробити видимими депрекейшени в контрольованому середовищі.
Рішення: У staging підвищіть видимість помилок і пропустіть критичні потоки. Депрекейшени можуть стати завтрашніми фаталами, коли бібліотеки оновляться.
Завдання 13: Перевірити живі помилки трафіку в access-логах (помітити сплески 502 і проблемні кінцеві точки)
cr0x@server:~$ sudo awk '$9 ~ /^5/ {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head
184 /wp-admin/admin-ajax.php
77 /?wc-ajax=checkout
22 /wp-json/wc/v3/orders
Значення: Збої зосереджені навколо AJAX і оформлення — класичні шляхи з великою роллю плагінів.
Рішення: Сфокусуйте тестування й ізоляцію на цих маршрутах. Не витрачайте час на оновлення головної сторінки.
Завдання 14: Підтвердити налаштування opcache (погано налаштований opcache може виглядати як «оновлення PHP все поламало»)
cr0x@server:~$ php -i | egrep 'opcache.enable|opcache.memory_consumption|opcache.max_accelerated_files' | head
opcache.enable => On => On
opcache.memory_consumption => 128 => 128
opcache.max_accelerated_files => 10000 => 10000
Значення: OPcache увімкнено, але пам’ять може бути як достатньою, так і ні в залежності від кількості плагінів.
Рішення: Якщо ви бачите часті скидання кешу або «out of memory for opcache», збільшіть пам’ять і ліміт файлів для opcache. Інакше ви гнатиметеся за фантомною латентністю.
Завдання 15: Порівняти версії PHP по флету серверів (спіймати часткові оновлення)
cr0x@server:~$ for h in wp-app-01 wp-app-02 wp-app-03; do ssh $h "php-fpm8.1 -v 2>/dev/null | head -1 || php-fpm8.0 -v 2>/dev/null | head -1"; done
PHP 8.1.2 (fpm-fcgi) (built: Feb 15 2025 10:41:12)
PHP 8.1.2 (fpm-fcgi) (built: Feb 15 2025 10:41:12)
PHP 8.0.30 (fpm-fcgi) (built: Jan 10 2025 08:12:44)
Значення: Один вузол на PHP 8.0, інші — на 8.1.
Рішення: Стоп. Виправте розбіжність версій перед розслідуванням «випадкових» помилок. Змішаний рантайм — податок на надійність, який ви платитимете постійно.
Завдання 16: Підтвердити, який конфігураційний файл використовує FPM (бо ви думаєте, що змінили його…)
cr0x@server:~$ php-fpm8.1 -tt 2>&1 | head -20
[27-Dec-2025 12:33:01] NOTICE: configuration file /etc/php/8.1/fpm/php-fpm.conf test is successful
[27-Dec-2025 12:33:01] NOTICE: using php.ini in /etc/php/8.1/fpm/php.ini
Значення: Ви редагуєте правильний шлях файлів для FPM.
Рішення: Якщо він вказує десь інакше (контейнери, кастомні префікси), налаштуйте tooling деплою. Редагування неправильного ini-файлу — класика.
Завдання 17: Перевірити пропускну здатність пула PHP-FPM і таймаути (щоб уникнути міфів «оновлення спричинило 502»)
cr0x@server:~$ sudo egrep 'pm\.max_children|pm\.max_requests|request_terminate_timeout' /etc/php/8.1/fpm/pool.d/www.conf | sed 's/;.*$//'
pm.max_children = 20
pm.max_requests = 500
request_terminate_timeout = 60s
Значення: Ваш пул обмежений 20 робітниками і вбиває запити через 60 секунд.
Рішення: Якщо трафік або повільніший код збільшили час запитів, підніміть max_children (в рамках CPU/RAM) і налаштуйте timeout. Але не «вирішуйте» фатали підвищенням таймаутів.
Шаблони оновлення, що уникають простоїв (Nginx/Apache, PHP-FPM та відкат)
«Без простоїв» не означає «без ризику». Це означає, що ви можете переключити версію рантайму, не рвучи з’єднання і не затемнюючи сайт.
Хитрість — у паралелізмі: тримайте старий і новий PHP поруч, маршрутизовуйте трафік свідомо і тримайте відкат на відстані одного зміни конфігурації.
Патерн A: Паралельні PHP-FPM сокети + поетапне зміщення трафіку
Запустіть два сервіси FPM: старий (наприклад, PHP 8.0) і новий (наприклад, PHP 8.1). Підключайте Nginx (або Apache proxy_fcgi) до одного сокета одночасно,
або ще краще — розділяйте трафік на рівні балансувальника: канарьте один вузол на новому PHP, тримаючи решту на старому.
Це найчистіший підхід для мінімальних простоїв, бо:
- Відокремлює встановлення пакетів від переключення трафіку.
- Дозволяє тестування на реальному продакшн-трафіку на невеликій частці.
- Відкат швидкий: переключіть upstream-сокет або видаліть канар з пулу.
Патерн B: Blue/green шар додатка з незмінними образами
Зберіть новий образ (VM або контейнер) з новим рантаймом PHP, тими ж конфігами, тим самим кодом WordPress і плагінами, потім підніміть його
за балансувальником поруч зі старим пулом. Злійте й переключіться. Так ви зберігаєте аудит змін.
Це також запобігає «сніговим серверам», де один вузол має інше розширення, бо хтось колись щось дебагнув і не задокументував.
Патерн C: Ті самі сервери, але швидкий відкат через перемикач конфігу
Якщо ви змушені переключатися на місці, зберігайте старий FPM-сервіс встановленим і здійним, і робіть перемикання як деплой конфігу:
оновіть Nginx fastcgi_pass на новий сокет і зробіть reload. Reload, а не restart.
Reload означає, що існуючі з’єднання виживуть; нові воркери підхоплять конфіг. Restart означає, що ви дізнаєтеся про розлючених клієнтів.
Обирайте reload. Завжди.
Мінімальний безпечний план відкату
- Старий PHP-FPM має залишатися встановленим і запущеним (або доступним для запуску) протягом всього вікна оновлення.
- Ваш веб-сервер може швидко переключатися між сокетами або upstream.
- OPcache скидається при переході (або ви погоджуєтесь на ризик змішаного байткоду в кеші).
- Ви знаєте, які плагіни/теми змінювалися недавно, і можете відключити їх через WP-CLI.
Жарт №2: Єдина річ більш постійна, ніж тимчасове оновлення PHP — це «тимчасовий» хотфікс, який вам страшно видалити.
Збереження стану й диску: прихований множник простоїв
WordPress — це не лише PHP. Це PHP плюс база даних плюс завантаження файлів плюс кеші. Оновлення PHP може спровокувати:
- Картачі кешу, якщо opcache скидається і object cache одночасно промахується.
- Перегенерацію медіа, якщо бібліотеки зображень відрізняються (наявність gd vs imagick).
- Зміни прав файлової системи, якщо пакети змінюють дефолтні user/group або конфіг пула.
Якщо ви використовуєте спільне сховище (NFS, EFS, Gluster, CephFS), будьте обережні: плагін, що робить багато stat() викликів,
може стати повільнішим під новим рантаймом PHP (або просто через інший стан прогрітого opcache), і затримки диску раптом набувають значення.
В продакшні сховище ніколи не «чужа проблема». Це просто проблема, що ще не дістала ваш номер телефону.
Три міні-історії з корпоративного світу (біль, зарозумілість і нудна компетентність)
Міні-історія №1: Інцидент, спричинений неправильною передумовою
Середня компанія вела WordPress для маркетингових сторінок і окремий додаток для білінгу. Маркетинг «не був критичним»,
фраза, яку керівники говорять прямо перед тим, як просити ETA кожні сім хвилин.
Інфраструктурна команда оновила PHP з 7.4 до 8.1 на веб-вузлах під час чергового циклу патчів. Вони перевірили php -v, оновили головну сторінку,
побачили 200 і закрили тікет. Передумова була проста: «Якщо головна сторінка завантажується, WordPress у порядку».
Наступного ранку команда контенту спробувала опублікувати пост. Редактор упав. Потім адмін-логін почав кидати 500.
Голова сторінка все ще виглядала нормально, бо була кешована в CDN і edge-cache не турбувався про PHP-фатали.
Тим часом заплановані пости не опублікувалися, бо виклики WP-Cron падали, і запуск кампанії тихо прогавили.
Корінна причина була банальною: плагін, що використовувався лише у шляху адмін-редактора. Він застосовував бібліотеку, яка при PHP 8.1 кидала TypeError,
коли отримувала null. Він ніколи не виконувався під анонімними домашніми запитами. Ніхто не тестував адмін-шлях. Ніхто не дивився логи.
Усі тестували ту єдину сторінку, яка найімовірніше була закешована.
Виправлення було соромно просте: зафіксувати плагін на оновленій версії і додати тест «адмін-критичного шляху» до чекліста релізу.
Справжній урок був операційний: перевіряйте робочі процеси, що мають значення, а не сторінки, що зручні.
Міні-історія №2: Оптимізація, що обернулася навпаки
Інша організація хотіла «прискорити WordPress» і вирішила ввімкнути агресивні налаштування OPcache і збільшити pm.max_children одразу після оновлення PHP.
Дві зміни одночасно. Два регулятори, одна панель. Ви вже знаєте, чим це обернулося.
Спочатку метрики виглядали чудово: більший пропуск, менше стрибків CPU. Потім підкралась пам’ять. Вузли почали свопити.
Латентність стала нелінійною. З’явилися кілька 502, потім багато. Команда припустила, що нова версія PHP нестабільна.
Насправді ні. Вони збільшили кількість воркерів, не збільшивши пам’ять, а OPcache був налаштований настільки великим, що в кожного вузла залишилося менше запасу для
реальних запитів. Під навантаженням kernel почав витісняти пам’ять, сторінковий кеш пішов у треш, і PHP-воркери застопорилися. Стек не «впав». Він задихнувся.
Відкат до старої версії PHP не допоміг, бо налаштування ресурсів залишилися. Це створило плутанину: «Ми відкатилися, але все одно не працює».
Після години розслідувань вони повернули налаштування FPM та OPcache — і сайт відновився.
Урок: тонке налаштування продуктивності — це зміна з зоною ураження. Робіть її окремо від оновлення версії. І якщо ви торкаєтесь pm.max_children,
знайте свій пам’ятний слід на воркера, а не тільки використання CPU.
Міні-історія №3: Нудна, але правильна практика, що врятувала ситуацію
Третя компанія вела WooCommerce з купою плагінів, деякі старі, деякі кастомні. У них була бюрократична на вигляд звичка: кожне оновлення рантайму вимагало канарного вузла і
скриптованого «топ-20 ендпоінтів» синтетичного тесту. Без винятків.
Оновлення PHP до 8.2 робили поетапно. Вони збирали нові образи, піднімали один канарний вузол і направляли на нього 2% трафіку.
Синтетичні тести били по оформленню, додаванню в кошик, логіну, збереженню поста в адмінці та кільком API-ендпоінтам. Вони також відтворювали реальний трафік, програючи маленький зріз access-логів проти канару (санітизований і з обмеженням швидкості).
За кілька хвилин логи помилок на канарі показали, як ворнінги перетворюються на фатали в робочому плагіні. Головний пул лишався здоровим.
Команда відключила плагін на канарі, щоб підтвердити діагноз, а потім вивела канар з ротації.
Клієнти навіть не помітили.
«Нудна» частина була в рукбуку: точні команди для diff конфігів, порівняння списків модулів, перевірки налаштувань пулу і відкат ваг трафіку.
Це не було хитрим. Це було повторювано. Саме це їх врятувало.
Їхнє подальше виправлення теж було нудне: замінити плагін на підтримуваний альтернативний і запланувати оновлення PHP знову.
Вони втратили день, а не вихідні.
Поширені помилки: симптом → корінна причина → виправлення
Якщо ви довго в продакшні, частину з цього можна діагностувати з одного скріншоту. Іншу частину треба дивитись у логах.
Ось мапа.
1) Симптом: Білий екран (200 OK, порожня сторінка)
- Корінна причина: Фатальна помилка PHP при
display_errors=Off, часто під час ініціалізації теми чи плагіна. - Виправлення: Перевірте лог PHP-FPM на фатали. Тимчасово увімкніть логування WordPress. Знайдіть і оновіть/відключіть проблемний плагін/тему.
2) Симптом: 502 Bad Gateway одразу після оновлення
- Корінна причина: Nginx/Apache все ще вказує на старий шлях сокета, або FPM не працює, або пул не стартує через синтаксис конфігу.
- Виправлення: Підтвердьте ціль
fastcgi_pass, запустітьphp-fpm -tt, перевірте статус systemd, права сокета, перезавантажте веб-сервер.
3) Симптом: Працює іноді, ламається іноді
- Корінна причина: Розбіжність версій між вузлами; один сервер оновлено, інший — ні. Або непослідовні файли плагінів на спільному сховищі.
- Виправлення: Порівняйте рантайм-версії на всіх вузлах. Забезпечте атомарність ідентичних деплоїв; не змішуйте ручні правки на NFS з CI-деплоєм.
4) Симптом: Адмін-панель не працює, публічний сайт — ні
- Корінна причина: Несумісний плагін, що використовується переважно в адмін/редакторських шляхах. CDN ховає публічні збої.
- Виправлення: Тестуйте адмін-робочі потоки у staging. Дивіться логи канарів. Відключайте/оновлюйте адмін-тільки плагіни першими.
5) Симптом: Оформлення замовлення не працює, сторінка кошика — так
- Корінна причина: Несумісність платіжного шлюзу або плагіна доставки; суворіша типізація в PHP 8 викликає фатали в рідкісних краєвих випадках.
- Виправлення: Відтворіть через
/?wc-ajax=checkout, прочитайте PHP-помилки, оновіть плагін або замініть його. Не «просто підвищуйте таймаути».
6) Симптом: Раптовий стрибок CPU і повільні запити після оновлення
- Корінна причина: OPcache холодний старт, неправильна конфігурація JIT або знижена ефективність кешування через скидання; іноді плагін починає використовувати повільніший шлях під новим PHP.
- Виправлення: Прогрійте кеші, підтвердьте налаштування opcache, перевірте slowlog і порівняйте профілі запитів. Налаштовуйте пул FPM лише після відновлення правильності роботи.
7) Симптом: Завантаження зображень не працює або мініатюри відсутні
- Корінна причина: Відсутні
gdабоimagickу новій версії PHP; або різні версії бібліотек змінили поведінку. - Виправлення: Встановіть відповідні розширення, перезапустіть FPM, перевірте через
php -m, потім протестуйте завантаження знову.
8) Симптом: «Allowed memory size exhausted» з’являється частіше
- Корінна причина: Різні значення
memory_limitу FPM ini; зміни в поведінці плагіна; підвищена конкуренція збільшує пікове споживання пам’яті. - Виправлення: Підтвердьте
memory_limitдля FPM, налаштуйте його в реалістичних межах і проведіть аудит плагіна, що споживає пам’ять. Не латайте витоки нескінченним збільшенням пам’яті.
Чеклісти / покроковий план
Ось план, який я б запустив для продакшн-сайту WordPress, де простій неприйнятний, а звинувачення щедрі.
Дотримуйтесь порядку. Порядок — це суть.
Фаза 0: Визначте, що для вас означає «без простоїв»
- Ціль: Немає планованої сторінки обслуговування; існуючі сесії виживають; прийнятне невелике збільшення хвостової латентності.
- Необхідно: відкат за кілька хвилин, канар і видимість логів.
- Реальність: Якщо у вас один сервер без балансувальника, «без простоїв» стає «дуже короткий простій». Ви все одно можете бути обережними, але фізика перемагає.
Фаза 1: Інвентаризація рантайму, модулів і поверхні WordPress
- Занотуйте версію PHP-FPM, шлях ini, список модулів, налаштування opcache.
- Експортуйте список плагінів і тему.
- Визначте критичні потоки: логін, збереження в адмінці, оформлення замовлення, API-ендпоінти, cron.
- Підтвердьте, що можете відключити плагіни через WP-CLI, якщо wp-admin стане недоступним.
Фаза 2: Побудуйте staging-середовище, яке не є казкою
- Той самий код WordPress, ті самі плагіни, та сама тема.
- Ті самі рівні кешування (object cache, поведінка page cache), або принаймні розумійте різниці.
- Копіюйте БД продакшну (санітизовану) і репрезентативний шматок uploads.
- Використовуйте той самий клас конфігурації PHP-FPM (таймаути, налаштування пулу), щоб рано виявити проблеми з потужністю.
Фаза 3: Тестування сумісності, що дійсно знаходить проблеми
- Прогоніть топ-ендпоінти і критичні потоки під новим PHP.
- Зробіть ворнінги помітними у staging: увімкніть високий рівень error_reporting, збирання логів.
- Слідкуйте за TypeError, депрекейшенами в ключових шляхах, відсутніми розширеннями.
- Запустіть таргетований синтакс-скан плагінів і димові тести на ризикових плагінах (платежі, доставка, билдери).
Фаза 4: Канар у продакшні
- Підніміть один вузол з новим PHP (або переключіть один існуючий вузол).
- Направте на нього невеликий відсоток трафіку.
- Моніторте: rate 5xx, латентність, рестарти PHP-FPM, slowlog, використання пам’яті.
- Якщо з’являються помилки: виведіть канар з ротації, виправте проблему в staging і спробуйте знову.
Фаза 5: Розгортання й стабілізація після переключення
- Розгортайте поступово по флоту.
- Прогрійте кеші, щоб уникнути штампування навантаження.
- Тримайте старий PHP доступним, поки не пройдете повний бізнес-цикл (а не тільки 15 спокійних хвилин).
- Після стабілізації: видаліть старий рантайм, але збережіть артефакти відкату задокументованими (як швидко перевстановити, які пакети потрібні).
Поширені запитання
1) Як визначити, чи проблема WordPress — це несумісність PHP чи просто питання потужності?
Шукайте фатали й TypeError у логах PHP-FPM. Проблеми потужності проявляються таймаутами, «reached pm.max_children», повільними запитами і 502 без конкретного стек-трейсу.
Несумісність майже завжди залишає крихітку: шлях файлу, номер рядка й чіткий тип помилки.
2) Чи можна оновити PHP без оновлення ядра WordPress?
Іноді можна, але це погана ставка. Ядро загалом встигає за підтримуваними версіями PHP, але старе ядро плюс сучасний PHP підвищують ризик, що плагіни зачеплять нетестовані шляхи.
Оновіть ядро в staging перед PHP. Якщо не можете — принаймні перевірте точну версію ядра проти цільового PHP у staging з реальними робочими потоками.
3) Чому WP-CLI працює, а сайт падає?
WP-CLI використовує CLI SAPI і свій власний шлях до php.ini. Ваш сайт використовує PHP-FPM з іншими ini-налаштуваннями, іншими розширеннями і іншими правами користувача.
Завжди перевіряйте обидва. Різниця не академічна; саме там ховаються простріли.
4) Чи безпечно запускати дві версії PHP-FPM на одному сервері?
Так, якщо ви ізолюєте сокети/порти й конфіги для кожної версії. Це звична операційна практика для поетапних оновлень.
Ризик — це людська помилка: вказати Nginx на неправильний сокет або встановити модулі в одній версії і забути про іншу. Використовуйте керування конфігами й явні шляхи.
5) Який найшвидший відкат, якщо PHP 8.x ламає плагін?
Якщо старий FPM-сервіс залишився запущеним: переключіть upstream-сокет назад і зробіть reload Nginx/Apache. Це питання хвилин.
Якщо ні: перевстановлення пакетів, переконфігурація, рестарт сервісів — це вже інцидент, а не зміна.
6) Чи варто вмикати display_errors у продакшні, щоб бачити, що відбувається?
Ні. Логування помилок — так. Відображення помилок може витікати секрети і псувати відповіді в неприємний спосіб.
Використовуйте логи PHP-FPM, debug log WordPress (тимчасово) і централізоване логування. Якщо потрібно бачити більше — робіть це безпечно.
7) Чому я отримую 502 лише під час піків трафіку після оновлення?
Новий рантайм може мати інші характеристики продуктивності, або кеші скинулися й ви бачите холодний старт. Під навантаженням навіть невеликі уповільнення перетворюються на черги, а потім на таймаути.
Перевірте налаштування пулу FPM (pm.max_children), slowlog і таймаути апстріму.
8) Чи потрібно чистити OPcache при перемиканні версій PHP?
Якщо ви перемикаєте сокети між двома сервісами FPM, у кожного свій стан OPcache — перехресного забруднення не буде.
Якщо ви рестартуєте або рефрешите той самий сервіс після змін коду, скидання OPcache може запобігти дивному «старий код все ще виконується».
Але не нічищіть кеши по всьому флоту одночасно; це може спричинити штамп.
9) Які типи плагінів найнебезпечніші під час оновлень PHP?
Платіжні шлюзи, модулі доставки/податків, page builders, плагіни безпеки/фаєрволи і все, що бандлить великі бібліотеки вендорів.
Вони глибоко входять у шляхи запитів і часто роблять жорсткі припущення щодо типів і середовища сервера.
10) Якщо я не можу зробити канар, яка наступна найкраща річ?
Принаймні тримайте старий і новий PHP-FPM бок-о-бок на тому ж хості і перемикайте через конфіг, що можна reload-нути, з протестованим відкатом.
Якщо у вас один вузол, плануйте вікно з низьким трафіком і прийміть, що «без простоїв» стане «короткий простій», а ризик знижуйте через вичерпні тести у staging.
Висновок: практичні наступні кроки
Несумісність PHP — це не моральна вада. Це передбачуваний результат роботи великої екосистеми плагінів на рантаймі, що постійно підвищує коректність.
Ваше завдання — зробити оновлення нудним: інвентар, staging, канар, переключення й швидкий відкат у разі потреби.
- Сьогодні: Підтвердьте реальний веб-рантайм (версія FPM, проводка сокета) і централізуйте логи, які знадобляться під час інциденту.
- Цього тижня: Побудуйте staging, що відображає плагіни, кешування й робочі потоки продакшну. Тестуйте адмін і оформлення, а не лише головну сторінку.
- Наступне вікно змін: Запустіть паралельні PHP-FPM версії і канарьте один вузол. Слідкуйте за логами помилок і хвостовою латентністю. Рухайтесь вперед тільки при чистих сигналах.
- Після розгортання: Усуньте розбіжності версій, задокументуйте відкат і припиніть робити «дві зміни одночасно». Ваш майбутній я має достатньо хобі.