thephpleague / omnipay-coinbase

Coinbase driver for the Omnipay PHP payment processing library
MIT License
16 stars 12 forks source link

Error "Unable to parse response body into JSON: 4" when sending request #12

Open konrad-ch opened 7 years ago

konrad-ch commented 7 years ago

Hello, I think I'm doing everything right:

$gateway = Omnipay::create("Coinbase");
$gateway->initialize(['apiKey' => 'my_api_v2_key_with_all_perm', 'secret' => 'my_api_secret', 'accountId' => 'my_acc_id']);
$transaction = $gateway->purchase(['amount' => 10, 'currency' => 'USD', 'description' => 'something']);
$response = $transaction->send();

but getting an error message on send():

Unableto parse response body into JSON: 4

Whats going on? I've managed to check that this error is caused by empty (NULL) json returned by guzzle. But what causes it?

epectechnologies commented 7 years ago

+1, I also ran into this in the InvoicePlane implementation.

https://community.invoiceplane.com/t/topic/4572/6?u=epec

Moorst commented 5 years ago

@konrad-ch did you ever get to the bottom of this? I'm having the same issue

konrad-ch commented 5 years ago

@Moorst If i remember correctly I managed to fix the error, but moved to another btc processor since then and forgot to make a clean patch and share. Please check these files I digged out, maybe you can make a fix based on that:

AbstractRequest.php:

<?php

namespace Omnipay\Coinbase\Message;

/**
 * Coinbase Abstract Request
 *
 * @method \Omnipay\Coinbase\Message\Response send()
 */
abstract class AbstractRequest extends \Omnipay\Common\Message\AbstractRequest
{
    const API_VERSION = 'v2';
    const API_VERSION_STRICT = '2018-03-05';

    protected $liveEndpoint = 'https://api.coinbase.com';
    protected $testEndpoint = 'https://api.sandbox.coinbase.com';

    public function getApiKey()
    {
        return $this->getParameter('apiKey');
    }

    public function setApiKey($value)
    {
        return $this->setParameter('apiKey', $value);
    }

    public function getSecret()
    {
        return $this->getParameter('secret');
    }

    public function setSecret($value)
    {
        return $this->setParameter('secret', $value);
    }

    public function getAccountId()
    {
        return $this->getParameter('accountId');
    }

    public function setAccountId($value)
    {
        return $this->setParameter('accountId', $value);
    }

    public function sendRequest($method, $action, $data = null)
    {
        // don't throw exceptions for 4xx errors
        $this->httpClient->getEventDispatcher()->addListener(
            'request.error',
            function ($event) {
                if ($event['response']->isClientError()) {
                    $event->stopPropagation();
                }
            }
        );

        //$nonce = $this->generateNonce();
        $timestamp = time();
        $url = $this->getEndpoint().$action;
        //$body = $data ? http_build_query($data) : null;

        $httpRequest = $this->httpClient->createRequest($method, $url, null, $data);
        $httpRequest->setHeader('Content-Type', 'application/json');
        $httpRequest->setHeader('CB-ACCESS-KEY', $this->getApiKey());
        $httpRequest->setHeader('CB-ACCESS-SIGN', $this->generateSignature($method, $url, $data, $timestamp));
        $httpRequest->setHeader('CB-ACCESS-TIMESTAMP', $timestamp);
        $httpRequest->setHeader('CB-VERSION', self::API_VERSION_STRICT);

        return $httpRequest->send();
    }

    public function generateNonce()
    {
        return sprintf('%0.0f', round(microtime(true) * 1000000));
    }

    public function generateSignature($method, $url, $body, $timestamp)
    {
        $message = $timestamp.strtoupper($method).parse_url($url, PHP_URL_PATH).$body;

        return hash_hmac('sha256', $message, $this->getSecret());
    }

    /*
    public function generateSignature($url, $body, $nonce)
    {
        $message = $nonce.$url.$body;

        return hash_hmac('sha256', $message, $this->getSecret());
    }
    */

    protected function getEndpoint()
    {
        $base = $this->getTestMode() ? $this->testEndpoint : $this->liveEndpoint;
        return $base . '/' . self::API_VERSION;
    }
}

PurchaseRequest.php

<?php

namespace Omnipay\Coinbase\Message;

/**
 * Coinbase Purchase Request
 *
 * @method \Omnipay\Coinbase\Message\PurchaseResponse send()
 */
class PurchaseRequest extends AbstractRequest
{
    public function getData()
    {
        $this->validate('amount', 'currency', 'description');

        $data = [
            "amount" => $this->getAmount(),
            "currency" => $this->getCurrency(),
            "name" => $this->getDescription()
        ];
        /*
        $data = array();
        $data['account_id'] = $this->getAccountId() ?: null;
        $data['button'] = array();
        $data['button']['name'] = $this->getDescription();
        $data['button']['price_string'] = $this->getAmount();
        $data['button']['price_currency_iso'] = $this->getCurrency();
        $data['button']['success_url'] = $this->getReturnUrl();
        $data['button']['cancel_url'] = $this->getCancelUrl();
        $data['button']['callback_url'] = $this->getNotifyUrl();
        */

        return $data;
    }

    public function sendData($data)
    {
        //$httpResponse = $this->sendRequest('POST', '/buttons', $data);
        $httpResponse = $this->sendRequest('POST', '/checkouts', json_encode($data));

        return $this->response = new PurchaseResponse($this, $httpResponse->json());
    }
}