🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

2回答

2142閲覧

決済完了結果のXMLの取得方法が1週間以上まったくわかりません。(PHPで構築したネットショップにカード決済機能を導入)

mukufusa

総合スコア12

XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

2クリップ

投稿2019/10/10 17:26

前提・実現したいこと

XMLの結果取得の方法が全くわからず1週間以上はまってます。

プログラマ初心者ですが、PHPでネットショップを自力で構築しました。
現在、イプシロンという決済代行会社のクレジットカード決済(リンク方式ではなくトークン方式)を導入しようとしています。

※トークン方式は、自社サイトのカート内で決済が完結する方式。リンク方式は外部サイトに飛ばされるため、カゴ落ちする可能性が高い。

イプシロン 開発者向け情報(トークン決済 送受信パラメータの仕様)
https://www.epsilon.jp/developer/spec02.html

発生している問題・エラーメッセージ

必要な情報(お客様情報や決済金額など)をPOST方式でイプシロンに送信し、なんとか決済を完了するところまでできました。
(イプシロンの管理画面で決済確認済。XMLを見ても result="1" で正常に完了)

しかし、最後の決済結果がXMLでイプシロン側の画面に表示され、それを取得する方法がいくら調べてもまったくわかりません。
決済結果を取得し、解析し、購入完了のページをお客様に表示させたいのです。

ちなみに、XMLを扱うのはまったくの初めてです。

該当のソースコード

以下、送信Formです。

<form action="https://beta.epsilon.jp/cgi-bin/order/direct_card_payment.cgi" method="post"> <input type=""text name="contract_code" value="12345678"> <input type=""text name="user_id" value="7"> <input type=""text name="user_name" value="佐藤太郎"> <input type=""text name="user_mail_add" value="mukufusa@gmail.com"> <input type=""text name="item_code" value="XXXXXX"> <input type=""text name="item_name" value="〇〇〇〇"> <input type=""text name="order_number" value="00000007"> <input type=""text name="st_code" value="11000-0000-00000"> <input type=""text name="mission_code" value="1"> <input type=""text name="item_price" value="9800"> <input type=""text name="process_code" value="1"> <input type=""text name="memo1" value="aaa"> <input type=""text name="memo2" value="aaa"> <input type=""text name="card_st_code" value="10"> <input type=""text name="pay_time" value="NULL"> <input type=""text name="tds_check_code" value="1"> <input type=""text name="keitai" value="0"> <input type=""text name="kari_flag" value="1"> <input type=""text name="security_check" value="1"> <input type=""text name="user_agent" value="XXXXX"> <input type="text" name="token" value="<?php print $token; ?>"> </form>

以下、画面に表示された決済結果のXMLです。

<?xml version="1.0" encoding="x-sjis-cp932"?>

<Epsilon_result>
<result acsurl="" />
<result err_code="" />
<result err_detail="" />
<result kari_flag="1" />
<result pareq="" />
<result result="1" />
<result trans_code="1068179" />
</Epsilon_result>

試したこと

XMLについて基本的なところを調べましたが、XMLファイル(.xml)に直接アクセスして内容を取得する方法が書かれたページが多く「 simplexml_load_file() 」、今回のケースのようにCGIに対して値を送信しその結果として表示されたXMLを取得する方法についてはいくら探しても見つけることができませんでした。サポートに質問しても「XMLの処理については案内できない」とのことでした。

初歩的な質問かもしれませんが、自力では解決方法が見つけられなかったため、何卒よろしくお願いいたします。

補足情報

以下、サポートより頂いた回答になります。

弊社から送信されたxmlを貴サイト側にて解析・処理いただくことで
購入者様の画面へ決済完了画面を表示していただく仕様となっております。

なお、貴サイト側での解析方法等につきましては
貴社環境に依存するため、恐れ入りますが
弊社より具体的なご案内はできかねますことをご了承ください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2019/10/11 00:54

それ以前に初心者で何もわからない状態で決済の仕組みを導入していることに驚愕です。 セキュリティは問題なく仕込めているのでしょうか。商法など関連する法律についてはきちんと網羅されているのでしょうか。 とても自力できちんとしたものを運用できるようには思えません。 諦めろと言う意味ではなく利用者に損害を与えないような体制や仕組みがきちんと考慮されてるかの懸念です。
mukufusa

2019/10/14 13:16

クレジットカード情報はトークンで暗号化され、念のため変数からもすぐ破棄されるコードになっています。もちろん自分のDBにも情報が保持されることがないので大丈夫だと思っていましたが、この状態でも致命的な問題があるのでしょうか。いずれにせよ、まだセキュリティに関しては知識がないので、正式リリースの前にすでに購入してある分厚い本2冊を読んで勉強したいと思います。ご忠告頂きありがとうございました。
guest

回答2

0

ベストアンサー

POST方式でイプシロンに送信し、なんとか決済を完了するところまでできました。
(イプシロンの管理画面で決済確認済。XMLを見ても result="1" で正常に完了)
しかし、最後の決済結果がXMLでイプシロン側の画面に表示され、それを取得する方法がいくら調べてもまったくわかりません。

POSTメソッドでイプシロン側に送信し、その送信による決済結果がイプシロン側の画面に表示される、ということは、サーバーサイドからみて通常とは逆の立場になります。通常は人間が操作するWEBブラウザーがクライアントとなり、PHPでホスティングしているPHPプログラムがそのサーバーとなります。イプシロンへ決済のために送信するときは、サーバーサイドのPHPプログラムからイプシロンのCGIを呼び出すかたちですが、これはサーバーサイドのPHPプログラムがクライアントであり、イプシロンのCGIがサーバー、すなわち通常とは逆の立場となるわけです。

質問中では「送信Form」としてHTMLのformタグの内容を示されていますが、WEBブラウザーでHTMLのフォームから決済要求の送信(submit)をしたのでしょうか?そうだとするとWEBブラウザーとイプシロン間で処理が完結してしまうので、決済結果のXMLを取得する余地が無くなります。そうではなく、質問者さんが作成したPHPのサーバーサイドプログラムからイプシロンへ送信するのが前提であれば、以下のような流れでイプシロンから返信されるXMLのレスポンスを取り扱うことができます。(と、言いますかイプシロンの送受信パラメータ(≒API)仕様をみるとそういう使い方が前提のはずです)
質問者さんはプログラマ初心者、と言うことでしたので、少し冗長ですが、細かく追って行きます。

送受信パラメータの説明をみると、テスト用のサーバーが用意されているのでこちらを相手に試します。httpsでホスティングされていますが、幸いhttpでも動作しましたので、一部httpでやり取りしてみています。

まず、質問者さんご提示の送信Formを実際にHTMLからsubmitした場合、HTTPリクエストとしては以下のようになりました。つまり、おおむねこの内容で送信することで、決済要求として等価な動きになるはずです。

POST /cgi-bin/order/direct_card_payment.cgi HTTP/1.1 Host: localhost:8000 Connection: keep-alive Content-Length: 389 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: null Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Sec-Fetch-Site: cross-site Accept-Encoding: gzip, deflate, br Accept-Language: ja,en-US;q=0.9,en;q=0.8 contract_code=12345678&user_id=7&user_name=%E4%BD%90%E8%97%A4%E5%A4%AA%E9%83%8E&user_mail_add=mukufusa%40gmail.com&item_code=XXXXXX&item_name=item_name_dummy&order_number=00000007&st_code=11000-0000-00000&mission_code=1&item_price=9800&process_code=1&memo1=aaa&memo2=aaa&card_st_code=10&pay_time=NULL&tds_check_code=1&keitai=0&kari_flag=1&security_check=1&user_agent=XXXXX&token=tokenvalue

次に、ncコマンドを利用して、上記のPOSTリクエストをイプシロンのサーバーへHTTPで送信します。
すると、イプシロンのテスト用サーバーからは以下の内容でHTTPレスポンスが受信できます。

$ nc beta.epsilon.jp 80 < post.txt HTTP/1.1 200 OK Date: Thu, 10 Oct 2019 18:48:44 GMT Server: Apache Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/xml; charset=CP932 11b <?xml version="1.0" encoding="x-sjis-cp932"?> <Epsilon_result> <result acsurl="" /> <result err_code="607" /> <result err_detail="%8C_%96%F1%83R%81%5B%83h%8C%9F%8D%F5%83G%83%89%81%5B" /> <result pareq="" /> <result result="9" /> <result trans_code="" /> </Epsilon_result> 0

それらしいHTTPレスポンスです。result="9"を示しているので正常終了ではありませんが、err_detailの値をURLデコードすると「契約コード検索エラー」なので、それっぽく動いていそうです。では、これをPHPのプログラムコードに落としてやり取りしてみます。セットしている値は依然としてダミーの値ですが、httpではなく、ちゃんとhttpsを使ってみます。

PHP

1<?php 2$url = "https://beta.epsilon.jp/cgi-bin/order/direct_card_payment.cgi"; 3$data = array( 4 'contract_code' => "12345678", 5 "user_id" => "7", 6 "user_name" => "hoge", 7 "user_mail_add" => "hoge@mail", 8 "item_code" => "XXXXXX", 9 "item_name" => "item_name_dummy", 10 "order_number" => "00000007", 11 "st_code" => "11000-0000-00000", 12 "mission_code" => "1", 13 "item_price" => "9800", 14 "process_code" => "1", 15 "memo1" => "aaa", 16 "memo2" => "aaa", 17 "card_st_code" => "10", 18 "pay_time" => "NULL", 19 "tds_check_code" => "1", 20 "keitai" => "0", 21 "kari_flag" => "1", 22 "security_check" => "1", 23 "user_agent" => "XXXXX", 24 "token" => "tokenvalue", 25); 26 27$content = http_build_query($data); 28$options = array('http' => array( 29 'method' => 'POST', 30 'content' => $content 31)); 32 33 34$contents = file_get_contents($url, false, stream_context_create($options)); 35 36print("CONTENTBODY>>>>\n"); 37print($contents); 38print("\n"); 39print("<<<<CONTENTBODY\n"); 40

このコード(t01.php)を実際に実行すると、以下のようになります。

bash

1$ php t01.php 2PHP Notice: file_get_contents(): Content-type not specified assuming application/x-www-form-urlencoded in /cygdrive/d/project/test/t01.php on line 34 3CONTENTBODY>>>> 4<?xml version="1.0" encoding="x-sjis-cp932"?> 5<Epsilon_result> 6 <result acsurl="" /> 7 <result err_code="607" /> 8 <result err_detail="%8C_%96%F1%83R%81%5B%83h%8C%9F%8D%F5%83G%83%89%81%5B" /> 9 <result pareq="" /> 10 <result result="9" /> 11 <result trans_code="" /> 12</Epsilon_result> 13<<<<CONTENTBODY 14 15$ 16

file_get_contents関数の返り値$contentsにHTTPレスポンス中のコンテントボディ部であるXMLでの決済結果が取得できています。あとは続けてPHPのプログラム内でXML内容の処理を行っていけば良いのではないでしょうか。

尚、上記の私の書いたサンプルコードはフレームワークも使わない生のPHPコードですので、質問者さんが何かしらフレームワークを使われているのであれば、適当に書き直してください。

(テスト/確認環境:Windows 7, Cygwin PHP7.3.7)

投稿2019/10/10 20:20

dodox86

総合スコア9256

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mukufusa

2019/10/12 15:11

迅速かつ大変ご丁寧なご回答頂き本当にありがとうございます! やはり通常とは逆の立場での処理だったのですね。なんとなく気づいていましたが、やり方を検索するためのキーワードもわからなかったのでとても助かりました。 file_get_contents 関数 と stream_context_create を組み合わせて使いPOST送信するのですね! XMLの値を取得して出力しても、画面には何も表示されずに少し戸惑いましたが、右クリックからソースを見るとXMLが出力されていて、ただ、XMLの場合はタグなので画面には表示されなかったみたいです。 取得したXMLはStringだったので、これまたそれなりに苦戦しましたが simplexml_load_string で配列に変換してそれぞれの値を取り出しました。 他社システムとの連携は、初心者はわからない知識が多重に重なるため非常に難しかったです。 クレジットカード決済導入には何と15日もかかってしまいましたが、ここで質問したら一日で解決しました。本当に自分でわからないとこは、今度からもう少し早めにこのサイトで質問してみようと思います。 本当にありがとうございました!
dodox86

2019/10/13 09:30

> file_get_contents 関数 と stream_context_create を組み合わせて使いPOST送信するのですね! file_get_contentsを使ったのはテスト用サーバーとダミーのデータでPOSTをした限り、「HTTPレスポンス中のXMLのコンテントボディ部を簡単に取得し、確認できたから」なのですが、少し気になったのは、HTTPレスポンス中の"Transfer-Encoding: chunked"ヘッダーとXMLの前後の長さデータ(回答中の実行例 "11b"と"0"の部分)です。 "Transfer-Encoding: chunked"は"chunked"と示されているようにデータが細切れになることを意味していますが、今回はたまたま1回で返されているので、file_get_contentsをそのまま使えている様子です。もしこれが複数になってしまった場合、file_get_contentsで望みの結果を得られるか私の方では不確かなので、気に留めておいた方が良いかもしれません。上記、念のため申し添えておきます。 https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Transfer-Encoding#Directives
mukufusa

2019/10/14 13:12

HTTPでリクエストを送信して結果が確認できたからfile_get_contentsを使ったのですね。"Transfer-Encoding: chunked"に関してはかしこまりました。ご丁寧に補足して頂きありがとうございましたm(__)m
guest

0

参考まで、XMLを取得した後の処理を記載しておきます。
決済完了のときとエラーのときの[result]の配列の場所が違うので注意して下さい。

$string = file_get_contents($url, false, stream_context_create($options));

$string = mb_convert_encoding($string,"UTF-8");
$string = str_replace("x-sjis-cp932","UTF-8",$string);

//var_dump($string); 型と値を出力する。XMLの内容はタグで囲まれているため""のみ表示される。XMLはソースに表示されています。

$xml = simplexml_load_string($string);
$xml_array = json_decode( json_encode( $xml ), TRUE );

if($xml_array['result'][5]['@attributes']['result'] == 1){
print '<font color="blue">決済完了</font>';
print '<br>';
print 'result = ';
print ($xml_array['result'][5]['@attributes']['result']);
} else {
print '<font color="red">決済結果 = エラー</font>';
print '<br>';
print 'result = ';
print ($xml_array['result'][4]['@attributes']['result']);
}

投稿2019/10/12 15:17

mukufusa

総合スコア12

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2019/10/13 09:38

ご報告ありがとうございます。私の方では正当な契約情報を持っていないのもあって完全な形では試せませんでしたが、承知しました。 (尚、コードはマークダウン機能を使って提示された方がより読みやすくなって良いです。次の機会にはそのようにすることをお勧めします)
mukufusa

2019/10/14 13:19 編集

契約情報を公開できない状況にもかかわらず、試してご教授頂き本当にありがとうございました。コードを公開する場合はマークダウン機能を使うのですね。かりこまりました。次回からそうしたいと思います!
m.ts10806

2019/10/14 20:03

質問も回答も編集できるので、今回から対応されたほうが良いかと思います(次回が必ずあるとは限らないので)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問