Friday, May 5, 2017

Connect to Xero Private Application Using Php Application

The link below is for Xero dashboard:
https://my.xero.com

Very first you need to create an application in Xero, follow the link below to create application:
https://app.xero.com/Application/

Click on "Add Application" and fill up required fields. In this step you will need public/private key pair. To generate public/pair key follow the link. You need to upload "publickey.cer" in xero application form and other file named "privatekey.perm" need to place in a folder named "XeroCerts" in your application directory.




After click save you will forward to next page, from where you can get Consumer Key & Consumer Secret which will need to connect to your organization via this application.





You are done with create application in Xero.

Next step to write some PHP script to connect to Xero.
Below is a small PHP script which help you to connect to Xero.


<?php
define('BASE_PATH', dirname(__FILE__));
$configs = array(
    "consumer_key" => "QM6QQSESK2KVGTRUGY1........",
    "consumer_secret" => "LHAHIPRIIP6ZZASIHPP........",
    "core_version" => "2.0",
    "payroll_version" => "1.0",
    "file_version" => "1.0",
    "rsa_private_key" => BASE_PATH . "/XeroCerts/privatekey.pem",
    "rsa_public_key" => BASE_PATH . "/XeroCerts/publickey.cer",
    "application_type" => "Private",
    "oauth_callback" => "oob",
    "user_agent" => "Trial #3"
);

$parameters = array();

$xero_connector = new XeroConnector($configs, $parameters);
$organization_data = $xero_connector->execute("GET", "Organisation");
XeroConnector::prettyPrint($organization_data);

class XeroConnector
{
    private $configs = null;
    private $headers = array();
    private $parameters = array();

    function __construct($configs, $parameters)
    {
        $this->configs = $configs;
        $this->parameters = $parameters;
    }

    function execute($method, $target, $post_body = "")
    {
        $this->post_body = $post_body;
        $this->method = strtoupper($method);
        $this->path = "https://api.xero.com/api.xro/2.0/$target";
        $this->nonce_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        $this->buildParameters();
        $this->sign();
        return $this->curlRequest($this->sign["signed_url"]);
    }

    private function sign()
    {
        $this->parameters["oauth_signature"] = $this->generateSignature();
        $this->sign = array(
            'parameters' => $this->parameters,
            'signature' => $this->escape($this->parameters["oauth_signature"]),
            'signed_url' => $this->path . '?' . $this->normalizeParameters('true'),
            'header' => $this->getHeaderString(),
            'sbs' => $this->sbs
        );
    }

    private function curlRequest($url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

        $this->headers['Accept'] = 'application/json';
        switch ($this->method) {
            case "GET":
                $this->content_length = 0;
                break;
            case 'POST':
                $this->headers['Content-Length'] = strlen($this->post_body);
                curl_setopt($ch, CURLOPT_POST, TRUE);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $this->post_body);
                $this->headers['Content-Type'] = 'application/x-www-form-urlencoded';
                break;
            case 'PUT' :
                $this->headers['Content-Length'] = strlen($this->post_body);
                $fh = tmpfile();
                fwrite($fh, $this->post_body);
                rewind($fh);
                curl_setopt($ch, CURLOPT_PUT, true);
                curl_setopt($ch, CURLOPT_INFILE, $fh);
                curl_setopt($ch, CURLOPT_INFILESIZE, $this->headers ['Content-Length']);
                $this->headers['Content-Type'] = 'application/x-www-form-urlencoded';
                break;
            default :
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->method);
        }

        if (count($this->headers) > 0) {
            $headers = array();
            foreach ($this->headers as $k => $v) {
                $headers [] = trim($k . ': ' . $v);
            }
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        }

        $response = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        curl_close($ch);

        return array('body' => json_decode($response), 'code' => $code);
    }

    private function getHeaderString($args = array())
    {
        $result = 'OAuth ';

        foreach ($this->parameters as $pName => $pValue) {
            if (strpos($pName, 'oauth_') !== 0)
                continue;
            if (is_array($pValue)) {
                foreach ($pValue as $val) {
                    $result .= $pName . '="' . $this->escape($val) . '", ';
                }
            } else {
                $result .= $pName . '="' . $this->escape($pValue) . '", ';
            }
        }
        return preg_replace('/, $/', '', $result);
    }

    private function generateSignature()
    {
        switch ($this->parameters['oauth_signature_method']) {
            case 'RSA-SHA1':
                $private_key = openssl_pkey_get_private($this->readFile($this->configs['rsa_private_key']));
                $this->sbs = $this->escape($this->method) . "&" . $this->escape($this->path) . "&" .
                    $this->escape($this->normalizeParameters());
                openssl_sign($this->sbs, $signature, $private_key);
                openssl_free_key($private_key);
                return base64_encode($signature);
            case 'PLAINTEXT':
                return urlencode($this->configs["consumer_secret"]);
            case 'HMAC-SHA1':
                $this->sbs = $this->escape($this->method) . '&' . $this->escape($this->path) . '&' . $this->escape($this->normalizeParameters());
                return base64_encode(hash_hmac('sha1', $this->sbs, $this->configs["consumer_secret"], true));
            default:
                throw new OAuthSimpleException('Unknown signature method for OAuthSimple');
        }
    }

    private function normalizeParameters($filter = 'false')
    {
        $elements = array();
        ksort($this->parameters);
        foreach ($this->parameters as $paramName => $paramValue) {
            if ($paramName == 'xml') {
                if ($filter == "true")
                    continue;
            }
            if (preg_match('/\w+_secret/', $paramName))
                continue;
            if (is_array($paramValue)) {
                sort($paramValue);
                foreach ($paramValue as $element)
                    array_push($elements, $this->escape($paramName) . '=' . $this->escape($element));
                continue;
            }
            array_push($elements, $this->escape($paramName) . '=' . $this->escape($paramValue));

        }
        return join('&', $elements);
    }

    private function readFile($file_path)
    {
        $fp = fopen($file_path, "r");
        $file_contents = fread($fp, 8192);
        fclose($fp);
        return $file_contents;
    }

    private function escape($string)
    {
        if ($string === 0)
            return 0;
        if (empty($string))
            return '';
        if (is_array($string))
            throw new OAuthSimpleException('Array passed to _oauthEscape');

        $string = rawurlencode($string);
        $string = str_replace('+', '%20', $string);
        $string = str_replace('!', '%21', $string);
        $string = str_replace('*', '%2A', $string);
        $string = str_replace('\'', '%27', $string);
        $string = str_replace('(', '%28', $string);
        $string = str_replace(')', '%29', $string);
        return $string;
    }

    private function buildParameters()
    {
        $this->parameters["oauth_nonce"] = $this->getNonce(5);
        $this->parameters["oauth_token"] = $this->configs["consumer_key"];
        $this->parameters["oauth_version"] = "1.0";
        $this->parameters["oauth_timestamp"] = time();
        $this->parameters["oauth_consumer_key"] = $this->configs["consumer_key"];
        $this->parameters["oauth_signature_method"] = "RSA-SHA1";
    }

    private function getNonce($length = 5)
    {
        $result = '';
        $cLength = strlen($this->nonce_chars);
        for ($i = 0; $i < $length; $i++) {
            $rnum = rand(0, $cLength);
            $result .= substr($this->nonce_chars, $rnum, 1);
        }
        return $result;
    }

    public static function prettyPrint($o)
    {
        echo "<pre>";
        print_r($o);
        echo "</pre>";
    }
}


And output will be like this on execution the above script:


Array
(
    [body] => stdClass Object
        (
            [Id] => 0d1fe562-8621-4bbb-b249-6a5ea051f308
            [Status] => OK
            [ProviderName] => Trial #3
            [DateTimeUTC] => /Date(1494001316337)/
            [Organisations] => Array
                (
                    [0] => stdClass Object
                        (
                            [APIKey] => W2N0UZYHPLFSPABKS2SS42AF5GDKMD
                            [Name] => Trial #3
                            [LegalName] => Trial #3
                            [PaysTax] => 1
                            [Version] => AU
                            [OrganisationType] => COMPANY
                            [BaseCurrency] => AUD
                            [CountryCode] => AU
                            [IsDemoCompany] => 
                            [OrganisationStatus] => ACTIVE
                            [FinancialYearEndDay] => 30
                            [FinancialYearEndMonth] => 6
                            [SalesTaxBasis] => ACCRUALS
                            [SalesTaxPeriod] => QUARTERLY1
                            [DefaultSalesTax] => Tax Exclusive
                            [DefaultPurchasesTax] => Tax Inclusive
                            [CreatedDateUTC] => /Date(1493991850000)/
                            [OrganisationEntityType] => COMPANY
                            [Timezone] => AUSEASTERNSTANDARDTIME
                            [ShortCode] => !GS3w5
                            [OrganisationID] => c653628f-a901-4836-8de1-6b00d23664fe
                            [LineOfBusiness] => Software Development & Consulting
                            [Addresses] => Array
                                (
                                )

                            [Phones] => Array
                                (
                                )

                            [ExternalLinks] => Array
                                (
                                )

                            [PaymentTerms] => stdClass Object
                                (
                                )

                        )

                )

        )

    [code] => 200
)



No comments:

Post a Comment