Consuming SharePoint Online Data with PHP and Microsoft Graph

PHP can talk to Microsoft 365 just fine. The annoying part is that a quick proof of concept often mixes authentication, Graph URLs, SharePoint internal field names, and presentation code in one file. It works—until a token expires or one column changes.

The problem: the page knows everything

$url = 'https://graph.microsoft.com/v1.0/sites/'
    . $siteId . '/lists/' . $listId
    . '/items?expand=fields';

That URL returns list items, but Graph list data lives inside fields. URL columns, people fields, and missing properties can arrive in shapes that differ from SharePoint REST.

The quirk: successful authentication does not mean the app can read the list

The token may be valid while the application lacks permission to the site. I log the HTTP status and a request correlation ID, but never the access token.

$headers = [
    'Authorization: Bearer ' . $token,
    'Accept: application/json'
];

[$status, $body] = graphGet($url, $headers);

if ($status !== 200) {
    error_log("Graph failed with HTTP {$status}");
    http_response_code(502);
    exit('Microsoft 365 data is temporarily unavailable');
}

The workaround: return a smaller contract

$output = array_map(function ($row) {
    $f = $row['fields'] ?? [];

    return [
        'bannerId' => trim($f['BannerID'] ?? ''),
        'name'     => trim($f['Title'] ?? ''),
        'email'    => strtolower(trim($f['EmployeeEmail'] ?? '')),
        'url'      => trim($f['ProfileUrl'] ?? '')
    ];
}, $data['value'] ?? []);

The consuming page never sees the token, tenant ID, site ID, list ID, or internal field names. PHP owns those details and returns predictable JSON. That makes the front end simpler and lets me change the Microsoft 365 implementation without rebuilding the page.

Leave a Comment

Your email address will not be published. Required fields are marked *