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

2018年7月3日火曜日

greple + App::Greple::msdoc で Microsoft Office ドキュメントをコマンドラインから検索、テキスト抽出(出力)する!

知人がFacebookでつぶいていたのをみて、面白そうだったので早速手持ちの Mac(macOS 10.13.5)にインストール。ちょっとインストールに手間取ったので、備忘録として残しておきます。

参考情報


greple を Mac へインストール


ターミナルより、次の3つのコマンドでインストールできます。
※参考情報であげたサイトをみると brew (要 Homebrewのインストール)でインストールしてますね。

sudo cpan install App::Greple::perl
sudo cpan install App::cpanminus
sudo cpanm install App::Greple::msdoc

cpan は perl モジュールをインストールするためのツールで、macOS には標準搭載されています。これを使って greple をインストールします。 /Library 以下に書き込む(標準 perl を使うので)ため、sudo を使って管理者権限でインストールします。

greple コマンドは、
  • /usr/local/bin/greple 
にインストールされます。

次に cpanm コマンドをインストールします。これは App::cpanmius というモジュールをインストールすることで利用できるようになります。

cpanm コマンドは、
  • /usr/local/bin/cpanm
にインストールされます。
cpanm をインストールした理由は、App:Greple::msdoc(GitHub)のINSTALL項目に、「cpanm App::Greple::msdoc」とあったので、cpanm があったほうがいいのだろうな、、という軽い気持ちでした。

で、そのコマンドを叩いてインストールしたのでした。

/usr/local/bin への PATHを通そう!


macOS 標準の bash シェルを使っているなら、
which greple
/usr/local/bin/greple
とPATHがすでに通っていれば何もしなくてもよいのですが、
which greple と /usr/local/bin/greple 等 greple のPATHが表示されないなら、PATHを設定する必要があります。

 ~/.bash_profile
export PATH="/usr/local/bin:$PATH"
を追加しておきましょう。

使ってみよう!


とまぁ、インストールは cpanm をどうやってインストールするのかなとかで少し手間取りましたが、終わってみれはあっさりとインストールできました。インストールしたからには使ってみなければ!ですね!

Microsoft Office 2016 for Mac で、2種類のフォーマットの Word文書を用意してみた
  • test.doc (Word 97-2004 までの形式)
  • test.docx (Word 2007 以降の形式)
でまぁ文章は上記の通りですね。あまり考えてません (^^;
ダウンロードフォルダに test.docとtest.docx を置いたとします。

現在の Word 形式の場合


greple -Mmsdoc --dump  ~/Downloads/test.docx >  ~/Downloads/test.txt

としてダウンロードフォルダに text.txt として出力してみましょう。
それを CotEditor というテキストエディタで開きます。


ほうほう、改行コードは LF なのね。。また段落(Enter)ごとに空行が入るのは仕様だそうです(参考情報によれば)。ちなみに、Shift+Enter (改行)は、認識しないようで、テキストデータで出すと、改行なしで出力されます。

を出力すると


になります。

画像を途中で挟んでも、そこは無視されてテキスト部分だけが出力されます(当たり前か)。

古い Word 97-2014 形式の場合


greple -Mmsdoc --dump  ~/Downloads/test.doc >  ~/Downloads/test2.txt
SKIP /Users/◯◯/Downloads/test.doc

あらま、古い形式は対応していないようですね。
test2.txt も空でデータが入っていません。

検索してみよう


greple -Mmsdoc '検索'  ~/Downloads/test.docx


ふむふむ。まぁ テキストファイルに落とし込めたなら、あとは別ツールを使えばいいので、このあたりでいいかな。

PowerPoint もいけるそうだが、どうやる?


折角なので、発表に使ったデータでやってみましょう。
のように 64スライドもあります。画像も沢山つかっています。
これを test.pptx にリネームして、ダウンロードフォルダにいれておきます。

greple -Mmsdoc --dump  ~/Downloads/test4doc >  ~/Downloads/test4.txt

とするとあっさりできましたね。
ちなみにサクッと出来ました。time で時間をはかるとほぼ一瞬。

time greple -Mmsdoc --dump ~/Downloads/test4.pptx> test4.txt
real 0m0.297s
user 0m0.218s
sys 0m0.047s

はやいな!
データは、スライドにページ番号をいれていたので、
開幕〜いきますよ!
9
のようにスライド9番目だなというのは分かります。ただスライドの順番がバラバラですねぇ。スライド28→7→8→9→10→22→11→.. 


スライド44の文字化け


は、下図のように元スライドをみると「→」か。。まぁ一部このような部分もありますが、ほぼテキストをうまく取り出しているのですごいですね!



じゃあ、Excelはいけるの?いけるよね?


Excelデータを test5.xlsx としてダウンロードフォルダに入れる

greple -Mmsdoc --dump ~/Downloads/test5.xlsx > test5.txt

さすがに意味不明なデータになりますね。



元は、下記のようにA - E にデータが入っていました。もちろんテキストデータとしては問題なく出力できていますが、どの行かわからなーいという感じに。




簡単に使えるようにエイリアス設定をしておこう!


greple というコマンド自体覚えておける自信がありません。
ここは alias コマンドで好きな名前で使えるようにしちゃいましょう。
macOS の標準シェルは bash です。ので、 ~/.bash_profile の末尾に、

alias msdump='greple -Mmsdoc --dump'

を追加しておけば、以後

msdump  ◯◯.docx  > △△.txt 

のように、コマンドオプションを知らなくても使えるようになりますよ。

XML形式での出力も可能


何かプログラム処理をしたいなら、そういうのもありかもしれません。

greple -Mmsdoc --dump --indent ~/Downloads/test.docx >  ~/Downloads/test.xml

などのように --dump に加えて --indent オプションを追加するだけです。
すると下図のように、XML形式のデータとして出力できますね。



とちょっと面白そうなコマンドだなと思っていろいろ試したのでした。これはなかなか良さそうですね!

2018年7月3日 @kimipooh