Integrating Alibaba Cloud Drive API with PHP: Complete Guide and Code Samples
This article explains how to integrate Alibaba Cloud Drive's personal cloud storage capabilities into PHP applications, covering platform overview, OAuth2 authorization flow, essential API endpoints, detailed PHP class implementations, and practical examples for uploading files, managing folders, and retrieving download links.
Alibaba Cloud Drive Overview
Alibaba Cloud Drive is a personal cloud storage service offered by Alibaba Group, providing secure, stable, and efficient cloud space for storing, managing, and syncing various files and data across multiple devices.
Open Platform
The platform exposes personal cloud storage capabilities via APIs, allowing developers to integrate features such as basic file management (upload/download), media transcoding and playback, and user authorization and information queries.
Documentation URL:
https://www.yuque.com/aliyundrive/zpfszxIntegration Process
Server-side API call flow is illustrated in the diagram below.
Creating an Application
Register an application to obtain appid and secret credentials.
Creating the app yields the following credentials: appid and secret
Writing the Application
The core PHP class ADrive encapsulates all API interactions.
<?php
/**
* @desc ADrive https://www.yuque.com/aliyundrive/zpfszx
* @author Tinywan (ShaoBo Wan)
* @date 2024/8/7 22:57
*/
declare(strict_types=1);
namespace app\common\service;
use Psr\SimpleCache\InvalidArgumentException;
use support\exception\BusinessException;
use support\Log;
use think\facade\Cache;
class ADrive {
const ACCESS_TOKEN = 'ADRIVE_ACCESS_TOKEN:';
private array $config = [];
private string $http = 'https://openapi.aliyundrive.com/';
private string $redirect_uri = 'http://webman2024.tinywan.com:8484/test/adrive-callback';
private array $url = [
'access_token' => 'oauth/access_token',
'authorize' => 'oauth/authorize',
'drive' => 'adrive/v1.0/user/getDriveInfo',
'create' => 'adrive/v1.0/openFile/create',
'complete' => 'adrive/v1.0/openFile/complete',
'fileList' => 'adrive/v1.0/openFile/list',
'deleteFile' => 'adrive/v1.0/openFile/recyclebin/trash',
'searchList' => 'adrive/v1.0/openFile/search',
'updateFile' => 'adrive/v1.0/openFile/update',
'starredList' => 'adrive/v1.0/openFile/starredList',
'getDownloadUrl' => 'adrive/v1.0/openFile/getDownloadUrl'
];
private ?PublicHttp $publicHttp = null;
public function __construct(int $agencyId = 0) {
$agencyInfo['id'] = 2024;
$agencyInfo['aly_appid'] = '282392bf68014e13b5db2a2b35d9b3ce';
$agencyInfo['aly_secret'] = 'a524d58d17a44c1faaa914db460be16a';
if ($this->publicHttp === null) {
$this->publicHttp = new PublicHttp();
}
$this->config = $agencyInfo;
}
public function authorize(): string {
return $this->http . $this->url['authorize'] . '?client_id=' . $this->config['aly_appid'] .
'&redirect_uri=' . $this->redirect_uri .
'&scope=user:base,file:all:read,file:all:write&response_type=code&state=' . $this->config['id'];
}
public function getToken(string $code, int $type = 1) {
$info = [
'client_id' => $this->config['aly_appid'],
'client_secret' => $this->config['aly_secret'],
'grant_type' => $type == 1 ? 'authorization_code' : 'refresh_token'
];
if ($type == 1) {
$info['code'] = $code;
} else {
if (empty($this->config['id'])) {
throw new \Exception('未传入旅行社标识');
}
$token = Cache::get(self::ACCESS_TOKEN . $this->config['id']);
if (empty($token)) {
throw new \Exception('未有阿里云盘缓存');
}
$info['refresh_token'] = $token['refresh_token'];
}
$result = $this->publicHttp->postAlyFile($this->http . $this->url['access_token'], $info);
Log::info('[阿里云云盘获取令牌]' . json_encode($result, JSON_UNESCAPED_UNICODE));
if (!is_array($result)) {
$result = json_decode($result, true);
}
Cache::set(self::ACCESS_TOKEN . $this->config['id'], $result, 7200);
return $result;
}
public function getUserDrive(): array {
$userToken = Cache::get(self::ACCESS_TOKEN . $this->config['id']);
if (empty($userToken)) {
throw new \Exception('登录失效,请重新授权阿里网盘');
}
$result = $this->publicHttp->postAlyFile(
$this->http . $this->url['drive'],
[],
['Authorization:' . $userToken['token_type'] . ' ' . $userToken['access_token']]
);
if (!is_array($result)) {
$result = json_decode($result, true);
}
if (empty($result['default_drive_id'])) {
throw new \Exception('获取阿里云盘drive_id失败');
}
Cache::set('aly_drive_' . $this->config['id'], $result['default_drive_id']);
Cache::set('aly_userInfo_' . $this->config['id'], $result);
return ['status' => 0, 'msg' => '获取用户drive成功', 'data' => $result['default_drive_id']];
}
public function updateFile(array $input): array {
$userToken = Cache::get(self::ACCESS_TOKEN . $this->config['id']);
if (empty($userToken)) {
throw new \Exception('登录失效,请重新授权阿里网盘');
}
$drive = Cache::get('aly_drive_' . $this->config['id']);
if (empty($drive)) {
$driveInfo = $this->getUserDrive();
$drive = $driveInfo['data'];
}
$fileName = $input['file_name'] . date('Y-m-d-H:i:s');
$result = $this->publicHttp->postAlyFile(
$this->http . $this->url['create'],
[
'drive_id' => $drive,
'parent_file_id' => empty($input['file_id']) ? 'root' : $input['file_id'],
'type' => 'file',
'check_name_mode' => 'ignore',
'name' => $fileName,
],
['Authorization:' . $userToken['token_type'] . ' ' . $userToken['access_token']]
);
if (!is_array($result)) {
$result = json_decode($result, true);
}
if (empty($result['part_info_list'][0]['upload_url'])) {
throw new \Exception('获取上传路径失败');
}
$sourceFile = fopen($input['file_path'], "rb");
$res = $this->publicHttp->putAlyFile($result['part_info_list'][0]['upload_url'], $sourceFile, ['Authorization:' . $userToken['token_type'] . ' ' . $userToken['access_token']]);
if ($res['code'] != 1) {
throw new \Exception('上传文件失败');
}
$onMsg = $this->publicHttp->postAlyFile(
$this->http . $this->url['complete'],
[
'drive_id' => $drive,
'file_id' => $result['file_id'],
'upload_id' => $result['upload_id']
],
['Authorization:' . $userToken['token_type'] . ' ' . $userToken['access_token']]
);
if (!is_array($onMsg)) {
$onMsg = json_decode($onMsg, true);
}
if (empty($onMsg['name'])) {
throw new \Exception('同步阿里云网盘失败');
}
return ['status' => 0, 'msg' => '上传文件成功', 'file_id' => $result['file_id']];
}
// Additional methods: addFile, fileList, searchList, starredList, fileRename, deleteFile, getDownloadUrl
// (omitted for brevity but follow the same pattern of token retrieval, API call, error handling)
}Simple Request Class
The PublicHttp class provides generic POST and PUT wrappers for the Aliyun Drive API.
<?php
/**
* @desc PublicHttp.php description
* @author Tinywan (ShaoBo Wan)
* @date 2024/8/7 23:05
*/
declare(strict_types=1);
namespace app\common\service;
class PublicHttp {
public function postAlyFile(string $_url, array $params, array $header = []): string {
$headerArray = ["Content-Type:application/json;charset=utf-8", "Accept:application/json"];
if (!empty($header)) {
$headerArray = array_merge($headerArray, $header);
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_URL, $_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headerArray);
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
public function putAlyFile(string $url, $sourceFile, array $headerArr = [], int $timeout = 30): array {
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headerArr);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_INFILE, $sourceFile);
$response = curl_exec($ch);
if ($error = curl_error($ch)) {
$bkArr = ['code' => 0, 'msg' => $error];
} else {
$bkArr = ['code' => 1, 'msg' => 'ok', 'data' => $response];
}
curl_close($ch);
return $bkArr;
}
}Authorization Flow
To obtain an authorization code, redirect the user to the URL generated by $aDriver->authorize(). After the user scans the QR code and approves, Aliyun Drive redirects to the configured callback URL.
/**
* @desc Get authorization code
*/
public function authorize(Request $request): Response {
$aDriver = new ADrive();
return redirect($aDriver->authorize());
}Callback Handling
The callback receives the code parameter, exchanges it for an access token, and returns the token JSON.
/**
* @param Request $request
* @return Response
*/
public function aDriveCallback(Request $request): Response {
Log::info('[Callback params]:' . json_encode($request->get()));
$code = $request->get()['code'];
$aDriver = new ADrive();
$token = $aDriver->getToken($code);
Log::info('[Access token]:' . json_encode($token));
return response_json(200, '请求成功', ['token' => $token]);
}File Upload Example
The following controller method uploads a local file to the user's Aliyun Drive.
/**
* @desc File upload
*/
public function uploadFile(Request $request): Response {
$aDriver = new ADrive();
$param = [
'file_name' => '开源技术小栈-文件上传测试',
'file_path' => runtime_path() . DIRECTORY_SEPARATOR . 'swoole.jpg',
];
$res = $aDriver->updateFile($param);
Log::info('[Upload response]:' . json_encode($res));
return response_json(200, '请求成功', $res);
}The API returns a JSON object containing status, msg, and the newly created file_id.
{
"code": 200,
"msg": "请求成功",
"data": {
"status": 0,
"msg": "上传文件成功",
"file_id": "66b5b06c8e278ff7d300479fac0fb623fdfe299a"
}
}After a successful upload, the file appears in the user's cloud drive as shown in the screenshot above.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Tech Hub
Sharing cutting-edge internet technologies and practical AI resources.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
