te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>php - use access token for life time in xero - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

php - use access token for life time in xero - Stack Overflow

programmeradmin4浏览0评论

I am trying to implement xero account software in my php project. I have to create an invoice with an attachment. I am using xero api for this. Initial authentication is working well. Means if I authenticate first time then it generates all the tokens and those tokens are being saved into the table. Below is the code for authenticate: xero_callback.php is: This is working fine.

    <?php
session_start();
require 'db.php'; // Include database connection file

define('CLIENT_ID', 'xxxxx');
define('CLIENT_SECRET', 'xxxxx');
define('REDIRECT_URI', 'http://localhost/xero_testing/xero_callback.php');

if (!isset($_GET['code'])) {
    die("No authorization code received.");
}

$code = $_GET['code'];

$tokenUrl = ";;

$data = [
    "grant_type" => "authorization_code",
    "code" => $code,
    "redirect_uri" => REDIRECT_URI,
    "client_id" => CLIENT_ID,
    "client_secret" => CLIENT_SECRET
];

$ch = curl_init($tokenUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/x-www-form-urlencoded"]);

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

$result = json_decode($response, true);

if (!isset($result["access_token"])) {
    die("Failed to get access token.");
}

$accessToken = $result["access_token"];
$refreshToken = $result["refresh_token"];
$expiresIn = $result["expires_in"];

// Get Tenant ID
$ch = curl_init(";);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer $accessToken",
    "Content-Type: application/json"
]);

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

$tenantData = json_decode($tenantResponse, true);
$tenantId = $tenantData[0]["tenantId"] ?? null;

if (!$tenantId) {
    die("Failed to retrieve Tenant ID.");
}

// Store in Database
$db->query("INSERT INTO xero_tokens (tenant_id, access_token, refresh_token, expires_in) 
            VALUES ('$tenantId', '$accessToken', '$refreshToken', '$expiresIn')");

echo "Successfully connected to Xero! Tenant ID: $tenantId";
?>

Now below is the code to create invoice and update access token when it expires. After authenticating first time everything is working. But when access token gets expired after 30 mins and then if I regenerate the access token using the refresh token then it gives error: below is the code for create invoice:

    <?php
require 'db.php';
$result = $db->query("SELECT * FROM xero_tokens ORDER BY created_at DESC LIMIT 1");
$xero = $result->fetch_assoc();
$accessToken = $xero['access_token'];
$tenantId = $xero['tenant_id'];
$refreshToken = $xero['refresh_token'];
$record_id = $xero['id'];
$contactID = getContactID('John Doe', $accessToken, $tenantId);

$invoiceData = [
    "Type" => "ACCREC",
    "Contact" => ["ContactID" => $contactID],
    "LineItems" => [[
        "Description" => "Consulting Service",
        "Quantity" => 1,
        "UnitAmount" => 200.00,
        "AccountCode" => "200"
    ]],
    "Date" => date("Y-m-d"),
    "DueDate" => date("Y-m-d", strtotime("+30 days")),
    "InvoiceNumber" => "INV-" . time()
];

$headers = [
    "Authorization: Bearer $accessToken",
    "Xero-tenant-id: $tenantId",
    "Content-Type: application/json",
    "Accept: application/json",
];

$ch = curl_init(".xro/2.0/Invoices");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($invoiceData));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

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

if ($httpCode == 401 || $httpCode == 403) {    
    refreshAccessToken($refreshToken, $record_id);

    // Fetch the latest access token from DB after refreshing
    $result = $db->query("SELECT * FROM xero_tokens ORDER BY created_at DESC LIMIT 1");
    $xero = $result->fetch_assoc();
    $accessToken = $xero['access_token'];
    $tenantId = $xero['tenant_id'];

    $headers = [
        "Authorization: Bearer $accessToken",
        "Xero-tenant-id: $tenantId",
        "Content-Type: application/json",
        "Accept: application/json",
    ];

    $ch = curl_init(".xro/2.0/Invoices");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($invoiceData));
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
}

curl_close($ch);
$responseData = json_decode($response, true);

$invoiceId = $responseData['Invoices'][0]['InvoiceID'] ?? null;

if (!$invoiceId) {
    die("Failed to create Invoice.");
}

echo "Invoice Created: ID = $invoiceId";

$path = 'ALK.pdf';
$filename = 'ALK.pdf';
if (file_exists($path)) {
    $fileHandle = fopen($path, 'r');
    $fileSize = filesize($path);

    $ch = curl_init(".xro/2.0/Invoices/$invoiceId/Attachments/$filename");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_UPLOAD, true);
    curl_setopt($ch, CURLOPT_INFILE, $fileHandle);
    curl_setopt($ch, CURLOPT_INFILESIZE, $fileSize);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "Authorization: Bearer $accessToken",
        "Xero-tenant-id: $tenantId",
        "Content-Type: application/octet-stream",
        "Content-Length: $fileSize"
    ]);

    $attachmentResponse = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    fclose($fileHandle);
    curl_close($ch);

    if ($httpCode == 200) {
        echo "Attachment Uploaded Successfully!";
    } else {
        echo "Error uploading attachment: ";
        print_r(json_decode($attachmentResponse, true));
    }
} else {
    echo "File does not exist at path: " . $path;
}


function getContactID($contactName, $accessToken, $tenantId) {

$headers = [
    "Authorization: Bearer $accessToken",
    "Accept: application/json"
];

$ch = curl_init(";);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode == 200) {
    echo "Access Token is valid.";
    print_r($response); 
} else {
    echo "Access Token is invalid or expired. HTTP Code: $httpCode";
}

//exit;
    
    $contactName = urlencode($contactName);
    $url = ".xro/2.0/Contacts?where=Name.Contains(\"$contactName\")";
    
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "Authorization: Bearer $accessToken",
        "Xero-tenant-id: $tenantId",
        "Content-Type: application/json",
        "Accept: application/json"
    ]);

    $response = curl_exec($ch);
    $data = json_decode($response, true);

    if (isset($data['Contacts'][0]['ContactID'])) {
        return $data['Contacts'][0]['ContactID']; // Return ContactID if found
    } else {
        return null; // Contact not found
    }
}

function refreshAccessToken($refreshToken, $record_id) {
    global $db; 

    $clientId = 'xxxx'; 
    $clientSecret = 'xxxxx'; 

    $curl = curl_init();
    curl_setopt_array($curl, array(
        CURLOPT_URL => '',
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => http_build_query([
            'grant_type' => 'refresh_token',
            'client_id' => $clientId,
            'client_secret' => $clientSecret,
            'refresh_token' => $refreshToken
        ]),
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/x-www-form-urlencoded'
        ],
    ));

    $response = curl_exec($curl);
    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    curl_close($curl);

    if ($httpCode == 200) {
        $tokenData = json_decode($response, true);
        if (isset($tokenData['access_token'], $tokenData['refresh_token'])) {
            // Update the database with the new tokens
            $newAccessToken = $tokenData['access_token'];
            $newRefreshToken = $tokenData['refresh_token'];

            $updateQuery = $db->prepare("UPDATE xero_tokens SET access_token = ?, refresh_token = ?, created_at = NOW() WHERE id = ?");
            $updateQuery->bind_param("ssi", $newAccessToken, $newRefreshToken, $record_id);
            $updateQuery->execute();

            if ($updateQuery->affected_rows > 0) {
                echo "Access token refreshed successfully!";
            } else {
                echo "Failed to update token in the database.";
            }
        } else {
            echo " Refresh token response missing expected fields.";
        }
    } else {
        echo "Failed to refresh access token. HTTP Code: $httpCode";
    }
}

function saveNewToken($accessToken, $refreshToken, $record_id)
{
    global $db;
    $stmt = $db->prepare("UPDATE xero_tokens SET access_token = ?, refresh_token = ?, created_at = NOW() WHERE id = ?");
    $stmt->bind_param("ssi", $accessToken, $refreshToken, $record_id);
    $stmt->execute();
}



?>

Error is:

    Access Token is valid.[]403
{"Type":null,"Title":"Forbidden","Status":403,"Detail":"AuthenticationUnsuccessful","Instance":"1111eace-cfc0-413b-8111-5c53832769b7","Extensions":{}}
发布评论

评论列表(0)

  1. 暂无评论