2018年7月10日火曜日

【備忘録】PHP7.0.x --> 7.2.7 へのアップグレード

WordPress も 7.2以上を推奨しましたし、そろそろやらないとなーということでアップグレードしました。ソースからコンパイルしているため、何度か失敗したこと、PHP更新はいろいろなところに影響が波及するので纏まって時間ができたときにーって思っていたら大幅に遅れたのでした。

情報収集



を見て、PHP7.0からの変更点を流し読み。
基本的にアップグレードするサーバー上で PHPを利用しているのは、WordPressといくつかのウェブサイトでした。ウェブサイトも筆者がコーディングしたPHPなので何か問題があっても対処可能。WordPress もプラグインで何かおかしい物が出てくるかもしれませんが、それほど古いものは使っていないし対処できるでしょうということで、エイヤって更新することにしました。

一番気をつけるのは count 関数の型が object と 配列に限定されたことでしょうか。文字列のカウントに count は使っちゃ駄目よってことですね。
これ関係でWordPressコアで警告でていたのですが(後述)、コアのコードは型もあってるはずなのになぁとは思いました。

ソースからコンパイルしてインストール


今回ソースからコンパイルしてバージョンごとに別のフォルダにインストールするので、手軽に前のバージョンに戻すことができます。そのためインストールまでは現環境に影響を与えません。現時点では PHP 7.2.7 が最新版だったのでこれをダウンロードします。

以下、その他いろいろなオプションをつけていますが、そのうちいくつかのみ紹介します。当方は libssl として LibreSSLをメインに使っていて、nginx, postfix は LibreSSLライブラリを使っています。しかしPHPではどうしてもうまく行かなったので、仕方なく Red Hat Enterprise Linux 標準のもの(/usr/lib64)をとりあえずつかうことにします。

あと、iconv を別途 /usr/local 以下にインストールして、これも使えるようにするために、オプションと make 時のライブラリ指定もしてます。

また、設定ファイルは共通の場所を指定するようにしてます。

なお下記の ./configure のオプションは一部のみ抜粋しています。このままやったら足りないものがいろいろあります(mysql 関連、gettext 、png, jpeg, freetype, pcre-regex、その他もろもろ)

./configure \
  --prefix=/usr/local/php-7.2.7 \
  --with-config-file-path=/etc/php7.d \
  --enable-opcache \
  --with-libdir=lib64 \
  --enable-mbstring \
  --enable-fpm \
  --with-openssl=shared \
  --with-iconv-dir=/usr/local \
  --with-gd \
  --with-gnu-ld \
  --enable-gd-jis-conv

make ZEND_EXTRA_LIBS='-liconv'

make install

というか筆者の環境を LibreSSL メインにしてしまったことで、いろいろややこしいことになってるんですよね(【備忘録】Postfix 3.2.2 と Nginx 1.13.4 に LibreSSL を組み込んでコンパイルしてアップグレード


参考


指摘

  --with-mcrypt

って PHP7.2 から廃止されたんじゃとSNSで指摘を受けました。確かに!
PHP7.1 へアップグレードしようかなーと思っていた時期、PHP 7.1.x で推奨されなくなる機能をみて、廃止されるのかぁと思っていたのを思い出しました。すっかり忘れてました。

実際
/usr/local/php-7.2.7/bin/php -m でも mcrypt はモジュールとして読み込まれていませんでした。/usr/local/php-7.0.*/bin/php -m では mcrypt として読み込まれていたのですよね。他にもいらないオプションもありそうな気がしますねぇ。とりあえず警告をなくすことを優先しつつ、もう少し調べねば!

APCu モジュールのインストールと有効化


pecl 経由では下記のようになってエラーなったので、別途ソースからコンパイルしてインストールした。

1. https://pecl.php.net/package/APCu から 5.1.11 をダウロードして展開
2. ./configure --enable-apcu --with-php-config=/usr/local/php-7.2.7/bin/php-config
3. make
4. make install

で、/usr/local/php-7.2.7/lib/php/年月日/apcu.so にインストールされる。

確認方法


/usr/local/php-7.2.7/bin/php -m | grep apcu
apcu

のように、apcu がモジュールとして組み込まれていたらOK。
もともと 
php.ini において
[apcu]
extension=apcu.so
などのようにモジュールは読み込むようにしている必要あり。


(没)pecl 経由でのインストールしたらエラーに

おそらく先に php を入れ替えてからしないとダメかもしれない。しかし、入れ替え前に導入できていないと、入れ替え時が面倒ですからね。

cd /usr/local/php-7.2.7
cd bin
./pecl install APCu

running: make INSTALL_ROOT="/tmp/pear/temp/pear-build-kitaniTzjBcB/install-apcu-5.1.11" install
Installing shared extensions: /tmp/pear/temp/pear-build-kitaniTzjBcB/install-apc\
u-5.1.11/usr/local/php-7.2.7/lib/php/20170718/
Installing header files: /tmp/pear/temp/pear-build-kitaniTzjBcB/install-apc\
u-5.1.11/usr/local/php-7.2.7/include/php/
running: find "/tmp/pear/temp/pear-build-kitaniTzjBcB/install-apcu-5.1.11" | xargs ls -dils
xargs: ls: シンボリックリンクの階層が多すぎます
ERROR: `find "/tmp/pear/temp/pear-build-kitaniTzjBcB/install-apcu-5.1.11" | xargs ls-dils' failed


OpenSSL モジュールの有効化


/usr/local/php-7.2.7/lib/php/年月日/openssl.so
/usr/local/php-7.2.7/lib/php/年月日/openssl.a

の2つが出来ているはず。

php.ini に
extension=openssl.so
を追加しておけばよい。

確認方法


/usr/local/php-7.2.7/bin/php -m | grep ssl
openssl

のように、openssl がモジュールとして組み込まれていること、
ldd /usr/local/php-7.2.7/bin/php | grep ssl

libssl.so.** => /usr/lib64/libssl.so.***

libssl**.so => /usr/lib64/libssl**.so
のように libssl が php にライブラリとして組み込まれていることを確認。

PHP 7.0 から 7.2 へのアップグレード手順


以上のように、PHP 7.2に APCu と OpenSSL モジュール、そして/usr/local/php-7.2.7/bin/php -v にて、  Zend OPcache が組み込まれていることが確認できれば、ようやくアップグレードになります。

筆者の環境では
/usr/local/php7 以下が phpの prefix フォルダ
/etc/php7.d が phpのetcフォルダに設定しています。
その状況では

/etc/init.d/php-fpm stop

cd /usr/local
rm php7
ln -s php-7.2.7  php7
cd php7
mv etc etc.org 
ln -s /etc/php7.d etc

のように、php-fpm を停止した上で、

/usr/local/php-7.2.7 --> /usr/local/php7 
/usr/local/php-7.2.7/etc --> /etc/php7.d (念の為)

のシンボリックリンクをはる。そして、

/etc/init.d/php-fpm start

*これでエラーが出るようなら、php-fpm のプロセスが残っていることを意味します。
即時停止したいなら、少し乱暴ではありますが、
killall  php-fpm 
とプロセスを全部切ってしまうこともできます(ただ編集中の人がいないこと前提)。
筆者のケースではあまり大規模じゃないこと、編集者に全員事前に知らせてあることもあるのでサクッとやっちゃったって感じです。

/etc/init.d/nginx restart

NGINXも再起動しておきます。


PhpMyAdmin で警告がでる


WordPress について count関数絡みでエラーがでますね。
PHP 7.2 からは Object と 配列しか count は使えなくなったことを受けての警告かな。

とりあえずバージョンアップせよってことかな。


最近版は、phpMyAdmin-4.8.2-all-languages なのでこれを導入しました。
以前は、 4.6系を使っていました。IP限定の上にSSL暗号化していて、筆者以外誰も使えないようにしているという条件下なので、あまり頻繁にバージョンアップしていなかったのでした。


を参考に

$cfg['blowfish_secret'] = 'ユニーク文字';
$cfg['PmaAbsoluteUri'] = 'https://◯◯/phpmyadmin';

を設定。ユニーク文字は、32文字以上だということなので、それだけ注意。
あとphpmyadmin をサブディレクトリに置く場合には、PmaAbsoluteIUriパラメータを追加すること。

頭文字_乱数(sha1)

として乱数(sha1)は、

od -vAn -N4 -tu4 < /dev/urandom | sha1sum

で生成しました。

あと
$cfg['Servers'][$i]['AllowRoot'] = false;
あたりを加えて rootでのログインを禁止する設定もセキュリティ的にやっておいたほうがいい。

アクセスしたら真っ白ー

jsファイルが読み込めないだとぅ。

nginx の phpmyadmin 専用設定に
 location ~* \.(jpe?g|gif|png|ico|css|js)$ {
 }
の |js 部分を追加。nginx として js拡張子にアクセスできるようにするよってこと。しかし前のバージョンで

ということでめでたく更新完了。
エラーも出なくなってますね!

WordPress の予約投稿の即時反映がうまくいかない。


いくつかのサイトで、予約投稿を即時公開したいものがあって、独自プラグインを用意していたがこれがうまく動かない。結局、wp-content/object-cache.php のオブジェクトキャッシュが邪魔をしていて、すぐにどうにもならないので、とりあえずは


  • 全サイト wp-content/object-cache.php を削除


APCu を使えないのは痛いかもしれないが、副作用をとりあえず抑えることを優先しました。


警告を潰す!!


警告を放置しても動作はしますが、将来的に動作しなくなる、あるいは意図しない動作をする場合があります。ので警告を見つけたのなら、解決することを強く推奨。でないと、「PHPのバージョンアップしたら動かねぇ」ってときが来てしまうかも。
ということでしばらく、 PHPのエラーを眺めてエラーはいたら潰していくやり方で警告をなくしていくことにしました。で、いろいろ出てきたものを紹介しておきます。

なお眺めるのは
tail  -f  /var/log/◯◯/php-fpm.log 
など、ファイルに対して tail にオプション f をつけてあげると、読み込んだファイルの末尾で待機し、ファイルに何か記載があればそのままスクリーン画面に出してくれます

そうそう、 tailf ってコマンドもあるんですね、知らなかった...


NOTICE: PHP message: PHP Warning:  Use of undefined constant staff - assumed 'staff' (this will throw an Error in a future version of PHP) 

関数への文字列引き渡しについて、ダブルクォーテーション(シングルクォーテーション)を使っていないケース

  • get_header(staff);  --> get_header("staff");
これ、get_footer も含めていろんなところで見かけて、気づいたところは修正。
<?php echo get_the_post_thumbnail_url(post-thumbnails); ?>

NOTICE: PHP message: PHP Warning:  Use of undefined constant ja - assumed 'ja' (this will throw an Error in a future version of PHP)


  • if($lang == ja){ --> if($lang === "ja"){

WordPress のコミュニティに入る前に業者に依頼して作成してもらったテーマ内に残っていたコード。文字列はダブルクォーテーションかシングルクォーテーションで括ってほしいなぁ。そのうち警告ではなくてエラーになったら目も当てられませんからねぇ。


NOTICE: PHP message: PHP Warning:  count(): Parameter must be an array or an object that implements Countable in /◯◯/wp-includes/post-template.php on line 284


  • if ( $page > count( $pages ) ) // if the requested page doesn't exist
            $page = count( $pages ); // give them the highest numbered page that DOES exist

しかし、 $pages は配列なんですよね。
なんでエラーになるかなぁ。
とりあえずこれは放置。

NOTICE: PHP message: PHP Warning:  preg_replace(): Compilation failed: missing terminating ] for character class at offset 64 in /◯◯/wp-content/themes/△△/functions.php on line 145"

で問題のコード
  •  $text = preg_replace('/(' . $keys .')/iu', '<span class="search-highlight">\0</span>', $text);
\0 で引っかかってるんですね。https://www.webcreatorbox.com/tech/wordpress-tips あたりをみると、検索ワードをハイライトする場合に使うみたいですね。なるほど。
サイトでも \0 に記述がありますけど、
http://php.net/manual/ja/function.preg-replace.php
のドキュメントをみると $0 \\0 を使えって書いてますね。ふむふむ。

追記
 あと、 $keys に入る文字に / や [ ] とか特殊文字が含まれているとエラーになることに気づく。
  •  $text = preg_replace('/(' . preg_quote( $keys, '/' )  .')/iu', '<span class="search-highlight">\\0</span>', $text);
にしないといけませんね。
/ とか検索文字列にいれたらもろにエラーでてました。。
そして実際のサイト内検索すると、問題なくハイライトされることを確認。



その他、まだまだ出てきそうです。自前のデータベースシステムも警告出まくってます。まぁそっちは、開発版で修正済みなのでそれにどこかのタイミングで置き換えるだけなんですけどね。

本日のところはこれぐらいにして、今後1,2週間ぐらいウォッチして修正していこうかなーと思います。

これでようやく PHPについて現代社会に復帰できたかな (^^;

2018年7月10日 @kimipooh

追加のエラー対応


ログインしようとすると nginxエラーでログインできず


NOTICE: PHP message: PHP Warning: Cannot assign an empty string to a string offset in /◯◯/wp-content/plugins/wp-editor/classes/WPEditor.php on line 333"

NOTICE: PHP message: PHP Fatal error: Uncaught Error: [] operator not supported for strings in /◯◯/wp-content/plugins/breadcrumb-navxt/includes/class.mtekk_adminkit.php:247"

一見、breadcrumb-navxtプラグインが悪いようにみえますが、実際は WP Editor プラグインの問題でした。WP Editorプラグインを停止することで両方のエラーがでなくなりました。
333行目は
        $data[ $key ] = $value;
この $data 配列の初期化については
        $data = '';
のように、配列なのに文字列で初期化すると、PHP 7.1 からその挙動が変更されたために、おかしな値がはってしまうようになったのですね。
具体的には 

$data = '';
$data[ 'test' ] = 'value';
var_dump($data);

だと

PHP 5.6
array(1) {
  ["test"]=>
  string(5) "value"
}

PHP7.1 
Warning: Illegal string offset 'test' in /Users/kitani/a.php on line 3
string(1) "v"

となる。
正しくは
$data = array();
$data[ 'test' ] = 'value';
var_dump($data);

としなければならない。
いずれにしても WP Editorプラグインはメンテナンスされていないものなので、停止して解決。

current_time で 現在時刻が正しく取得できない

NOTICE: PHP message: PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function current_time(), 0 passed in /◯◯/wp-content/plugins/list-view-google-calendar/list-view-google-calendar.php on line 248 and at least 1 expected in /◯◯/wp-includes/functions.php:61"

筆者の開発プラグインで動作してなかった問題。

WordPress関数の current_time の仕様が変更になっていたようで、これまでは赤文字のやり方が使えていましたが、PHP7.2にしたらそれでエラーになってしまった問題

get_date_from_gmt(current_time(), 'c');

date('c', current_time("timestamp",0))

のように第一引数は必ずいれないといけないように変わってますねぇ。

current_time("Ymd");

これについてはまだ使えるようですが、

date("Ymd", current_time("timestamp",0));

のような記述に念の為変えておきました。


2018年7月11日 @kimipooh

0 件のコメント: