Amazon PayのShippingAddress.name
Amazon PayでCheckoutSessionをスタートすると、その返り値のShippingAddressにお届け先住所が入ってきます。そのなかのName がお届け先のお名前で、姓名分割されていない1つのフィールドです。
Amazon Pay FAQ(v2)には、
Amazon Payから取得できるアドレス帳の情報には様々なパターンがあります。テストユーザーを用意していますので、どのパターンのユーザ情報も処理ができることをご確認してください。
氏名ブランクあり(半角)氏名ブランクあり(全角)
Amazon Pay FAQ(v2) アカウント情報として何が取得できますか?
氏名ブランクなし
ミドルネームあり
とあります。
半角スペースで区切ったケース「東京 太郎」、全角スペースで区切ったケース「東京 太郎」、詰まっているケース「東京太郎」があるそうです。
そのうちの半角スペース区切り、全角スペース区切りは、PHPのexplode関数で分割できます。
$name = '東京 太郎';
$arr = explode(' ', $name, 2);
// $arr[0] '東京'
// $arr[1] '太郎'
$name = '東京 太郎';
$arr = explode(' ', $name, 2);
// $arr[0] '東京'
// $arr[1] '太郎'
Code language: plaintext (plaintext)
igo-php
スペースで区切られていない場合は、igo-phpを使って分割します。
igo-phpは、半角スペース区切り、全角スペース区切りの場合も分割してくれます。
igo-phpを使って、姓名分割する処理は、igo-php-sample を参考にしました。
本家
本家を使うことができればいいんですが、namespace設定がありません。
ECサイト側にnamespaceのないCategory
クラスがすでにありました。igo-phpでもCategoryクラスを定義していてバッティングしてしまい、使えませんでした。
packagistで、igo-phpを検索すると、いくつかヒットしました。
logue/igo-php 0.2.0
requires php: >= 5.4.0 とありますが、PHP7以降で導入されたメソッドの返り値の型を宣言しています。
ECサイト側の諸事情で、これも使えませんでした。
technote/igo-php v0.3.29
requires php: >= 5.6.0、こちらを使うことができました。
メモリ不足エラー
ところが、実行しみてると、メモリ不足エラーです。
PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 72 bytes) in /xxx/yyy/vendor/technote/igo-php/src/Igo/FileMappedInputStream.php on line 60
Code language: plaintext (plaintext)
メモリ上限の設定を調べると、128M でした。
ini_get('memory_limit')
Code language: plaintext (plaintext)
メモリ上限を140Mにして、ようやくエラーがなくなりました。
ini_set('memory_limit', '140M');
Code language: plaintext (plaintext)
少ししか上乗せしていないけど、140Mでいいの?
姓名分割処理でどれぐらいメモリを使っているのか知りたいわね
姓名分割処理がどれぐらいメモリを使っているのか、調べてみると、
$mem0 = memory_get_usage();
〜姓名分割処理〜
$mem1 = memory_get_peak_usage();
echo $mem1 - $mem1;
Code language: plaintext (plaintext)
120Mも使っていました。
つまり、もともとのページ処理では、20M程度しかメモリを使っていませんでした。姓名分割処理が120Mを使おうとして、メモリ上限の128Mに達してしまったんですね。
メモリ上限をいくつにするかは迷うところです。今回の件では、160M〜256Mにしておけばいいと思います。
ここまでは、メモリが例えば500Mも余っているのに、memory_limit=128Mだったので、エラーになった。memory_limit=140Mにして、140Mのメモリを確保できるようになった、という状況です。
ところが、メモリが100Mしか余っていない場合、memory_limit=140Mにしてあっても、メモリ不足エラーになってしまう可能性があります。
問題なのは、PHPのメモリ不足エラーは、error_handling関数でキャッチできないことです。ユーザに500エラーを晒してしまいます。
姓名分割処理がメモリ不足エラーで落ちても、呼んだ側は落ちないようにするには、違うプロセス空間で実行する必要があります。
呼んだ側と姓名分割処理が違うプロセスなら、呼んだ側は姓名分割処理の道連れにならずにすみます。
心配しすぎかもね
違うプロセスで姓名分割を処理する
違うプロセスで実行するには、pcntl_fork、REST API、CLI、の方法があります。
pcntl_fork
呼ぶ側を親プロセス、新しいプロセスを子プロセスと呼びます。
子プロセスの起動時間が最も短そうです。
子プロセスが姓名分割処理の結果を返すには、共有メモリを使います。
親プロセスが子プロセスの姓名分割処理が終わるまで待つには、pcntl_waitpid関数を使います。
注意することは、子プロセス側は姓名分割処理が終わったら、exit()を呼ぶ必要があることです。exit()を呼ばないと、子プロセスがコールスタックを戻りながら、コントローラまで戻り、データベースなどを更新してしまいます。
<?php
class Fuga
{
public function nameSplit($name)
{
$pid = pcntl_fork();
if ($pid == -1) {
return [$name, ''];
} else if ($pid) {
// 親プロセスの場合
pcntl_wait($status); // ゾンビプロセスから守る
$nameArr = 共有メモリから結果を取り出す
return $nameArr;
} else {
// 子プロセスの場合
姓名分割処理
結果を共有メモリに書く
exit(); // ★コレ
}
}
Code language: plaintext (plaintext)
設定によっては、pcntl_forkが使えないこともあるそうです。
PHPがサポートするプロセス制御機能は、デフォルトでは有効となってい ません。
https://www.php.net/manual/ja/pcntl.installation.php
REST API
呼ぶ側は、curl関数で呼びます。curl関数の呼び出しがゴチャゴチャしがちです。
呼ぶ側のユニットテストをするために、REST API側のWebサーバ起動が必要です。
公開する必要がなければ、REST APIのアクセス制限をして、localhostだけにアクセス許可します。
メモリ不足エラーになると、アクセスログやエラーログに500エラーが残ります。
CLI
実測していませんが、REST APIより遅いかもしれません。
呼ぶ側は、passthru関数で呼びます。
CLI側は、コマンドライン引数を受け取り、STDOUTにjsonを出力します。
呼ぶ側は、ob_start関数とob_get_clean関数でpassthru関数をはさんでおき、結果をキャプチャーします。
ob_start();
passthru($cmd, $result);
$output = ob_get_clean();
if ($result == 0) {
$vars = json_decode($output, true);
}
Code language: plaintext (plaintext)
まとめ
pcntl_forkは、子プロセス側でexit()を書かなければいけないことが少し気になります。
pcntl_forkを使い慣れていないだけでしょ
REST APIは、curl関数の呼び出しがゴチャゴチャしがちなこと、呼ぶ側のユニットテストが難しそうです。
今回は、CLIで実装しました。