Search code examples
phprestcurlchanneladvisor

Working with ChannelAdvisor REST API in PHP - requests not working in CURL


I would like to integrate with ChannelAdvisor REST API using the SOAP Credentials Flow.

Based on their documentation, I have setup the following in PostMan (rest client in Chrome browser) like this:

enter image description here

enter image description here

When I make the rest; the rest api server returns the expected response:

enter image description here

So, I tried to replicate this in PHP with the following class:

<?php

class ChannelAdvisorREST {

    /**
     * ChannelAdvisor constants & properties
     */
    const BASE_URL = 'https://api.channeladvisor.com/v1';
    private $config;

    /**
     * Class constructor
     */
    public function __construct()
    {
        $this->config = \Config::get('channeladvisor');
    }

    // TEST
    public function test($accountId)
    {
        // var_dump($this->config);

        var_dump(self::getAccessToken($accountId));
    }
    // TEST

    /**
     * Method to get access token from rest server.
     *
     * @param $accountId
     * @return string
     */
    private function getAccessToken($accountId)
    {
        return self::curlPOST('/oauth2/token', [
            'client_id' => $this->config['api_app_id'],
            'grant_type' => 'soap',
            'scope' => 'inventory',
            'developer_key' => $this->config['api_developer_key'],
            'password' => $this->config['api_password'],
            'account_id' => $accountId
        ]);
    }

    /**
     * Method to generate a HTTP POST request
     *
     * @param $endpoint
     * @param $fields
     * @return string
     */
    private function curlPOST($endpoint, $fields = array())
    {
        // Open connection
        $ch = curl_init();

        // Set the url, number of POST vars, POST data
        curl_setopt($ch, CURLOPT_USERPWD, $this->config['api_app_id'] .':'. $this->config['api_shared_secret']);
        curl_setopt($ch, CURLOPT_URL, self::BASE_URL . $endpoint);
        curl_setopt($ch, CURLOPT_POST, count($fields));
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields, '', '&'));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/x-www-form-urlencoded'
        ));

        // Execute post request
        $result = curl_exec($ch);

        // Close connection
        curl_close($ch);

        // Finished
        return $result;
    }
}

When I execute the test($accId) method on this class, I get the following response:

boolean false

Any idea why it isn't quite working as same as the PostMan test?

P.S. I have already verified all the config/parms etc... are correct and same as my PostMan test. This class is a snipped version from my original code (created in Laravel 4.2, but this issue is not related to Laravel).


Solution

  • I have found the problem. The issue was caused by my php not being configured with curl.cainfo.

    I found this by adding the following debug code to my curlPOST method like this:

    private function curlPOST($endpoint, $fields = array())
    {
        // Open connection
        $ch = curl_init();
    
        // Set the url, number of POST vars, POST data
        curl_setopt($ch, CURLOPT_USERPWD, $this->config['api_app_id'] .':'. $this->config['api_shared_secret']);
        curl_setopt($ch, CURLOPT_URL, self::BASE_URL . $endpoint);
        curl_setopt($ch, CURLOPT_POST, count($fields));
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields, '', '&'));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/x-www-form-urlencoded'
        ));
        curl_setopt($ch, CURLOPT_VERBOSE, true);
        $verbose = fopen('php://temp', 'w+');
        curl_setopt($ch, CURLOPT_STDERR, $verbose);
    
        // Execute post request
        $result = curl_exec($ch);
    
        // Debug error
        if ($result === FALSE) {
            printf("cUrl error (#%d): %s<br>\n", curl_errno($ch), htmlspecialchars(curl_error($ch)));
            rewind($verbose);
            $verboseLog = stream_get_contents($verbose);
            echo "Verbose information:\n<pre>", htmlspecialchars($verboseLog), "</pre>\n";
        }
        @fclose($verbose);
    
        // Close connection
        curl_close($ch);
    
        // Finished
        return $result;
    }
    

    This outputted the following error message:

    cUrl error (#60): SSL certificate problem: unable to get local issuer certificate
    Verbose information:
    * Hostname was found in DNS cache
    * Hostname in DNS cache was stale, zapped
    *   Trying 216.27.89.14...
    * Connected to api.channeladvisor.com (216.27.89.14) port 443 (#7)
    * SSL certificate problem: unable to get local issuer certificate
    * Closing connection 7
    boolean false
    

    Which helped me track down the issue with my php.