Amazon Linux 2に PHP 8.1をインストール
はじめに
Amazon Linux 2にPHPをインストールするときは、
いつもamazon-linux-extras リポジトリからインストールするのですが、
現時点では同リポジトリではPHP 8.1をインストールできません。
$ amazon-linux-extras list | grep php
42 php7.4 available [ =stable ]
51 php8.0 available [ =stable ]
ということで、今回はyum
でインストールします。
参考
今回は以下の記事を参考にしました。
https://computingforgeeks.com/how-to-install-php-centos-rhel-linux/
手順
1. remiリポジトリ追加
sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
sudo yum install https://rpms.remirepo.net/enterprise/remi-release-7.rpm
sudo yum install yum-utils
2. PHP 8.1インストール
sudo yum-config-manager --disable 'remi-php*'
sudo yum-config-manager --enable remi-php81
sudo yum install php81
sudo yum install php81-php-{cli,fpm,mysqlnd,zip,devel,gd,mbstring,curl,xml,pear,bcmath,json,opcache,redis,memcache,intl}
ただし、このままだと php
コマンドでは使えないので、
$ php -v
-bash: php: コマンドが見つかりません
$ php81 -v
PHP 8.1.3 (cli) (built: Feb 16 2022 01:00:24) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.1.3, Copyright (c) Zend Technologies
with Zend OPcache v8.1.3, Copyright (c), by Zend Technologies
シンボリックリンクを貼る。
$ sudo ln -s /usr/bin/php81 /usr/bin/php
[ec2-user@ip-172-31-8-78 ~]$ php -v
PHP 8.1.3 (cli) (built: Feb 16 2022 01:00:24) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.1.3, Copyright (c) Zend Technologies
with Zend OPcache v8.1.3, Copyright (c), by Zend Technologies
このやり方でいいんかな??
phpbrewでPHP 8.1をインストール
はじめに
自分の場合はローカルPCでphpbrewを利用してPHPをインストールしています。
昨年PHP 8.1がリリースされたので、phpbrewでPHP 8.1をインストールします。
※phpbrew github.com
手順
たぶん以下の手順でいけるかと。
- phpbrew self-update
- phpbrew known --update
- phpbrew install 8.1.3 +default +dbs +curl +zlib
- phpbrew switch 8.1.3
すでにphpbrewをインストール済みの場合は、
最初にphpbrew self-update
してからphpbrew known --update
しないと8.1系が出てこないかもです。
また、PCにデフォルトでインストールされているopensslのバージョンが古い場合は、
opensslの最新バージョンをインストールしたうえで、
phpbrew installのオプションに +openssl=/usr/local/Cellar/openssl@x.x/x.xx
などして、
opensslのパスを指定する必要になると思います。
以下のようなかんじで、無事にローカル環境をphp 8.1.3に切り替えました。
$ phpbrew switch php-8.1.3
$ php -v
PHP 8.1.3 (cli) (built: Mar 9 2022 23:04:47) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.3, Copyright (c) Zend Technologies
PHP 8.1に切り替えて発生するようになったエラーなど
個人的によく使っているCodeigniterはPHP 8.1に対応しているので問題なかったが、
他のライブラリでは以下のようなエラーが出るようになりました。
1. During inheritance of Countable: Uncaught ErrorException:
Fatal error: During inheritance of Countable: Uncaught ErrorException: Return type of class::method() should either be compatible with Countable::count(): int, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /path/to/****.php:xxxx
これについては下記の記事が分かりやすかったので参考にしました。
2. strtolower(): Passing null to parameter #1 ($string) of type string is deprecated
某ライブラリが発せられている警告なのですが、、 せめて null
チェックはしていて欲しかった。
組み込み関数のnullableでない引数にnullを渡すと、PHP 8.1から警告が出るようになります。
www.php.net
メンテされていないライブラリを使用しているからなのですが、
これを機に古いライブラリの入れ替えもしようかなと。
Markedカスタマイズ:テーブルの1列目をヘッダーにする
概要
Markedを使ってマークダウンでテーブルの1列目をthタグにするために、独自構文+renderメソッドで関数定義することで対応した。
Markedとは
マークダウン構文で書いたテキストをhtmlに変換するjavascriptライブラリ。
簡単な使い方
- マークダウンを記述(タグにid属性を書いておく)
- jsを読み込む
- maked関数でid指定して、htmlに変換して表示する
<div id="markdownText">
| | A | B | C | D | E | F | G | H |
|---|---|---|---|---|---|---|---|----|
| A | H | F | E | C | D | G | B | A! |
| B | - | H | D | A | C | D | E | B! |
| C | - | - | H | F | G | B | A | C! |
| D | - | - | - | H | B | E | G | D! |
| E | - | - | - | - | H | A | F | E! |
| F | - | - | - | - | - | H | C | F! |
| G | - | - | - | - | - | - | H | G! |
| H | - | - | - | - | - | - | - | - |
</div>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
document.getElementById("markdownText").innerHTML = marked(document.getElementById("markdownText").innerHTML.trim());
</script>
実行すると、以下のような表示になる。
A | B | C | D | E | F | G | H | |
---|---|---|---|---|---|---|---|---|
A | H | F | E | C | D | G | B | A! |
B | - | H | D | A | C | D | E | B! |
C | - | - | H | F | G | B | A | C! |
D | - | - | - | H | B | E | G | D! |
E | - | - | - | - | H | A | F | E! |
F | - | - | - | - | - | H | C | F! |
G | - | - | - | - | - | - | H | G! |
H | - | - | - | - | - | - | - | - |
htmlは以下のようなソースになっている。
<div id="markdownText"><table>
<thead>
<tr>
<th></th>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>E</th>
<th>F</th>
<th>G</th>
<th>H</th>
</tr>
</thead>
<tbody><tr>
<td>A</td>
<td>H</td>
<td>F</td>
<td>E</td>
<td>C</td>
<td>D</td>
<td>G</td>
<td>B</td>
<td>A!</td>
</tr>
(中略)
</tbody></table>
</div>
1列目をthタグにしたい
マークダウンで1列目をthタグにするような構文は定義されていない?ので、Markedのrendererメソッドで拡張した。
1: 独自構文の定義
Markedのrendererメソッドでは "n列目" という情報を取得できなかったので、
まずは独自の構文を定義した。
以下のように、先頭に「:」をつけたものをthタグでレンダリングする事とする。
| | A | B | C | D | E | F | G | H |
|---|---|---|---|---|---|---|---|----|
| :A | H | F | E | C | D | G | B | A! |
| :B | - | H | D | A | C | D | E | B! |
| :C | - | - | H | F | G | B | A | C! |
| :D | - | - | - | H | B | E | G | D! |
| :E | - | - | - | - | H | A | F | E! |
| :F | - | - | - | - | - | H | C | F! |
| :G | - | - | - | - | - | - | H | G! |
| :H | - | - | - | - | - | - | - | - |
2: Markedのrendererメソッドで拡張
詳しくはドキュメントを参照するとして、renderer.tablecellでテーブルセルの生成をカスタマイズ可能。 marked.js.org
あとはrenderer.tablecellメソッドで、
tbodyのセルのときだけテキストの先頭1文字目が「:」の場合は、thタグで生成するように書く。
var renderer = new marked.Renderer();
// tableタグ
renderer.tablecell = function(content, flags) {
//thead
if (flags.header) {
return '<th>' + content + '</th>';
}
//tbody
if (content.substring(0, 1) === ':') {
return '<th>' + content.substring(1) + '</th>';
}
return '<td>' + content + '</td>';
};
marked.setOptions({
renderer: renderer,
});
document.getElementById("markdownText").innerHTML = marked(document.getElementById("markdownText").innerHTML.trim());
これを実行すると以下のような表示になる。
A | B | C | D | E | F | G | H | |
---|---|---|---|---|---|---|---|---|
A | H | F | E | C | D | G | B | A! |
B | - | H | D | A | C | D | E | B! |
C | - | - | H | F | G | B | A | C! |
D | - | - | - | H | B | E | G | D! |
E | - | - | - | - | H | A | F | E! |
F | - | - | - | - | - | H | C | F! |
G | - | - | - | - | - | - | H | G! |
H | - | - | - | - | - | - | - | - |
生成するhtmlは以下のようになっており、1列目がthタグになっている。
<div id="markdownText"><table>
<thead>
<tr>
<th></th>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>E</th>
<th>F</th>
<th>G</th>
<th>H</th>
</tr>
</thead>
<tbody><tr>
<th>A</th>
<th>H</th>
<th>F</th>
<th>E</th>
<th>C</th>
<th>D</th>
<th>G</th>
<th>B</th>
<th>A!</th>
</tr>
(中略)
</tbody></table>
</div>
※html/js全文
<div id="markdownText">
| | A | B | C | D | E | F | G | H |
|---|---|---|---|---|---|---|---|----|
| :A | H | F | E | C | D | G | B | A! |
| :B | - | H | D | A | C | D | E | B! |
| :C | - | - | H | F | G | B | A | C! |
| :D | - | - | - | H | B | E | G | D! |
| :E | - | - | - | - | H | A | F | E! |
| :F | - | - | - | - | - | H | C | F! |
| :G | - | - | - | - | - | - | H | G! |
| :H | - | - | - | - | - | - | - | - |
</div>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
var renderer = new marked.Renderer();
// tableタグ
renderer.tablecell = function(content, flags) {
//thead
if (flags.header) {
return '<th>' + content + '</th>';
}
//tbody
if (content.substring(0, 1) === ':') {
return '<th>' + content.substring(1) + '</th>';
}
return '<td>' + content + '</td>';
};
marked.setOptions({
renderer: renderer,
});
document.getElementById("markdownText").innerHTML = marked(document.getElementById("markdownText").innerHTML.trim());
</script>
phpbrewでPHP 8をインストール
はじめに
2020/11/26にPHP 8がリリースされました。 www.php.net
自分の場合はローカルPCでphpbrewを利用して、
複数バージョンのPHPをインストールしています。
というわけで今回もphpbrewでPHP 8をインストールすることに。
※phpbrew github.com
手順
たぶん以下の手順でいけるかと。
- phpbrew self-update
- phpbrew known --update
- phpbrew install 8.0.0 +default +dbs +curl
- phpbrew switch 8.0.0
すでにphpbrewをインストール済みの場合は、
最初にphpbrew self-update
してからphpbrew known --update
しないと8.0.0が出てこないです。
また、PCにデフォルトでインストールされているopensslのバージョンが古い場合は、
opensslの最新バージョンをインストールしたうえで、
phpbrew installのオプションに +openssl=/usr/local/Cellar/openssl@x.x/x.xx
などして、
opensslのパスを指定する必要になると思います。
以下のようなかんじで、ローカル環境をphp 8.0.0に切り替えました。
php -v
PHP 8.0.0 (cli) (built: Nov 28 2020 08:39:49) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.0-dev, Copyright (c) Zend Technologies
Codeigniter 4はまだPHP 8に対応してないらしく、、、
php spark serve
でローカルサーバが起動しないっす。
% php spark serve
PHP Deprecated: Required parameter $userAgent follows optional parameter $body in [path]/vendor/codeigniter4/framework/system/HTTP/IncomingRequest.php on line 161
Deprecated: Required parameter $userAgent follows optional parameter $body in [path]/vendor/codeigniter4/framework/system/HTTP/IncomingRequest.php on line 161
CodeIgniter CLI Tool - Version 4.0.3 - Server-Time: 2020-11-29 09:21:52am
An uncaught Exception was encountered
Type: ErrorException
Message: Required parameter $from follows optional parameter $verbs
Filename: [path]/vendor/codeigniter4/framework/system/Router/RouteCollection.php
Line Number: 1018
8対応してくれるのを待つしかない。。
1582年10月4日の翌日は?
はじめに
以下の記事を読んでたら、
1582/10/4の翌日がほんとに1582/10/15になるかを確かめたくなった。
nagise.hatenablog.jp
というわけで、今回はJavaとPHPとPythonとGoで検証をしてみた。
結論
Javaのみ1582/10/4の翌日が1582/10/15になった。
PHPとPythonとGoは1582/10/4の翌日が1582/10/5だった。
各言語のバージョン
ローカルPCに入っているバージョンを使用。*1
検証
■Java
Javaは内部的にユリウス暦とグレゴリオ暦の切り替えを行っている。
ソースコード
import java.util.Calendar;
import java.util.GregorianCalendar;
public class Test {
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
c.set(1582, Calendar.OCTOBER, 4);
System.out.println(c.getTime());
c.add(Calendar.DAY_OF_MONTH, 1);
System.out.println(c.getTime());
System.out.println("---------------");
c = new GregorianCalendar(1582, Calendar.OCTOBER, 4);
System.out.println(c.getTime());
c.add(Calendar.DAY_OF_MONTH, 1);
System.out.println(c.getTime());
}
}
実行
$ java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
$
$ javac Test.java
$ java Test
Thu Oct 04 03:29:27 JST 1582
Fri Oct 15 03:29:27 JST 1582
---------------
Thu Oct 04 00:00:00 JST 1582
Fri Oct 15 00:00:00 JST 1582
■PHP
Javaみたいなことはやってない。
ソースコード
format('Y-m-d')."\n";
echo $date->modify('+1 days')->format('Y-m-d')."\n";
実行
$ php -v
PHP 7.4.0 (cli) (built: Mar 14 2020 18:05:20) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
$
$ php Test.php
1582-10-04
1582-10-05
■Python
Javaみたいなことはやってない。
ソースコード
import datetime
date = datetime.date(1582, 10, 4)
print(date)
print(date + datetime.timedelta(days=1))
実行
$ python3 --version
Python 3.7.5
$
$ python3 Test.py
1582-10-04
1582-10-05
■Go
Javaみたいなことはやってない。
ソースコード
package main
import(
"fmt"
"time"
)
func main() {
t := time.Date(1582, 10, 4, 0, 0, 0, 0, time.Local)
fmt.Println(t)
t = t.AddDate(0, 0, 1)
fmt.Println(t)
}
実行
$ go version
go version go1.13 darwin/amd64
$
$ go run Test.go
1582-10-04 00:00:00 +0900 JCST
1582-10-05 00:00:00 +0900 JCST
終わりに
しょうもないことに時間を使ってしまったと反省。
なお、Perlでも試そうとしたが、CPANモジュールをインストールできなくて諦めた。
(また今度、気が向いたときにやる)
*1:最新バージョンじゃない
composerでCodeIgniter 4をインストール〜ローカルサーバ起動
はじめに
先日、CodeIgniter 4正式版がリリースされたので、
数年前から4devで作って運用していたものをそろそろ4正式版ベースに移行したいと思った。
CodeIgniter 4のインストール&セットアップ
インストール方法は公式サイトに何通りかのやり方を書いているが、 codeigniter4.github.io
Adding CodeIgniter4 to an Existing Project
https://codeigniter4.github.io/userguide/installation/installing_composer.html#adding-codeigniter4-to-an-existing-project
の手順に沿ってインストールした。
$ composer require codeigniter4/framework
Using version ^4.0 for codeigniter4/framework
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.
Problem 1
- codeigniter4/framework v4.0.2 requires ext-intl * -> the requested PHP extension intl is missing from your system.
- codeigniter4/framework v4.0.1 requires ext-intl * -> the requested PHP extension intl is missing from your system.
- codeigniter4/framework 4.0.0 requires ext-intl * -> the requested PHP extension intl is missing from your system.
- Installation request for codeigniter4/framework ^4.0 -> satisfiable by codeigniter4/framework[4.0.0, v4.0.1, v4.0.2].
To enable extensions, verify that they are enabled in your .ini files:
- /Users/[myuser]/.phpbrew/php/php-7.4.0/etc/php.ini
- /Users/[myuser]/.phpbrew/php/php-7.4.0/var/db/iconv.ini
You can also run `php --ini` inside terminal to see which files are used by PHP in CLI mode.
Installation failed, deleting ./composer.json.
うぐっ。見慣れないエラーが。。
$ phpbrew ext install intl
===> Installing intl extension...
Log stored at: /Users/[myuser]/.phpbrew/build/php-7.4.0/ext/intl/build.log
Changing directory to /Users/[myuser]/.phpbrew/build/php-7.4.0/ext/intl
===> Phpize...
===> Configuring...
Error: Command failed: ./configure --with-php-config=/Users/[myuser]/.phpbrew/php/php-7.4.0/bin/php-config >> /Users/[myuser]/.phpbrew/build/php-7.4.0/ext/intl/build.log 2>&1 returns:
php-intlのインストールも失敗。いったい何事。。 というわけでログを調べる。
~/.phpbrew/build/php-7.4.0/ext/intl/build.log
checking if debug is enabled... no
checking if zts is enabled... no
checking for gawk... no
checking for nawk... no
checking for awk... awk
checking if awk is broken... no
checking whether to enable internationalization support... yes, shared
checking for icu-uc >= 50.1 icu-io icu-i18n... no
configure: error: Package requirements (icu-uc >= 50.1 icu-io icu-i18n) were not met:
No package 'icu-uc' found
No package 'icu-io' found
No package 'icu-i18n' found
Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.
Alternatively, you may set the environment variables ICU_CFLAGS
and ICU_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.
icuとやらをインストールすればいいんかな(=よく分かっていない)。
icu4cをインストール
やってみたところ既にインストール済みだった。
念のためupgradeをして、ログの助言通りPKG_CONFIG_PATHを設定。
$ brew install icu4c
Updating Homebrew...
Error: icu4c 63.1 is already installed
To upgrade to 66.1, run `brew upgrade icu4c`
$ brew upgrade icu4c
(以下省略)
$ export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"
気を取り直してphp-intlをインストール
$ phpbrew ext install intl
(中略)
[*] intl extension is enabled.
Done.
はい。いけました。(icu4cのupgradeは不要だったかもしれない)
改めてCodeIgniter 4をインストール
今度こそ!
まずはcomposerでインストール
$ composer require codeigniter4/framework
Using version ^4.0 for codeigniter4/framework
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 5 installs, 0 updates, 0 removals
- Installing laminas/laminas-zendframework-bridge (1.0.3): Downloading (100%)
- Installing laminas/laminas-escaper (2.6.1): Downloading (100%)
- Installing psr/log (1.1.3): Downloading (100%)
- Installing kint-php/kint (3.3): Downloading (100%)
- Installing codeigniter4/framework (v4.0.2): Downloading (100%)
kint-php/kint suggests installing kint-php/kint-twig (Provides d() and s() functions in twig templates)
kint-php/kint suggests installing kint-php/kint-js (Provides a simplified dump to console.log())
kint-php/kint suggests installing symfony/polyfill-mbstring (Replacement for ext-mbstring if missing)
kint-php/kint suggests installing symfony/polyfill-iconv (Replacement for ext-iconv if missing)
kint-php/kint suggests installing symfony/polyfill-ctype (Replacement for ext-ctype if missing)
Writing lock file
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!
はい。いけました。
setup
これは公式ドキュメントに書いている通り、手動作業が必要。
https://codeigniter4.github.io/userguide/installation/installing_composer.html#set-up
ソースコードのコピー
rsync -arvz vendor/codeigniter4/framework/app ./
rsync -arvz vendor/codeigniter4/framework/public ./
rsync -arvz vendor/codeigniter4/framework/tests ./
rsync -arvz vendor/codeigniter4/framework/writable ./
cp -p vendor/codeigniter4/framework/env ./
cp -p vendor/codeigniter4/framework/phpunit.xml.dist ./
cp -p vendor/codeigniter4/framework/spark ./
cp -p vendor/codeigniter4/framework/.gitignore ./
※公式ドキュメントには書いてないけど、 .gitignore にいろいろ書かれているのでコピーしたほうがよいと思う。
systemディレクトリのパス修正
app/Config/Paths.php
public $systemDirectory = __DIR__ . '/../../vendor/codeigniter4/framework/system';
ローカルサーバ起動
4devのときは php serve.php
でローカルサーバを起動していたのだが、
コマンドが変わっていた。
$ php spark serve
CodeIgniter CLI Tool - Version 4.0.2 - Server-Time: 2020-04-26 07:46:28am
CodeIgniter development server started on http://localhost:8080
Press Control-C to stop.
[Sun Apr 26 21:46:28 2020] PHP 7.4.0 Development Server (http://localhost:8080) started
”spark”ってちょっとかっこいいな。
初回の画面も(4devに比べて)いいかんじになりました。
PHP 7.4:Trying to access array offset on value of type bool
概要
PHP 7.4にバージョンアップすると、
Trying to access array offset on value of type bool のExceptionが発生するようになった。
問題のコード
mb_regex_encoding("UTF-8");
mb_ereg_search_init($text, "[가-힣]+");
if (mb_ereg_search()) {
$hangul = mb_ereg_search_getregs(); //get first result
$text = str_replace($hangul[0], $hc->conv2kana($hangul[0], true), $text);
do {
$hangul = mb_ereg_search_regs();//get next result
$text = str_replace($hangul[0], $hc->conv2kana($hangul[0], true), $text); //←ここでエラーが発生
} while($hangul);
}
これは何をやっているかというと、
$text からハングルの文字列を順に抜き出して、自前モジュールでカタカナに変換している。
do - whileの中で mb_ereg_search_regs関数で順に抜き出していって、
抜き出せるものがなくなったらループから抜ける。
このコードはphp 7.3までは特に問題なく動いていた。
何が問題か
エラーメッセージのとおり、
bool型の変数に対して配列インデックスでアクセスしているのが問題っぽい。
mb_ereg_search_regs() 関数は抜き出せるものがない場合、FALSEを返す仕様である。 https://www.php.net/manual/ja/function.mb-ereg-search-regs.php
do-whileの中でmb_ereg_search_regs() は最後はFALSEを返すので、
$hangul = FALSE; が代入され、
それに対して $hangul[0] のように配列アクセスをしているので今回のエラーが発生したようだ。
対処
とりあえずやっつけで回避。
mb_regex_encoding("UTF-8");
mb_ereg_search_init($text, "[가-힣]+");
if (mb_ereg_search()) {
$hangul = mb_ereg_search_getregs(); //get first result
$text = str_replace($hangul[0], $hc->conv2kana($hangul[0], true), $text);
do {
$hangul = mb_ereg_search_regs();//get next result
if ($hangul !== false) {
$text = str_replace($hangul[0], $hc->conv2kana($hangul[0], true), $text);
}
} while($hangul);
}
本当はそもそもdo-while構文を使わずに書き直した方がよいのでは、と思っているが。