Eccube

EC2 x S3 x ECCUBE 同期@AWS

AWS EC2において、ECCUBEが構築出来た。(現在、シングル構成)

ELBは上に付けているので、
いつでもインスタンス追加で、冗長化が可能だが、
今は、アクセス過多ということもないため、
当分、シングルで動かす予定だが、準備だけはしておきたい。

***

ホントは、EFSを使って、自動同期をしたいのですが、
「File System Mount Using Mount Target DNS Name Fails」という、エラーが出て、先に進めず。

ええ、わかっているんですよ。

EC2の?DHCP Options Sets とDNS Options Sets をいじることは。
でも、そうなっていても、このエラーが出てるから、困っているわけで・・・

今回は諦めて、遅いと定評のあるS3で実装。

※また、時間があるときにやってみます。


S3でデータ共有

概要は、こんなかんじ。

ただ、情報が少なすぎて、イミフで・・・

Access Key / Secret Keyって、いつ設定したっけ?&なんだっけ?
ってことで、そこから。

IAMで、アカウント作成すると、AccessKey & SecretKeyが手に入ります。

***

S3と同期するためには、S3cmdのインストールと設定が必要。

基本、Access Key / Secret Key以外は、デフォルトで良いようですが、
S3にアクセス権がないと、ダメみたい。

で、その設定方法ですが、S3のPermisshonにて、設定できるのですが、
AIMで設定しました。

参考

AIM > Users > Permissions

IAM USER S3 Permissions

AmazonS3FullAccessを割り当てると、s3cmd ls で、
s3のバケットリストが表示されます。

s3cmd ls aws

 

今回は、対象のバッケットのみに割当るのは、また後で。
とりあえず、全バケットに対して、フルアクセスを与えます。

***

画像など、第三者によって書き換えられる箇所だけ、同期するか、

s3cmd sync /home/eccube/html/upload/ s3://example-ec-cube/html/upload/
s3cmd sync /home/eccube/html/user_data/ s3://example-ec-cube/html/user_data/
s3cmd sync /home/eccube/data/download/ s3://example-ec-cube/data/download/
s3cmd sync /home/eccube/data/downloads/ s3://example-ec-cube/data/downloads/
s3cmd sync /home/eccube/data/upload/ s3://example-ec-cube/data/upload/

全体を同期するか、悩むところですが、data/logs が、ちょっと曲者ですが、
当然、そんなことも出来ちゃうようです。

?exclude を試す

ある特定のディレクトリ・ファイルを sync の対象から外したい時は ?exclude を付ける。
特定のファイル名なら ?exclude=”testfile01.txt” とすればよいのだけど、特定のディレクトリ配下のファイルすべて除外するという指定する時が結構やっかいだった。
結局、?exclude=”*exclude-dir/*” で動いた。

↑ このサイト、分かり易い


 

さて、更新する対象フォルダーは、こんなところ。

  • data
    • download
    • downloads(モジュールやプラグインファイル)
    • upload
    • smarty
      • templates
  • html
    • upload(商品写真など)
    • user_data

***

あとは、Cronで実行するか、ってところなんですが、
初動で、手動でやってみたところ、たしかに遅い・・・

でも、そんなに、頻繁にファイルを書き換えるわけじゃないから、
これで十分かもしれない。

ホントは、EFSを使いたい(心の声)

自動同期設定 Cron or Lambda

Lambda AWSで書くのが正解?

だと思うのですが、ちょっと読んだ感じ、すぐにはできそうにないので、
今回は、また断念して、Cronで自動同期の設定。

sudo vim /etc/crontab

で、Cronの設定ファイルを開き、

*/5 * * * * s3cmd sync /var/www/html/****/_data/download/ s3://****/_data/download/
*/5 * * * * s3cmd sync /var/www/html/****/_data/upload/ s3://****/_data/upload/
(以下省略)

と、記述。(5分毎に、s3cmd sync・・・を実行の意)

ホントは、s3cmd 以降を ; で区切り、1行で書くのが正解のようですが、
醜いので、ということで、行を分けております。

/var/www/html/***+/の箇所は、醜いのでナントカならないかな?
と思っていたら、ちゃんとそんあのも、用意されています。

BIN_DIR="/home/dqneo/bin"
LOG_DIR="/home/dqneo/logs"
0 9 * * * /bin/bash $BIN_DIR/hoge.sh >> $LOG_DIR/hoge.log
0 10 * * * /bin/bash $BIN_DIR/fuga.sh >> $LOG_DIR/fuga.log

早速実践!
さらに、スッキリしましたね!

動いているかは、

tail -f /var/log/cron

で、要観察。記述にミスがあると、エラーにも表示してくれます。

[ec2-user@ip-10-0-0-179 etc]$ sudo tail -f /var/log/cron
Sep 20 19:05:01 ip-10-0-0-179 crond[2479]: (CRON) bad username (/etc/crontab)
Sep 20 19:05:01 ip-10-0-0-179 crond[2479]: (CRON) bad username (/etc/crontab)

実行ユーザー名が抜けているので、rootを追記。
(だって、いらないって書いてあったじゃん・・・)

*/5 * * * * root s3cmd sync ・・・・

これで、洗濯機の回転をみるように、監視していたのですが、
5分毎に動いているようですが、S3で消したファイルが反映されてない・・・
逆に、EC2側のファイルを変えてみても、変化なし・・・

うーん、とりあえず、今日はここまで。

でも、S3側のファイルを消しても、EC2側には反映されない。
名前を書き換えると、コピーされるだけ。
ミラーリングとは、ほど遠い仕様だな・・・


-

ECCUBE 2.13系 * 同一のSHOPIDでサイト毎に決済する@GMOペイメント

相変わらず、普通は「出来ない」と断るような注文を受けておりますが、
出来ると言ってしまった「しわ寄せ」での、追加作業で、

今回は、

GMOペイメントにおいて、サイトA・サイトBで、

同一のSHOPIDで、サイトごとに決済処理する

です。

***

単に、SHOPIDを追加すればよいのですが、
SHOPID毎に、登録費用がかかるので、単一SHOPIDで、

かつ、

30サイトもECCUBEを作ってしまうと、管理が大変!!!

ということで、
1つのコアで、ドメイン毎にテンプレートを切り替えて運用している、
(カンタンに言うと、define.phpや、Config.phpでドメインごとに分岐(後述))
超特殊なECCUBEの環境下での、お話です。

サーバーやディレクトリーが別の場合でも、通知を受けるPHPにて、
対象ドメインの同pg_mulpay_recv.phpにPOSTで通知してやれば、動くはずです。

* 受取るデータ構造のチェック

まずは、どういうデータが渡されるのかを、知る必要があり、
pg_mulpay_recv.phpにて、渡されたデータを確認

 $_ = dirname(__FILE__). '/pg_mulpay_recv.log';
error_log(print_r($_REQUEST, true), 3, $_);

ずらーっと、配列データのある中、

まず当たりをつけたのは「Order_ID」

* モジュール「 EC-CUBEペイメント決済モジュール(2.13系)」

ソースを追いましょう。
まずは、
[OrderID] => 361-18114653を生成しているところを、Grepし、特定。

client/SC_Mdl_PG_MULPAY_Client_Base.php

function sendOrderRequest($url, $arrSendKey, $arrOrder, $arrParam, $arrPaymentInfo, $arrMdlSetting) {
    $arrReqParam = $arrParam;
    $arrOrder = SC_Util_PG_MULPAY_Ex::getOrderPayData($arrOrder['order_id']);
    if (SC_Utils_Ex::isBlank($arrOrder['OrderID'])) {
        $arrOrder['OrderID'] = $arrOrder['order_id'] . '-' . date('dHis');
        $OrderID = $arrOrder['OrderID'];
    }
    (以下省略)

試しに、5行目に、なんか追加してみます。

$arrOrder['OrderID'] = $arrOrder['order_id'] . '-' . date('dHis'. '-ABC');

で、決済してみたところ、

なんか、普通に動いてる!

pg_mulpay_recv.logには、ちゃんと

[OrderID] => 361-18114653-ABC

と、渡されているのに、決済後の処理は、変更前と変わらず、
ちゃんと、PaymentID = 6 「支払い済み」になってる!

***

GMOからの通知後の処理をするpage/LC_Page_Mdl_PG_MULPAY_Recv.phpを調べてみると、

function lfGetOrderId($param_OrderID) {
    list($order_id, $dummy) = explode('-', $param_OrderID);
    if (SC_Utils_Ex::isBlank($order_id) && !SC_Utils::sfIsInt($order_id)) {
        return;
    } else {
        return $order_id;
    }
}

order_idをハイフォンで分解し、先頭のものをOrder_IDとして、返しています。

つまり、このあとに何をつけようが、先頭の2つしか、使われないので、
Order_IDの後に、ハイフォンをつけ、

ドメインが特定出来るように文字を足してやれば良さそうです。

***

* さて、実装です!!

原則、できるだけソースをいじらないをモットーの改造ポリシーですので、
いじるところは、上記のここだけ。

client/SC_Mdl_PG_MULPAY_Client_Base.php

function sendOrderRequest($url, $arrSendKey, $arrOrder, $arrParam, $arrPaymentInfo, $arrMdlSetting) {
    $arrReqParam = $arrParam;
    $arrOrder = SC_Util_PG_MULPAY_Ex::getOrderPayData($arrOrder['order_id']);
    if (SC_Utils_Ex::isBlank($arrOrder['OrderID'])) {
        $arrOrder['OrderID'] = $arrOrder['order_id'] . '-' . date('dHis'). '-ABC';
        $OrderID = $arrOrder['OrderID'];
    }
    (以下省略)

オリジナルに書き加えると、不注意なアップデートで、大番狂わせを食らうので、
ちゃんと、class_exの方に、「sendOrderRequest」をコピーして、使いましょう!

また、文字制限があるようです。
足せる出来るのは、13文字(ハイフォン込)ですが、
実際には一桁目のOrder_IDがまだ3桁なので、一応6桁まで増えるとして、
残り使える文字数は、10文字

こうなると、ドメイン名を直接いれることは、もう無理です。
また、英数・ハイフォン以外は無効な文字として、跳ねられます。

なので、4文字程度の略語か数字で、
ドメイン対応表を基に、割り出すのが良さそうです。

この定義は、config.php で宣言。
変数でやってみたのですが、うまくいかず、
あと、記号が入ってると、決済時にエラーが表示されるので、要注意!
値が宣言されてない場合でも、sitecodeがついてしまいますが、正常に動きます。

define('sitecode', 'HND'); // (例)羽田空港の略

***

あとは、受信側「pg_mulpay_recv.php」で、処理先を振分けてやれば良いだけです。

まず、対応表を作成し、受信したOrder_IDの3つ目の値と照合。

$seller_siteurl = array(
	'HND'	=> 'www.tokyo-airport-bldg.co.jp/',
	'NRT'	=> 'www.narita-airport.jp/jp/',
	'KIX'	=> 'kansai-airport.or.jp/'
	);
if (preg_match('/\d+-\d+-(.{3,})/', $_Request['order_id'], $m) {
  if (isset($seller_siteurl[$m[1]])) {
    file_get_contents(ほげほげ)
} }

あとは、こちらを参考に、コードを足して下さい。

うちの環境では、単にデータベースを切り替えるだけで済むのですが、
細かなところを見直すと、ちょっとおかしな部分があって、
結局、file_get_contetsで、データを投げてることで、偽装しました。

あと、データを投げるときは、order_id の最後の識別文字を削除するように!
でないと、無限ループに陥ります。

うー、今日もマニアックでした・・・

-