PHP7からPHP8、Phalcon3からPhalcon5にアップグレードした作業ログ!

PHP7.1からPHP8.1に、Phalcon3.2からPhalcon5.2にアップグレード。

アップグレード前の環境

  • PHP7.1
  • Phalcon3.2
  • Zephir0.10
  • CentOS
  • Nginx

アップグレード後の環境

  • PHP8.1
  • Phalcon5.2
  • Zephir0.17
  • CentOS
  • Nginx

現バージョンの確認

# phpの現パージョン確認
$ php -v
PHP 7.1.33 (cli) (built: Sep 29 2020 09:53:22) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.1.33, Copyright (c) 1999-2018, by Zend Technologies

# phalconの現バージョン確認
$ php -r "echo Phalcon\Version::get();"
3.2.2

PHP7からPHP8へアップグレード

PHP設定ファイルのバックアップ

# php.iniのバックアップ
$ cp /etc/php.ini /etc/php.ini.yyyymmdd

# php-fpm.d/www.confのバックアップ
$ cp /etc/php-fpm.d/www.conf /etc/php-fpm.d/www.conf.yyyymmdd

現在のPHPのパッケージ確認

phpアップデートするときに同じの入れるのでメモっておく。

続きを読む

phalcon3から5にバージョンアップした際のDB関連の対応

phalcon3から5にバージョンアップした際にDB周りで発生したHTTP ERROR 500やDeprecated対応

Service Mysql is not registered

FastCGI sent in stderr: "PHP message: Service Mysql is not registered
#0 [internal function]: Phalcon\Factory\AbstractConfigFactory->getException()
#1 [internal function]: Phalcon\Factory\AbstractFactory->getService()
#2 [internal function]: Phalcon\Db\Adapter\PdoFactory->newInstance()
#3 /web/dev/ttonosaki/juku/app/settings/services.php(28): Phalcon\Db\Adapter\PdoFactory->load()
#4 [internal function]: Closure->{closure}()
#5 [internal function]: Phalcon\Di\Service->resolve()
#6 [internal function]: Phalcon\Di\Di->get()
#7 [internal function]: Phalcon\Di\Di->getShared()
#8 [internal function]: Phalcon\Mvc\Model\Manager->getConnection()
#9 [internal function]: Phalcon\Mvc\Model\Manager->getReadConnection()

DBの設定(config)でadapterの指定がMysqlからmysqlに変わったようなので修正。

-adapter = Mysql
+adapter = mysql

https://docs.phalcon.io/5.0/ja-jp/db-layer#load

SQLSTATE[HY000] [2002] No such file or directory

MySQLに接続できないエラー

FastCGI sent in stderr: "PHP message: SQLSTATE[HY000] [2002] No such file or directory
#0 [internal function]: PDO->__construct()
#1 [internal function]: Phalcon\Db\Adapter\Pdo\AbstractPdo->connect()
#2 [internal function]: Phalcon\Db\Adapter\Pdo\AbstractPdo->__construct()
#3 [internal function]: Phalcon\Db\Adapter\Pdo\Mysql->__construct()
#4 [internal function]: Phalcon\Db\Adapter\PdoFactory->newInstance()
#5 {pathto}/app/settings/services.php(31): Phalcon\Db\Adapter\PdoFactory->load()

PdoFactory->load()に渡すconfigの形式が変わったようです。
iniファイルをそのままconfigとして受けたしてもダメだったので以下のように修正。

-return (new PdoFactory())->load($config->database);
+return (new PdoFactory())->load([
+    'adapter'  => $config->database->adapter,
+    'options' => [
+        'host'     => $config->database->host,
+        'username' => $config->database->username,
+        'password' => $config->database->password,
+        'dbname'   => $config->database->dbname
+    ]
+]);

マニュアルを見る感じではiniファイルで設定した値をそのまま渡してもよさそうな記述でした。
https://docs.phalcon.io/5.0/ja-jp/db-layer#load

githubでコメントを見ると、マニュアルとは違う形式で受け取る内容がコメントに記載してありました。
https://github.com/phalcon/cphalcon/blob/v5.2.1/phalcon/Db/Adapter/PdoFactory.zep#L29-L41

Call to undefined method Criteria::addWhere()

Call to undefined method Phalcon\Mvc\Model\Criteria::addWhere()

phalcon v4でCriteria::addWhere()は削除されました。
https://docs.phalcon.io/4.0/ja-jp/upgrade#mvcmodelcriteria

andWhere()に変更

そのほかのアップグレードで発生したエラー対応

phalcon3から5にバージョンアップした際のMVC、Loaderの対応

phalcon3から5にバージョンアップした際にMVC・Module周り、Loaderで発生したHTTP ERROR 500やDeprecated対応

Phalcon\Loader not found

FastCGI sent in stderr: "PHP message: PHP Fatal error:  Uncaught Error: Class "Phalcon\Loader" not found in {path}

Phalcon\LoaderがPhalcon\Autoload\Loaderに変わったので修正。
https://docs.phalcon.io/5.0/ja-jp/upgrade > 一般的なメモ

Call to undefined method Loader::registerNamespaces()

FastCGI sent in stderr: "PHP message: PHP Fatal error:  Uncaught Error: Call to undefined method Phalcon\Autoload\Loader::registerNamespaces() in {path}

registerNamespaces()がsetNamespaces()にリネームされたので修正。
https://docs.phalcon.io/5.0/ja-jp/upgrade#autoload

Call to undefined method Loader::registerClasses()

FastCGI sent in stderr: "PHP message: PHP Fatal error:  Uncaught Error: Call to undefined method Phalcon\Autoload\Loader::registerClasses() in {path}

registerClasses()がsetClasses()にリネームされたので修正。
https://docs.phalcon.io/5.0/ja-jp/upgrade#autoload

Mvc\Application::handle() expects exactly 1 argument, 0 given

FastCGI sent in stderr: "PHP message: PHP Fatal error:  Uncaught ArgumentCountError: Phalcon\Mvc\Application::handle() expects exactly 1 argument, 0 given in {path}

handle()に$_SERVER["REQUEST_URI"]を渡す必要があるので、handle()の引数に$_SERVER["REQUEST_URI"]を追加。

-handle()
+handle($_SERVER["REQUEST_URI"])

https://docs.phalcon.io/5.0/ja-jp/application > 概要

ついでにhandle()周りの返却方法も変わっていたので修正。

続きを読む

phalcon3から5にバージョンアップした際のログイン、Securityの対応

phalcon3から5にバージョンアップした際にログイン回りで発生したエラー、Deprecated対応

Phalcon\Security not found

Class "Phalcon\Security" not found

https://docs.phalcon.io/5.0/ja-jp/upgrade#%E4%B8%80%E8%88%AC%E7%9A%84%E3%81%AA%E3%83%A1%E3%83%A2

「Phalcon\Security」から「Phalcon\Encryption\Security」に変更になったので、use文を変更。

Deprecated: Phalcon\Encryption\Security::checkHash()

[08-Jun-2023 10:06:48 UTC] PHP Warning:  Attempt to read property "password" on null in /{pathto}/app/controllers/IndexController.php on line 83
[08-Jun-2023 10:06:48 UTC] PHP Deprecated:  Phalcon\Encryption\Security::checkHash(): Passing null to parameter #2 ($passwordHash) of type string is deprecated in /{pathto}/app/library/util/Hash.php on line 49

ユーザー情報を取得できなかった場合に、比較するパスワードがnullのためエラーになっています。
ユーザー情報を取得できなかった場合、checkHash()しないようにしていたが、チェックが走るようになってしまっているのが原因。

findFirst()でユーザー情報を取得していたのだが、データがなかった場合にfindFirst()はfalseではなくnullを返すように変更されていました。
なので「$userData !== false」で比較していたところを「$userData !== null」に変更。

undefined method Session\Manager::isStarted()

Call to undefined method Phalcon\Session\Manager::isStarted()

sessionが開始しているかはisStarted()ではなくexists()を使う
https://docs.phalcon.io/5.0/ja-jp/session#exists

The session save path [/var/lib/php/session] is not writable

The session save path [/var/lib/php/session] is not writable

Sessionの保存先に書き込み権限がないので、権限付与かディレクトリのユーザー変更

今回は、/etc/php-fpm.d/www.confでUserとGroupをnginxに設定しているので、User:root,Group:apacheをnginxに変更

$ chown nginx:nginx /var/lib/php/session

そのほかのアップグレードで発生したエラー対応

phalcon3から5にバージョンアップした際のformの対応

phalcon3から5にバージョンアップした際にページネーションで発生したエラー、Deprecated対応

unexpected token "=>", expecting ")"

syntax error, unexpected token "=>", expecting ")"
#0 [internal function]: Phalcon\Mvc\View\Engine\Volt->render()
#1 [internal function]: Phalcon\Mvc\View->engineRender()
#2 [internal function]: Phalcon\Mvc\View->processRender()
#3 [internal function]: Phalcon\Mvc\View->render()
#4 {pathto}/public/index.php(30): Phalcon\Mvc\Application->handle()
#5 {main}

voltのform()の引数が変わったためにエラー。

引数を配列で渡せばOK

before

{{ form('login', 'id': 'loginForm', 'class': 'bf_form', 'onbeforesubmit': 'return false') }}

after

{{ form(['action': 'login', 'id': 'loginForm', 'class': 'bf_form', 'onbeforesubmit': 'return false']) }}

ただしこのままだと出力されるActionが変わってしまいます。
https://{ドメイン}/xxxxx だったのが、ドメイン無しのxxxxxになります。

今まで通りのActionで出力したい場合は、url()かformLegacy()を使用。

url()を使う場合は、form()の関数名はそのままで、'action'のパラメータにurl()を使用

{{ form(['action': url('login'), 'id': 'loginForm', 'class': 'bf_form', 'onbeforesubmit': 'return false']) }}

formLegacy()を使う場合は、'action'のパラメータはそのままで、form()の関数名を変更

{{ formLegacy(['action': 'login', 'id': 'loginForm', 'class': 'bf_form', 'onbeforesubmit': 'return false']) }}

formLegacy()について
https://docs.phalcon.io/5.0/ja-jp/upgrade#volt

Validator\PresenceOf not found

Class "Phalcon\Validation\Validator\PresenceOf" not found

phalcon 5.0のバリデーションのマニュアルを見るとClassの場所が変わっていました。
なのでuse文を変更。

-use Phalcon\Validation\Validator\PresenceOf;
+use Phalcon\Filter\Validation\Validator\PresenceOf;

Validator\Email not found

Class "Phalcon\Validation\Validator\Email" not found

PresenceOfと同様にClassの場所が変わっています。
use文を変更。

-use Phalcon\Validation\Validator\Email;
+use Phalcon\Filter\Validation\Validator\Email;

基本的にPhalcon\ValidationはPhalcon\Filter\Validationに移動されているようです。

checkboxにデフォルトチェックがつかない

エラーログは出ていませんでしたが、checkboxにデフォルトチェックがついていませんでした。
input要素をレンダリングする際のcheckedオプションの指定方法が変わったようです。

デフォルトチェックをつける場合、checkedオプションに'checked'を設定していましたが、valueと同じ値を設定する必要があるようです。

-{{ form.render('category', ['value': categoryId, 'checked':(postCategoryId === categoryId) ? 'checked':null]) }}
+{{ form.render('category', ['value': categoryId, 'checked':(postCategoryId === categoryId) ? categoryId:null]) }}

https://docs.phalcon.io/5.0/ja-jp/upgrade#phalconformselementcheck

そのほかのアップグレードで発生したエラー対応