Legacy PHP · 3 хв читання
З PHP 5 на PHP 8, не зупиняючи магазин
Дві версії PHP поруч на одному сервері, поки код переїжджає частина за частиною.
На цій сторінці
Лист від хостинг-компанії ввічливий і остаточний: PHP 5.6 вимкнуть наприкінці кварталу. Магазин працює на коді 2012 року, нікого з авторів поруч немає, а замовлення надходять щодня. Перемкнути версію й сподіватися — не план. Переписати все з нуля — план, але зазвичай поганий.
Ось як це робимо ми: обидві версії працюють поруч, а код переїжджає невеликими частинами, кожна перевірена окремо.
Чому б просто не перемкнути?
Бо багато чого, що PHP 5 приймав, PHP 8 відкидає, і зазвичай фатальною помилкою, а не попередженням. Звичні підозрювані:
| Що робить старий код | Що з цим сталося |
|---|---|
mysql_query() та решта mysql_* |
видалено в PHP 7.0; використовуйте PDO або mysqli |
ereg(), split() |
видалено в PHP 7.0; використовуйте preg_* |
each(), create_function() |
видалено в PHP 8.0 |
| конструктор з назвою класу | ігнорується з PHP 8.0; об’єкт створюється без нього |
0 == "abc" дорівнює true |
з PHP 8.0 це false, що непомітно змінює деякі if |
| властивості, додані до об’єктів на льоту | застаріле з PHP 8.2 |
null, переданий у strlen(), trim() і подібні |
застаріле з PHP 8.1 |
Перші три зупиняють сайт. Останні чотири гірші: сайт працює далі, але робить трохи не те.
Крок 1: копія і карта
На робочому сервері нічого не відбувається. Ми беремо копію коду й анонімізовану копію бази даних, розгортаємо їх на тестовому сервері й читаємо код. Тут два інструменти заощаджують дні:
- PHPCompatibility, набір правил для PHP_CodeSniffer, показує кожен рядок, який зламається на певній версії PHP.
- Rector автоматично переписує багато з цих рядків, наприклад старий синтаксис масивів чи видалені функції.
Жоден із них не замінює читання. Вони дають карту; маршрут обирає людина. Результат цього кроку — письмовий список: що ламається, де, наскільки це ризиковано і з чого почати.
Крок 2: страховка
Перш ніж щось змінювати, ми переконуємося, що помітимо, якщо щось зламається:
- резервні копії, які ми справді один раз відновили на тестовому сервері;
- короткий список сценаріїв, що приносять гроші: пошук, кошик, оформлення замовлення, лист з рахунком, експорт в адмінці;
- перевірка для кожного сценарію: автоматична там, де це дешево, і записана там, де ні.
Крок 3: дві версії на одному сервері
На сервері родини Red Hat (AlmaLinux, Rocky, RHEL) репозиторій Remi встановлює кілька версій PHP поруч, кожну з власною службою php-fpm. Далі nginx спрямовує кожну частину сайту на ту версію, до якої вона готова:
# нова, перевірена частина працює на PHP 8
location ^~ /checkout/ {
fastcgi_pass unix:/var/opt/remi/php85/run/php-fpm/www.sock;
include fastcgi.conf;
}
# усе інше поки що працює на PHP 5.6
location ~ \.php$ {
fastcgi_pass unix:/opt/remi/php56/root/var/run/php-fpm/www.sock;
include fastcgi.conf;
}
Шляхи до сокетів залежать від налаштувань кожного пулу; головне — сама ідея. Сайт увесь час працює, а кожна частина переїжджає, коли готова, а не коли так каже календар.
Крок 4: невеликі кроки
По одній частині: перетворити, перевірити на тестовому сервері, випустити в тиху годину, добу стежити за журналами. Потім наступна частина. Зазвичай першим іде шар роботи з базою даних, бо від нього залежить майже все і бо саме в mysql_* живуть діри в безпеці:
// до
$res = mysql_query("SELECT * FROM orders WHERE id=" . $_GET['id']);
// після
$stmt = $db->prepare('SELECT * FROM orders WHERE id = ?');
$stmt->execute([(int) $_GET['id']]);
Коли переїхала остання частина, PHP 5.6 вимикають, і ніхто цього не помічає. Це і є мета.
Може, краще переписати?
Рідко. Старий код негарний, але в ньому роки виправлених помилок і бізнес-правил, які ніхто не записав. Переписування викидає все це, і його доводиться знаходити знову, зазвичай уже на робочому сайті. Ми пропонуємо переписати, лише коли карта з кроку 1 показує, що так дешевше, і тоді кажемо про це письмово.
Скільки це триває?
Це залежить від обсягу коду й від того, скільки сюрпризів він ховає, а саме це і з’ясовує крок 1. Тож ми починаємо з нього: невеликий аудит за фіксованою ціною, який закінчується планом і ціною за решту.
Якщо лист від хостинг-компанії вже прийшов, надішліть нам запит.
Хочете так само у себе?
Два питання й адреса електронної пошти. Відповідаємо протягом двох робочих днів, зазвичай швидше.