Надіслати запит

Legacy PHP · 3 хв читання

З PHP 5 на PHP 8, не зупиняючи магазин

Дві версії PHP поруч на одному сервері, поки код переїжджає частина за частиною.

На цій сторінці
  1. Чому б просто не перемкнути?
  2. Крок 1: копія і карта
  3. Крок 2: страховка
  4. Крок 3: дві версії на одному сервері
  5. Крок 4: невеликі кроки
  6. Може, краще переписати?
  7. Скільки це триває?

Лист від хостинг-компанії ввічливий і остаточний: 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. Тож ми починаємо з нього: невеликий аудит за фіксованою ціною, який закінчується планом і ціною за решту.

Якщо лист від хостинг-компанії вже прийшов, надішліть нам запит.

Хочете так само у себе?

Два питання й адреса електронної пошти. Відповідаємо протягом двох робочих днів, зазвичай швидше.

Надіслати запит →