Symfony 5.4大文件(最大5GB)自动上传至OneDrive实现方案咨询
Symfony 5.4 自动上传大文件到OneDrive实现指南
一、OneDrive API授权配置
- 登录Azure门户,注册新应用程序(账号类型选「任何组织目录中的账户和个人Microsoft账户」)
- 在应用「API权限」中添加
Files.ReadWrite.All(应用权限)和offline_access,完成管理员同意 - 生成客户端密码(Client Secret),记录好Client ID、Client Secret
- 获取Refresh Token:执行以下curl命令替换占位符获取长期有效token
从返回结果中提取curl -X POST https://login.microsoftonline.com/common/oauth2/v2.0/token \ -d "client_id=YOUR_CLIENT_ID" \ -d "scope=https://graph.microsoft.com/.default offline_access" \ -d "client_secret=YOUR_CLIENT_SECRET" \ -d "grant_type=client_credentials"refresh_token
二、安装依赖
在Symfony项目中安装Microsoft Graph SDK简化API调用:
composer require microsoft/microsoft-graph
也可直接使用Symfony自带的HttpClient组件,无需额外SDK。
三、大文件分片上传逻辑
5GB文件需用分片上传会话实现,步骤如下:
- 创建上传会话:向OneDrive API请求生成会话URL
- 分片上传:将本地文件分割为5MB-10MB的块,逐个上传到会话URL
- 完成上传:所有块上传后发送合并请求,生成完整文件
四、编写Symfony控制台命令
创建独立命令执行上传任务:
// src/Command/UploadBackupToOneDriveCommand.php namespace App\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Microsoft\Graph\Graph; class UploadBackupToOneDriveCommand extends Command { protected static $defaultName = 'app:upload-backup-to-onedrive'; private $clientId; private $clientSecret; private $refreshToken; public function __construct(string $clientId, string $clientSecret, string $refreshToken) { $this->clientId = $clientId; $this->clientSecret = $clientSecret; $this->refreshToken = $refreshToken; parent::__construct(); } protected function configure() { $this->addArgument('backup-file', InputArgument::REQUIRED, '备份zip文件路径'); $this->addArgument('onedrive-path', InputArgument::OPTIONAL, 'OneDrive目标路径', '/Backups/'); } protected function execute(InputInterface $input, OutputInterface $output): int { $backupFile = $input->getArgument('backup-file'); $onedrivePath = $input->getArgument('onedrive-path'); $fileName = basename($backupFile); $fileSize = filesize($backupFile); // 初始化Graph客户端 $graph = new Graph(); $graph->setAccessToken($this->getAccessToken()); // 1. 创建上传会话 $uploadSession = $graph->createRequest("POST", "/me/drive/root:{$onedrivePath}{$fileName}:/createUploadSession") ->attachBody(['item' => ['@microsoft.graph.conflictBehavior' => 'replace']]) ->execute()->getBody(); $uploadUrl = $uploadSession['uploadUrl']; // 2. 分片上传 $chunkSize = 5 * 1024 * 1024; // 5MB分片 $handle = fopen($backupFile, 'rb'); $offset = 0; while ($offset < $fileSize) { $end = min($offset + $chunkSize - 1, $fileSize - 1); $content = fread($handle, $chunkSize); $graph->createRequest("PUT", $uploadUrl) ->addHeaders([ 'Content-Length' => (string)($end - $offset + 1), 'Content-Range' => "bytes {$offset}-{$end}/{$fileSize}" ]) ->attachBody($content) ->execute(); $offset = $end + 1; $output->writeln("已上传 {$offset}/{$fileSize} 字节"); } fclose($handle); $output->writeln("备份文件 {$fileName} 成功上传至OneDrive"); return Command::SUCCESS; } private function getAccessToken(): string { $tokenEndpoint = 'https://login.microsoftonline.com/common/oauth2/v2.0/token'; $data = [ 'client_id' => $this->clientId, 'client_secret' => $this->clientSecret, 'refresh_token' => $this->refreshToken, 'grant_type' => 'refresh_token', 'scope' => 'https://graph.microsoft.com/.default' ]; $ch = curl_init($tokenEndpoint); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); $tokenData = json_decode($response, true); return $tokenData['access_token']; } }
在services.yaml中配置命令参数:
services: App\Command\UploadBackupToOneDriveCommand: arguments: $clientId: '%env(ONEDRIVE_CLIENT_ID)%' $clientSecret: '%env(ONEDRIVE_CLIENT_SECRET)%' $refreshToken: '%env(ONEDRIVE_REFRESH_TOKEN)%'
在.env中添加环境变量:
ONEDRIVE_CLIENT_ID=你的客户端ID ONEDRIVE_CLIENT_SECRET=你的客户端密钥 ONEDRIVE_REFRESH_TOKEN=你的刷新令牌
五、自动执行脚本
通过crontab设置定时任务,示例为每天凌晨2点执行:
0 2 * * * cd /你的Symfony项目路径 && php bin/console app:upload-backup-to-onedrive /备份文件路径/backup.zip
注意事项
- 分片大小需≥5MB(最后一块除外),避免请求过多
- 添加重试逻辑处理网络波动,可使用Symfony的RetryHttpClient
- 集成Monolog记录上传日志,便于排查问题
- 配置
@microsoft.graph.conflictBehavior处理文件冲突(如replace覆盖或rename重命名)
内容的提问来源于stack exchange,提问作者Maksim
相关产品推荐
相关产品推荐

