vgrem/php-spo
REST/OData client library for Microsoft 365 in PHP. Access SharePoint Online/On-Prem (2013-2019), OneDrive for Business, Teams, and Outlook APIs with supported auth flows (client credentials, certificates, etc.). Install via Composer.
Installation:
composer require vgrem/php-spo
Ensure vendor/autoload.php is included in your Laravel app (handled automatically by Laravel’s autoloader).
Authentication: Register an app in Azure AD and obtain:
.env:SPO_CLIENT_ID=your_client_id
SPO_CLIENT_SECRET=your_client_secret
SPO_TENANT_ID=your_tenant_id
First Use Case: Fetch a SharePoint site’s lists:
use Vgrem\PhpSpo\Client;
use Vgrem\PhpSpo\Authentication\ClientCredential;
$auth = new ClientCredential(
env('SPO_CLIENT_ID'),
env('SPO_CLIENT_SECRET'),
env('SPO_TENANT_ID')
);
$client = new Client($auth);
$site = $client->getSite('https://yourdomain.sharepoint.com/sites/yoursite');
$lists = $site->getLists();
ClientCredential, OAuth2, and Certificate flows.Site, List, Drive, User, etc., for granular operations.Fetch a List:
$list = $site->getList('Documents');
$items = $list->getItems(['$select' => 'Title,Id']);
Create/Update/Delete Items:
$item = $list->createItem(['Title' => 'New File', 'FileLeafRef' => 'file.txt']);
$list->updateItem($item->getId(), ['Title' => 'Updated File']);
$list->deleteItem($item->getId());
File Operations:
$file = $list->getFile('file.txt');
$content = $file->getContent(); // Download
$file->updateContent(file_get_contents('local-path.txt')); // Upload
$teams = $client->getTeams();
foreach ($teams as $team) {
$channels = $team->getChannels();
}
$channel = $team->getChannel('general');
$channel->sendMessage('Hello from PHP!');
$emails = $client->getOutlook()->getMessages();
foreach ($emails as $email) {
$email->getBody();
}
$email = $client->getOutlook()->createMessage();
$email->setSubject('Test')
->setBody('Hello!')
->setTo(['user@example.com'])
->send();
$drive = $client->getOneDrive();
$file = $drive->uploadFile('local-file.txt', 'remote-file.txt');
$content = $drive->downloadFile('remote-file.txt');
Service Providers:
Bind the client to Laravel’s container in AppServiceProvider:
public function register()
{
$this->app->singleton(Client::class, function ($app) {
$auth = new ClientCredential(
env('SPO_CLIENT_ID'),
env('SPO_CLIENT_SECRET'),
env('SPO_TENANT_ID')
);
return new Client($auth);
});
}
Facade (Optional): Create a facade for cleaner syntax:
// app/Facades/SPO.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class SPO extends Facade { protected static function getFacadeAccessor() { return 'spo.client'; } }
Update config/app.php to bind the facade.
Jobs/Queues: Offload long-running operations (e.g., bulk file uploads) to queues:
use Vgrem\PhpSpo\Client;
class UploadFilesJob implements ShouldQueue
{
protected $client;
public function __construct(Client $client) { $this->client = $client; }
public function handle() {
$this->client->getSite('...')->uploadFiles(...);
}
}
Events/Listeners:
Trigger events for SharePoint/Teams actions (e.g., FileUploaded, TeamMessageSent):
event(new FileUploaded($file));
Authentication Timeouts:
ClientCredential tokens expire after 1 hour. Subsequent requests fail with 401 Unauthorized.OAuth2 with longer-lived tokens.
if ($auth->isTokenExpired()) {
$auth->refreshToken();
}
Throttling:
sleep(1); // Simple delay
// OR
$client->setRateLimit(10); // Hypothetical method (check docs)
OData Query Complexity:
$expand or $filter queries may fail silently.Permissions:
Files.ReadWrite) cause 403 Forbidden.https://graph.microsoft.com/.default (for delegated)
api://<client-id>/Files.ReadWrite (for app-only)
Large File Handling:
$file->uploadContent($chunkedContent, ['chunkSize' => 1024 * 1024]); // 1MB chunks
Enable Logging:
$client->setLogger(new \Monolog\Logger('spo', [new \Monolog\Handler\StreamHandler(storage_path('logs/spo.log'))]));
HTTP Debugging:
Guzzle middleware to inspect requests:
$client->getHttpClient()->getEmitter()->attach(
new \GuzzleHttp\Middleware::tap(function ($request) {
\Log::debug('SPO Request:', ['url' => (string) $request->getUri()]);
})
);
Common Errors:
InvalidAuthenticationToken: Check Client ID/Secret/Tenant ID.ResourceNotFound: Verify SharePoint site URL format (https://domain.sharepoint.com/sites/site).InvalidQuery: Validate OData syntax (use OData Validator).Custom Resources: Extend the library for unsupported endpoints:
class CustomResource extends \Vgrem\PhpSpo\Resource
{
protected $endpoint = 'https://graph.microsoft.com/v1.0/sites/{site-id}/custom';
public function getItems() { return $this->get('/items'); }
}
Middleware: Add request/response middleware:
$client->getHttpClient()->getEmitter()->attach(
new \GuzzleHttp\Middleware::mapRequest(function ($request) {
$request->getHeaders()->add('X-Custom-Header', 'value');
return $request;
})
);
Caching: Cache responses (e.g., lists, users) to reduce API calls:
$lists = Cache::remember('spo.lists', 300, function () use ($site) {
return $site->getLists();
});
Testing: Use mocks for unit tests:
$mockClient = Mockery::mock(Client::class);
$mockClient->shouldReceive('getSite')->andReturn($mockSite);
https://graph.microsoft.com.How can I help you explore Laravel packages today?