Cloud Computing 18 min read

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.

Open Source Tech Hub
Open Source Tech Hub
Open Source Tech Hub
Integrating Alibaba Cloud Drive API with PHP: Complete Guide and Code Samples

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/zpfszx

Integration 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

file uploadPHPOAuth2api-integrationAlibaba Cloud Drive
Open Source Tech Hub
Written by

Open Source Tech Hub

Sharing cutting-edge internet technologies and practical AI resources.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.