Laravel/核心PHP实现登录用户传文件至管理员OneDrive方案咨询
实现客户端用户上传文件至管理员OneDrive(Laravel/核心PHP方案)
先解决你之前Microsoft Graph API失败的常见坑
- 必须注册机密客户端应用,并申请应用权限(而非委派权限),比如
Files.ReadWrite.All,且需要管理员同意该权限 - 确保使用**客户端凭证流(Client Credentials Flow)**获取token,而非用户授权流
- 访问管理员OneDrive必须使用
/users/{admin-id}/drive端点,而非/me/drive或/drives/root(后者针对应用自身存储) - 提前通过Graph Explorer获取管理员的用户ID/主体名,以及目标文件夹的路径(或ID)
Laravel 实现步骤
1. 安装依赖
composer require microsoftgraph/msgraph-sdk-php
2. 配置环境变量(.env)
MS_GRAPH_TENANT_ID=你的Azure租户ID MS_GRAPH_CLIENT_ID=你的客户端ID MS_GRAPH_CLIENT_SECRET=你的客户端密钥 ADMIN_USER_ID=管理员的用户ID或邮箱(如admin@yourdomain.com) ADMIN_UPLOAD_FOLDER=管理员OneDrive内的目标文件夹名(如"用户上传文件")
3. 编写上传逻辑(控制器示例)
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Microsoft\Graph\Graph; class OneDriveUploadController extends Controller { // 已登录用户上传文件至管理员OneDrive public function upload(Request $request) { // 验证上传文件 $request->validate([ 'file' => 'required|file|max:51200', // 限制50M以内 ]); $uploadedFile = $request->file('file'); $fileName = $uploadedFile->getClientOriginalName(); $fileContent = fopen($uploadedFile->getRealPath(), 'r'); $fileSize = $uploadedFile->getSize(); // 获取Graph API访问token $token = $this->getAccessToken(); if (!$token) { return response()->json(['error' => '获取API授权失败'], 500); } $graph = new Graph(); $graph->setAccessToken($token); try { // 创建文件上传会话 $uploadSessionUrl = "/users/" . env('ADMIN_USER_ID') . "/drive/root:/".env('ADMIN_UPLOAD_FOLDER')."/$fileName:/createUploadSession"; $sessionResponse = $graph->createRequest("POST", $uploadSessionUrl) ->addHeaders(['Content-Type' => 'application/json']) ->attachBody([ 'item' => [ '@microsoft.graph.conflictBehavior' => 'rename' // 重复文件自动重命名 ] ]) ->execute(); $uploadUrl = $sessionResponse->getUploadUrl(); // 上传文件内容 $uploadResponse = $graph->createRequest("PUT", $uploadUrl) ->addHeaders([ 'Content-Length' => $fileSize, 'Content-Range' => "bytes 0-".($fileSize-1)."/".$fileSize ]) ->attachBody($fileContent) ->execute(); fclose($fileContent); return response()->json([ 'message' => '文件上传成功', 'file_id' => $uploadResponse->getId(), 'file_name' => $uploadResponse->getName() ]); } catch (\Exception $e) { return response()->json(['error' => $e->getMessage()], 500); } } // 获取客户端凭证模式的access token private function getAccessToken() { $tokenEndpoint = "https://login.microsoftonline.com/" . env('MS_GRAPH_TENANT_ID') . "/oauth2/v2.0/token"; $postData = http_build_query([ 'grant_type' => 'client_credentials', 'client_id' => env('MS_GRAPH_CLIENT_ID'), 'client_secret' => env('MS_GRAPH_CLIENT_SECRET'), 'scope' => 'https://graph.microsoft.com/.default' ]); $ch = curl_init($tokenEndpoint); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $response = curl_exec($ch); curl_close($ch); $tokenData = json_decode($response, true); return $tokenData['access_token'] ?? null; } // 示例:获取管理员上传文件夹内的文件列表 public function listFiles() { $token = $this->getAccessToken(); if (!$token) { return response()->json(['error' => '获取API授权失败'], 500); } $graph = new Graph(); $graph->setAccessToken($token); $files = $graph->createRequest("GET", "/users/" . env('ADMIN_USER_ID') . "/drive/root:/".env('ADMIN_UPLOAD_FOLDER').":/children") ->execute(); return response()->json($files->getArray()); } }
4. 路由配置(routes/api.php)
// 仅允许已登录用户访问 Route::post('/upload-to-admin-onedrive', [OneDriveUploadController::class, 'upload'])->middleware('auth:sanctum'); Route::get('/admin-onedrive-files', [OneDriveUploadController::class, 'listFiles'])->middleware('auth:sanctum');
核心PHP 实现步骤
1. 封装Token获取函数
<?php function getGraphAccessToken($tenantId, $clientId, $clientSecret) { $tokenUrl = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"; $postFields = http_build_query([ 'grant_type' => 'client_credentials', 'client_id' => $clientId, 'client_secret' => $clientSecret, 'scope' => 'https://graph.microsoft.com/.default' ]); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $tokenUrl); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $response = curl_exec($ch); curl_close($ch); $tokenData = json_decode($response, true); return $tokenData['access_token'] ?? null; }
2. 处理用户上传并同步至管理员OneDrive
<?php // 确保用户已登录(此处需自行实现登录校验逻辑) session_start(); if (!isset($_SESSION['user_id'])) { die("请先登录"); } // 处理文件上传 if ($_FILES['file']['error'] === UPLOAD_ERR_OK) { // 配置参数 $tenantId = "你的Azure租户ID"; $clientId = "你的客户端ID"; $clientSecret = "你的客户端密钥"; $adminUserId = "管理员邮箱或用户ID"; $targetFolder = "用户上传文件"; // 获取Token $token = getGraphAccessToken($tenantId, $clientId, $clientSecret); if (!$token) { die("获取API授权失败"); } $fileName = $_FILES['file']['name']; $filePath = $_FILES['file']['tmp_name']; $fileSize = $_FILES['file']['size']; // 创建上传会话 $sessionUrl = "https://graph.microsoft.com/v1.0/users/$adminUserId/drive/root:/$targetFolder/$fileName:/createUploadSession"; $sessionHeaders = [ "Authorization: Bearer $token", "Content-Type: application/json" ]; $sessionBody = json_encode([ 'item' => ['@microsoft.graph.conflictBehavior' => 'rename'] ]); $ch = curl_init($sessionUrl); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $sessionHeaders); curl_setopt($ch, CURLOPT_POSTFIELDS, $sessionBody); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $sessionResponse = curl_exec($ch); curl_close($ch); $sessionData = json_decode($sessionResponse, true); $uploadUrl = $sessionData['uploadUrl'] ?? null; if (!$uploadUrl) { die("创建上传会话失败:" . json_encode($sessionData)); } // 上传文件内容 $fileContent = fopen($filePath, 'r'); $uploadHeaders = [ "Content-Length: $fileSize", "Content-Range: bytes 0-".($fileSize-1)."/$fileSize" ]; $ch = curl_init($uploadUrl); curl_setopt($ch, CURLOPT_PUT, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $uploadHeaders); curl_setopt($ch, CURLOPT_INFILE, $fileContent); curl_setopt($ch, CURLOPT_INFILESIZE, $fileSize); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $uploadResponse = curl_exec($ch); curl_close($ch); fclose($fileContent); $uploadResult = json_decode($uploadResponse, true); if (isset($uploadResult['id'])) { echo "文件上传成功,文件ID:" . $uploadResult['id']; } else { echo "上传失败:" . json_encode($uploadResult); } } else { echo "文件上传出错,错误码:" . $_FILES['file']['error']; }
3. 示例:获取管理员OneDrive目标文件夹的文件列表
<?php function listAdminOneDriveFiles($token, $adminUserId, $targetFolder) { $listUrl = "https://graph.microsoft.com/v1.0/users/$adminUserId/drive/root:/$targetFolder:/children"; $headers = ["Authorization: Bearer $token"]; $ch = curl_init($listUrl); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); return json_decode($response, true); } // 使用示例 $token = getGraphAccessToken("你的租户ID", "你的客户端ID", "你的客户端密钥"); $files = listAdminOneDriveFiles($token, "管理员邮箱", "用户上传文件"); print_r($files);
内容的提问来源于stack exchange,提问作者Avinash Kumar
相关产品推荐
相关产品推荐

