Въпреки факта, че PHP 5 достигна края на живота си, все още има наследени приложения, изградени върху него, които трябва да работят в производствена или тестова среда. Ако инсталирате PHP пакети чрез хранилище на операционна система, все още има шанс да се окажете с пакети PHP 5, напр. Операционна система CentOS 7. Като се има предвид това, винаги има начин да накарате вашите наследени приложения да работят с по-новите версии на базата данни и по този начин да се възползвате от новите функции.
В тази публикация в блога ще ви преведем как можем да стартираме PHP 5 приложения с най-новата версия на MySQL 8.0 на операционна система CentOS 7. Този блог се основава на действителен опит с вътрешен проект, който изисква приложението PHP 5 да работи заедно с нашия нов MySQL 8.0 в нова среда. Имайте предвид, че най-добре би било да стартирате най-новата версия на PHP 7 заедно с MySQL 8.0, за да се възползвате от всички значителни подобрения, въведени в по-новите версии.
PHP и MySQL на CentOS 7
Първо, нека видим какви файлове се предоставят от пакета php-mysql:
$ cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)
$ repoquery -q -l --plugins php-mysql
/etc/php.d/mysql.ini
/etc/php.d/mysqli.ini
/etc/php.d/pdo_mysql.ini
/usr/lib64/php/modules/mysql.so
/usr/lib64/php/modules/mysqli.so
/usr/lib64/php/modules/pdo_mysql.so
По подразбиране, ако сме инсталирали стандартните компоненти на стека LAMP, идват с CentOS 7, например:
$ yum install -y httpd php php-mysql php-gd php-curl mod_ssl
Ще получите инсталирани следните свързани пакети:
$ rpm -qa | egrep 'php-mysql|mysql|maria'
php-mysql-5.4.16-46.el7.x86_64
mariadb-5.5.60-1.el7_5.x86_64
mariadb-libs-5.5.60-1.el7_5.x86_64
mariadb-server-5.5.60-1.el7_5.x86_64
След това в PHP ще бъдат заредени следните модули, свързани с MySQL:
$ php -m | grep mysql
mysql
mysqli
pdo_mysql
Когато разглеждате версията на API, докладвана от phpinfo() за клиенти, свързани с MySQL, всички те са съпоставени с версията на MariaDB, която сме инсталирали:
$ php -i | egrep -i 'client.*version'
Client API version => 5.5.60-MariaDB
Client API library version => 5.5.60-MariaDB
Client API header version => 5.5.60-MariaDB
Client API version => 5.5.60-MariaDB
На този етап можем да заключим, че инсталираният php-mysql модул е изграден и съвместим с MariaDB 5.5.60.
Инсталиране на MySQL 8.0
Въпреки това, в този проект от нас се изисква да работим на MySQL 8.0, така че избрахме Percona Server 8.0, за да заменим съществуващата по подразбиране инсталация на MariaDB, която имаме на този сървър. За да направим това, трябва да инсталираме Percona Repository и да активираме хранилището Percona Server 8.0:
$ yum install https://repo.percona.com/yum/percona-release-latest.noarch.rpm
$ percona-release setup ps80
$ yum install percona-server-server
Въпреки това получихме следната грешка, след като изпълнихме последната команда:
--> Finished Dependency Resolution
Error: Package: 1:mariadb-5.5.60-1.el7_5.x86_64 (@base)
Requires: mariadb-libs(x86-64) = 1:5.5.60-1.el7_5
Removing: 1:mariadb-libs-5.5.60-1.el7_5.x86_64 (@anaconda)
mariadb-libs(x86-64) = 1:5.5.60-1.el7_5
Obsoleted By: percona-server-shared-compat-8.0.15-6.1.el7.x86_64 (ps-80-release-x86_64)
Not found
Error: Package: 1:mariadb-server-5.5.60-1.el7_5.x86_64 (@base)
Requires: mariadb-libs(x86-64) = 1:5.5.60-1.el7_5
Removing: 1:mariadb-libs-5.5.60-1.el7_5.x86_64 (@anaconda)
mariadb-libs(x86-64) = 1:5.5.60-1.el7_5
Obsoleted By: percona-server-shared-compat-8.0.15-6.1.el7.x86_64 (ps-80-release-x86_64)
Not found
You could try using --skip-broken to work around the problem
You could try running: rpm -Va --nofiles --nodigest
Горното просто означава, че споделеният пакет за сървър на Percona ще отмени mariadb-libs-5.5.60, който се изисква от вече инсталираните пакети mariadb-server. Тъй като това е обикновен нов сървър, премахването на съществуващите пакети MariaDB не е голям проблем. Нека първо ги премахнем и след това да опитаме да инсталираме Percona Server 8.0 още веднъж:
$ yum remove mariadb mariadb-libs
...
Resolving Dependencies
--> Running transaction check
---> Package mariadb-libs.x86_64 1:5.5.60-1.el7_5 will be erased
--> Processing Dependency: libmysqlclient.so.18()(64bit) for package: perl-DBD-MySQL-4.023-6.el7.x86_64
--> Processing Dependency: libmysqlclient.so.18()(64bit) for package: 2:postfix-2.10.1-7.el7.x86_64
--> Processing Dependency: libmysqlclient.so.18()(64bit) for package: php-mysql-5.4.16-46.el7.x86_64
--> Processing Dependency: libmysqlclient.so.18(libmysqlclient_18)(64bit) for package: perl-DBD-MySQL-4.023-6.el7.x86_64
--> Processing Dependency: libmysqlclient.so.18(libmysqlclient_18)(64bit) for package: 2:postfix-2.10.1-7.el7.x86_64
--> Processing Dependency: libmysqlclient.so.18(libmysqlclient_18)(64bit) for package: php-mysql-5.4.16-46.el7.x86_64
--> Processing Dependency: mariadb-libs(x86-64) = 1:5.5.60-1.el7_5 for package: 1:mariadb-5.5.60-1.el7_5.x86_64
---> Package mariadb-server.x86_64 1:5.5.60-1.el7_5 will be erased
--> Running transaction check
---> Package mariadb.x86_64 1:5.5.60-1.el7_5 will be erased
---> Package perl-DBD-MySQL.x86_64 0:4.023-6.el7 will be erased
---> Package php-mysql.x86_64 0:5.4.16-46.el7 will be erased
---> Package postfix.x86_64 2:2.10.1-7.el7 will be erased
Премахването на mariadb-libs ще премахне и други пакети, които зависят от това, от системата. Основната ни грижа са пакетите php-mysql, които ще бъдат премахнати поради зависимостта от libmysqlclient.so.18, предоставена от mariadb-libs. Ще поправим това по-късно.
След това би трябвало да можем да инсталираме Percona Server 8.0 без грешка:
$ yum install percona-server-server
В този момент ето пакети, свързани с MySQL, които имаме в сървъра:
$ rpm -qa | egrep 'php-mysql|mysql|maria|percona'
percona-server-client-8.0.15-6.1.el7.x86_64
percona-server-shared-8.0.15-6.1.el7.x86_64
percona-server-server-8.0.15-6.1.el7.x86_64
percona-release-1.0-11.noarch
percona-server-shared-compat-8.0.15-6.1.el7.x86_64
Забележете, че нямаме пакети php-mysql, които предоставят модули за свързване на нашето PHP приложение с нашия прясно инсталиран сървър Percona Server 8.0. Можем да потвърдим това, като проверим заредения PHP модул. Трябва да получите празен изход със следната команда:
$ php -m | grep mysql
Нека го инсталираме отново:
$ yum install php-mysql
$ systemctl restart httpd
Сега ги имаме и са заредени в PHP:
$ php -m | grep mysql
mysql
mysqli
pdo_mysql
И можем също да потвърдим това, като разгледаме информацията за PHP чрез командния ред:
$ php -i | egrep -i 'client.*version'
Client API version => 5.6.28-76.1
Client API library version => 5.6.28-76.1
Client API header version => 5.5.60-MariaDB
Client API version => 5.6.28-76.1
Забележете разликата във версията на библиотеката на клиентския API и версията на заглавката на API. Ще видим последващия ефект от това по-късно по време на теста.
Нека стартираме нашия MySQL 8.0 сървър, за да изпробваме нашето PHP5 приложение. Тъй като накарахме MariaDB да използва datadir в /var/lib/mysql, първо трябва да го изтрием, да инициализираме отново datadir, да зададем правилна собственост и да го стартираме:
$ rm -Rf /var/lib/mysql
$ mysqld --initialize
$ chown -Rf mysql:mysql /var/lib/mysql
$ systemctl start mysql
Вземете временната парола за MySQL root, генерирана от Percona Server от регистрационния файл за грешки на MySQL:
$ grep root /var/log/mysqld.log
2019-07-22T06:54:39.250241Z 5 [Note] [MY-010454] [Server] A temporary password is generated for [email protected]: 1wAXsGrISh-D
Използвайте го, за да влезете по време на първото влизане на потребителя [email protected] Трябва да променим временната парола на нещо друго, преди да можем да извършим каквото и да било по-нататъшно действие на сървъра:
$ mysql -uroot -p
mysql> ALTER USER [email protected] IDENTIFIED BY 'myP455w0rD##';
След това продължете да създавате ресурсите на нашата база данни, изисквани от нашето приложение:
mysql> CREATE SCHEMA testdb;
mysql> CREATE USER [email protected] IDENTIFIED BY 'password';
mysql> GRANT ALL PRIVILEGES ON testdb.* TO [email protected];
След като приключите, импортирайте съществуващите данни от архивиране в базата данни или създайте ръчно обекти на базата данни. Нашата база данни вече е готова за използване от нашето приложение.
Грешки и предупреждения
В нашето приложение имахме прост тестов файл, за да се уверим, че приложението може да се свърже чрез сокет или с други думи, localhost на порт 3306, за да елиминира всички връзки към базата данни през мрежа. Веднага ще получим предупреждение за несъответствие на версията:
$ php -e test_mysql.php
PHP Warning: mysqli::mysqli(): Headers and client library minor version mismatch. Headers:50560 Library:50628 in /root/test_mysql.php on line 9
В същото време ще срещнете и грешката при удостоверяване с php-mysql модула:
$ php -e test_mysql.php
PHP Warning: mysqli::mysqli(): (HY000/2059): Authentication plugin 'caching_sha2_password' cannot be loaded: /usr/lib64/mysql/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory in /root/test_mysql.php on line 9
Или, ако сте работили с MySQL собствена библиотека с драйвери (php-mysqlnd), ще получите следната грешка:
$ php -e test_mysql.php
PHP Warning: mysqli::mysqli(): The server requested authentication method unknown to the client [caching_sha2_password] in /root/test_mysql.php on line 9
Освен това ще има и друг проблем, който ще видите по отношение на набора от знаци:
PHP Warning: mysqli::mysqli(): Server sent charset (255) unknown to the client. Please, report to the developers in /root/test_mysql.php on line 9
Решения и заобиколни решения
Плъгин за удостоверяване
Нито библиотеката php-mysqlnd, нито php-mysql за PHP5 поддържа новия метод за удостоверяване за MySQL 8.0. Започвайки от MySQL 8.0.4 методът за удостоверяване е променен на „caching_sha2_password“, който предлага по-сигурно хеширане на паролата в сравнение с „mysql_native_password“, който е по подразбиране в предишните версии.
За да позволите обратна съвместимост на нашия MySQL 8.0. В конфигурационния файл на MySQL добавете следния ред в секцията [mysqld]:
default-authentication-plugin=mysql_native_password
Рестартирайте MySQL сървъра и трябва да сте добре. Ако потребителят на базата данни е създаден преди горните промени, например чрез архивиране и възстановяване, създайте отново потребителя, като използвате операторите DROP USER и CREATE USER. MySQL ще следва новия плъгин за удостоверяване по подразбиране, когато създава нов потребител.
Незначително несъответствие на версията
С пакета php-mysql, ако проверим инсталираната версия на библиотеката, ще забележим разликата:
$ php -i | egrep -i 'client.*version'
Client API version => 5.6.28-76.1
Client API library version => 5.6.28-76.1
Client API header version => 5.5.60-MariaDB
Client API version => 5.6.28-76.1
PHP библиотеката е компилирана с MariaDB 5.5.60 libmysqlclient, докато клиентската API версия е на версия 5.6.28, предоставена от пакета percona-server-shared-compat. Въпреки предупреждението, все още можете да получите правилен отговор от сървъра.
За да потиснете това предупреждение при несъответствие на версията на библиотеката, използвайте пакет php-mysqlnd, който не зависи от библиотеката на MySQL Client Server (libmysqlclient). Това е препоръчителният начин, както е посочено в документацията на MySQL.
За да замените библиотеката php-mysql с php-mysqlnd, просто изпълнете:
$ yum remove php-mysql
$ yum install php-mysqlnd
$ systemctl restart httpd
Ако подмяната на php-mysql не е опция, последното средство е ръчно компилиране на PHP с библиотеката на MySQL 8.0 Client Server (libmysqlclient) и копиране на компилираните библиотечни файлове в директорията /usr/lib64/php/modules/, като замените стария mysqli. така, mysql.so и pdo_mysql.so. Това е малко проблем с малък шанс за успех, най-вече поради оттеглените зависимости на заглавните файлове в текущата версия на MySQL. Необходими са познания по програмиране, за да се заобиколи това.
Несъвместим набор от знаци
Започвайки от MySQL 8.0.1, MySQL промени набора от символи по подразбиране от latin1 на utf8mb4. Наборът от символи utf8mb4 е полезен, защото в днешно време базата данни трябва да съхранява не само езикови знаци, но и символи, нововъведени емоджи и т.н. Charset utf8mb4 е UTF-8 кодиране на набора от символи Unicode, използвайки един до четири байта на знак, в сравнение със стандартния utf8 (известен още като utf8mb3), който използва един до три байта на знак.
Много наследени приложения не са изградени върху набор от символи utf8mb4. Така че би било добре да променим настройката на символите за MySQL сървъра на нещо разбираемо от нашия наследен PHP драйвер. Добавете следните два реда в конфигурацията на MySQL в секцията [mysqld]:
collation-server = utf8_unicode_ci
character-set-server = utf8
По желание можете също да добавите следните редове в конфигурационния файл на MySQL, за да рационализирате целия клиентски достъп за използване на utf8:
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
Не забравяйте да рестартирате MySQL сървъра, за да влязат в сила промените. В този момент нашето приложение трябва да се разбира с MySQL 8.0.
Това е всичко за сега. Споделете всякаква обратна връзка с нас в секцията за коментари, ако имате други проблеми с преместването на наследени приложения към MySQL 8.0.