質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

90.11%

【cURL】ターミナルでは成功するのにPHPでは失敗する

解決済

回答 2

投稿

  • 評価
  • クリップ 2
  • VIEW 6,484

k_koichi

score 11

k_koichiと申します。
Rubyで似たような質問をされている方がおりましたが、その方法ではうまくいかなかった為質問させて頂きます。

決済サービスのSPIKEにてAPIでのやりとりを実現しようとしておりますが、
コンソールではうまくいくのですが、PHPでは失敗してしまいます。

[コンソール]
curl "https://api.spike.cc/v1/tokens" \
  -u "sk_test_apikey:" \
  -d "card[number]=4444333322221111" \
  -d "card[exp_month]=3" \
  -d "card[exp_year]=2017" \
  -d "card[cvc]=111" \
  -d "card[name]=TARO SPIKE" \
  -d "currency=JPY" \
  -d "email=foo@example.com"
<?php
include(dirname(__FILE__).'/../const.php');
// 問い合わせ先
$host = API_URL . 'tokens';
// APIキー
$key = API_KEY;

// ホストに接続
$ch = curl_init($host);

// データ
$data = array(
    "card[number]" => 4444333322221111,
    "card[exp_month]" => 3,
    "card[exp_year]" => 2017,
    "card[cvc]" => 111,
    "card[name]" => 'TARO SPIKE',
    "currency" => 'JPY',
    "email" => 'foo@example.com'
);
// データをJSONエンコードする
$json_data = json_encode($data);

//POSTを指定
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');

// ヘッダーにJSONを指定
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json'));

// 送信するデータをセット
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data);

// TRUE を設定すると出力結果を何も加工せずに返します。
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

// 接続に使用するユーザー名とパスワード。 "[key]:" 形式で指定します。
curl_setopt($ch, CURLOPT_USERPWD, $key . ':');

// HTTP/1.1 を使用する
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);

$return = curl_exec($ch);
curl_close($ch);

// 値をJSONデコードして配列化する
$json = json_decode($return, true);
// ダンプする
print_r($json);
?>

PHPでのリクエスト結果は、以下のようなエラーメッセージが返ってきます。

Array (
  [error] => Array (
      [type] => invalid_request_error
      [message] => カード名義を入力してください。 カード番号を入力してください。 セキュリティーコードを入力してください。 有効期限(月)を入力してください。 有効期限(年)を入力してください。 指定したクレジットカードは未対応です。
  )
)

card[...]の指定方法が間違っている為に、認識されていないように見えます。
正しい指定方法を教えていただけないでしょうか。

宜しくお願いいたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

  • ライブラリや設定ファイルを読み込む用途では, include より require のほうが適切です.また括弧は省略可能です.
  • PHP5.3以降は dirname(__FILE__) の代わりに __DIR__ が使えます. 
  • Content-Typeおよびパラメータの作り方が間違っています. 送信形式はapplication/jsonではなくapplication/x-www-form-urlencodedです. なお,デフォルトでこの値が使わるので明示的に設定する必要はありません.
  • PHP5.1.3以降は curl_setopt() より curl_setopt_array() を使う方が読みやすいです.
  • PHP5.4以降は array() より [] と書いたほうが読みやすいです.
  • POST指定は CURLOPT_POST で行うのが普通です.
  • HTTPバージョンはほとんどの場合デフォルトで1.1なので明示的に指定する必要はありません.ちなみに1.0であったとしても正しく処理されると思います.
  • 配列が複数行に渡る場合は,末尾要素にも,を付けましょう,このことはマニュアルが推奨しています
  • POSTされるデータはネストした配列としても表現でき,こちらのほうが読みやすくなるはずです.
  • クエリの組み立てにはhttp_build_queryを使いましょう.この関数の動作は引数を省略するとphp.iniに依存するので,第3引数まで必ず指定しましょう.
  • カード番号は文字列で表現すべきです.32bit環境で動作させると整数がオーバーフローする可能性があります.
  • json_decodeは第2引数にtrueを指定せずにオブジェクトとして扱うのがおすすめです. 配列なら $a['b']['c'][0]['d'][1] とアクセスするところをオブジェクトなら $a->b->c[0]->d[1] と表現でき,こちらのほうが読みやすく書きやすいです.
  • 結果の確認には print_r よりも var_dump を使いましょう. print_r は型が判別出来ないので不正確なデバッグ情報しか得られません.
  • HTMLが後ろに続かない場合 ?> は省略しましょう.このことはマニュアルが推奨しています

せっかくなのでエラー処理とかもキッチリ書いてみました.

 SpikeException.php

<?php

class SpikeException extends \RuntimeException {

    private $type;
    private $status;

    public function __construct($message, $type, $status) {
        parent::__construct($message);
        $this->type = $type;
        $this->status = $status;
    }

    public function __toString() {
        return "[$this->status] $this->type: {$this->getMessage()}";
    }

    public function getType() {
        return $this->type;
    }

    public function getStatusCode() {
        return $this->status;
    }

}

 SpikeClient.php

<?php

class SpikeClient {

    private $apikey;
    private $baseurl;

    public function __construct($apikey, $baseurl = 'https://api.spike.cc/v1') {
        $this->apikey = $apikey;
        $this->baseurl = $baseurl;
    }

    public function post($endpoint, array $params = []) {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => "$this->baseurl$endpoint",
            CURLOPT_USERPWD => "$this->apikey:",
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => http_build_query($params, '', '&'),
        ]);
        $r = json_decode(curl_exec($ch));
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if (curl_errno($ch)) {
            throw new SpikeException(curl_error($ch), 'curl_error', 0);
        }
        if ($status >= 400) {
            if (isset($r->error)) {
                throw new SpikeException($r->error->message, $r->error->type, $status);   
            }
            throw new SpikeException('不明なエラー', 'unknown', $status);   
        }
        return $r;
    }

}

 main.php

<?php

require_once __DIR__ . '/../SpikeClient.php';
require_once __DIR__ . '/../SpikeExeption.php';

try {

    $client = new SpikeClient('XXXXX');
    var_dump($client->post('/tokens', [
        'card' => [
            'number' => '4444333322221111',
            'exp_month' => 3,
            'exp_year' => 2017,
            'cvc' => 111,
            'name' => 'TARO SPIKE',
        ],
        'currency' => 'JPY',
        'email' => 'foo@example.com',
    ]));

} catch (SpikeException $e) {

    var_dump((string)$e);

}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/13 16:51

    CertaiN様

    PHPの基本的な部分までご指摘頂きありがとうございます。
    大変参考になり、無事解決致しました。

    キャンセル

0

http://qiita.com/issei-m/items/4860af70889cae0de9be
ここで紹介されてるライブラリを使ってみては

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/13 16:49

    redara様

    ありがとうございます、ぜひ参考にさせて頂きます。

    キャンセル

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

  • ただいまの回答率 90.11%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる