The very first step you make a connection between your application and Xero API. To do so you need to create and application in Xero and establish a connection. Follow the below link to see how PHP communicates with Xero Application:
http://pritomkumar.blogspot.com/2017/05/connect-to-xero-private-application.html
And below is full PHP script which will create Contacts in Xero:
Below is a screen-shot of my Xero portal:
Output will be as follows:
http://pritomkumar.blogspot.com/2017/05/connect-to-xero-private-application.html
And below is full PHP script which will create Contacts in Xero:
<?php
define('BASE_PATH', dirname(__FILE__));
$configs = array(
"consumer_key" => "OVLVISLORWW72YRDYAV3KI........",
"consumer_secret" => "HRTPKPBSSBNN4TA32BKW.......",
"core_version" => "2.0",
"payroll_version" => "1.0",
"file_version" => "1.0",
"rsa_private_key" => BASE_PATH . "/XeroCerts/privatekey.pem",
"application_type" => "Private",
"oauth_callback" => "oob",
"user_agent" => "Trial #3"
);
$parameters = array();
createContact($configs, $parameters);
function createContact($configs, $parameters)
{
$post = array(
"Contacts" => array(
"Contact" => array(
"Name" => "Xero Contact 1"
),
"Contact 2" => array(
"Name" => "Xero Contact 2"
)
)
);
$xero_connector = new XeroConnector($configs, $parameters);
$contact_data = $xero_connector->execute("POST", "Contact", $post);
XeroConnector::prettyPrint($contact_data);
}
class XeroConnector
{
private $configs = null;
private $headers = array();
private $parameters = array();
private $nonce_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
function __construct($configs, $parameters)
{
$this->configs = $configs;
$this->parameters = $parameters;
}
function execute($method, $target, $post_body = "")
{
if (is_array($post_body)) {
$this->post_body = $this->arrayToXml($post_body);
} else {
$this->post_body = $post_body;
}
$this->method = strtoupper($method);
$this->path = "https://api.xero.com/api.xro/2.0/$target";
$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_USERAGENT, "Test APP");
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/xml';
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 safe_encode_xml_entity($data)
{
return str_ireplace(
array("<", ">", "'", "\"", "&"),
array("<", ">", "'", """, "&"),
$data
);
}
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 $k => $v) {
if ($k == 'xml') {
if ($filter == "true")
continue;
}
if (preg_match('/\w+_secret/', $k))
continue;
if (is_array($v)) {
sort($v);
foreach ($v as $element)
array_push($elements, $this->escape($k) . '=' . $this->escape($element));
continue;
}
array_push($elements, $this->escape($k) . '=' . $this->escape($v));
}
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 arrayToXml($data, $tab = 0)
{
$xml = "\r\n";
foreach ($data as $k => $v)
{
$sp = "";
for ($i = 0; $i < $tab; $i++)
{
$sp .= "\t";
}
if (strpos($k, " ") !== false) {
$k = substr($k, 0, strpos($k, " "));
}
if (is_array($v)) {
$tab2 = $tab + 1;
$v = $this->arrayToXml($v, $tab2);
$xml .= "$sp<$k>$v". "$sp</$k>\r\n";
} else {
$v = $this->safe_encode_xml_entity($v);
$xml .= "$sp<$k>$v</$k>\r\n";
}
}
return $xml;
}
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(20);
$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)
{
$result = '';
$nonce_length = strlen($this->nonce_chars);
for ($i = 0; $i < $length; $i++) {
$index = rand(0, $nonce_length);
$result .= substr($this->nonce_chars, $index, 1);
}
return $result;
}
public static function prettyPrint($o)
{
echo "<pre>";
print_r($o);
echo "</pre>";
}
}
Below is a screen-shot of my Xero portal:
Output will be as follows:
Array
(
[code] => 200
[body] => stdClass Object
(
[Id] => e614f8ea-07b1-4b69-88b0-c174ffb062d5
[Status] => OK
[ProviderName] => Trial #2
[DateTimeUTC] => /Date(1494045918570)/
[Contacts] => Array
(
[0] => stdClass Object
(
[ContactID] => 7de72cb7-7d6f-13f8-9e76-ea191269553a
[ContactStatus] => ACTIVE
[Name] => Xero Contact 1
[EmailAddress] =>
[BankAccountDetails] =>
[Addresses] => Array
(
[0] => stdClass Object
(
[AddressType] => STREET
[City] =>
[Region] =>
[PostalCode] =>
[Country] =>
)
[1] => stdClass Object
(
[AddressType] => POBOX
[City] =>
[Region] =>
[PostalCode] =>
[Country] =>
)
)
[Phones] => Array
(
[0] => stdClass Object
(
[PhoneType] => DEFAULT
[PhoneNumber] =>
[PhoneAreaCode] =>
[PhoneCountryCode] =>
)
[1] => stdClass Object
(
[PhoneType] => DDI
[PhoneNumber] =>
[PhoneAreaCode] =>
[PhoneCountryCode] =>
)
[2] => stdClass Object
(
[PhoneType] => FAX
[PhoneNumber] =>
[PhoneAreaCode] =>
[PhoneCountryCode] =>
)
[3] => stdClass Object
(
[PhoneType] => MOBILE
[PhoneNumber] =>
[PhoneAreaCode] =>
[PhoneCountryCode] =>
)
)
[UpdatedDateUTC] => /Date(1494044711587+0000)/
[ContactGroups] => Array
(
)
[IsSupplier] =>
[IsCustomer] =>
[SalesTrackingCategories] => Array
(
)
[PurchasesTrackingCategories] => Array
(
)
[ContactPersons] => Array
(
)
[HasValidationErrors] =>
)
[1] => stdClass Object
(
[ContactID] => 8eb00757-74f3-4302-99a8-3453dd4d456c
[ContactStatus] => ACTIVE
[Name] => Xero Contact 2
[EmailAddress] =>
[BankAccountDetails] =>
[Addresses] => Array
(
[0] => stdClass Object
(
[AddressType] => STREET
[City] =>
[Region] =>
[PostalCode] =>
[Country] =>
)
[1] => stdClass Object
(
[AddressType] => POBOX
[City] =>
[Region] =>
[PostalCode] =>
[Country] =>
)
)
[Phones] => Array
(
[0] => stdClass Object
(
[PhoneType] => DEFAULT
[PhoneNumber] =>
[PhoneAreaCode] =>
[PhoneCountryCode] =>
)
[1] => stdClass Object
(
[PhoneType] => DDI
[PhoneNumber] =>
[PhoneAreaCode] =>
[PhoneCountryCode] =>
)
[2] => stdClass Object
(
[PhoneType] => FAX
[PhoneNumber] =>
[PhoneAreaCode] =>
[PhoneCountryCode] =>
)
[3] => stdClass Object
(
[PhoneType] => MOBILE
[PhoneNumber] =>
[PhoneAreaCode] =>
[PhoneCountryCode] =>
)
)
[UpdatedDateUTC] => /Date(1494044711620+0000)/
[ContactGroups] => Array
(
)
[IsSupplier] =>
[IsCustomer] =>
[SalesTrackingCategories] => Array
(
)
[PurchasesTrackingCategories] => Array
(
)
[ContactPersons] => Array
(
)
[HasValidationErrors] =>
)
)
)
)
Awesome! This is worked for me.
ReplyDelete