如何在Laravel应用中通过YouTube API v3上传视频并保存URL到数据库
实现Laravel应用上传视频到YouTube并保存URL到数据库
1. 安装Google API客户端依赖
确保Laravel项目安装Google官方API客户端包,执行命令:
composer require google/apiclient:^2.0
2. 配置Google客户端与YouTube服务
在config/services.php中添加YouTube凭证配置:
return [ // 其他服务配置... 'youtube' => [ 'client_id' => env('YOUTUBE_CLIENT_ID'), 'client_secret' => env('YOUTUBE_CLIENT_SECRET'), 'redirect_uri' => env('YOUTUBE_REDIRECT_URI'), 'access_token' => env('YOUTUBE_ACCESS_TOKEN'), 'refresh_token' => env('YOUTUBE_REFRESH_TOKEN'), 'scopes' => ['https://www.googleapis.com/auth/youtube.upload'], ], ];
在.env文件中填充对应凭证值(需确保OAuth 2.0凭证已申请youtube.upload权限)。
创建YouTube服务类封装上传逻辑:
// app/Services/YouTubeService.php namespace App\Services; use Google\Client; use Google\Service\YouTube; use Google\Http\MediaFileUpload; class YouTubeService { protected $youtube; public function __construct() { $client = new Client(); $client->setClientId(config('services.youtube.client_id')); $client->setClientSecret(config('services.youtube.client_secret')); $client->setRedirectUri(config('services.youtube.redirect_uri')); $client->setScopes(config('services.youtube.scopes')); $client->setAccessType('offline'); // 加载并刷新过期令牌 $client->setAccessToken(config('services.youtube.access_token')); if ($client->isAccessTokenExpired()) { $newToken = $client->fetchAccessTokenWithRefreshToken(config('services.youtube.refresh_token')); // 可将新的access_token更新到.env或数据库 file_put_contents(base_path('.env'), str_replace( 'YOUTUBE_ACCESS_TOKEN=' . env('YOUTUBE_ACCESS_TOKEN'), 'YOUTUBE_ACCESS_TOKEN=' . $newToken['access_token'], file_get_contents(base_path('.env')) )); $client->setAccessToken($newToken); } $this->youtube = new YouTube($client); } public function uploadVideo(string $filePath, string $title, string $description, string $privacyStatus = 'public'): \Google\Service\YouTube\Video { // 构建视频元数据 $video = new YouTube\Video(); $snippet = new YouTube\VideoSnippet(); $snippet->setTitle($title); $snippet->setDescription($description); $snippet->setCategoryId('22'); // 默认分类:娱乐,可按需修改 $video->setSnippet($snippet); $status = new YouTube\VideoStatus(); $status->setPrivacyStatus($privacyStatus); $video->setStatus($status); // 分块上传(大文件友好) $chunkSizeBytes = 1 * 1024 * 1024; $this->youtube->getClient()->setDefer(true); $insertRequest = $this->youtube->videos->insert('status,snippet', $video); $media = new MediaFileUpload( $this->youtube->getClient(), $insertRequest, 'video/*', null, true, $chunkSizeBytes ); $media->setFileSize(filesize($filePath)); $uploadStatus = false; $handle = fopen($filePath, 'rb'); while (!$uploadStatus && !feof($handle)) { $chunk = fread($handle, $chunkSizeBytes); $uploadStatus = $media->nextChunk($chunk); } fclose($handle); $this->youtube->getClient()->setDefer(false); return $uploadStatus; } }
3. 创建上传表单视图
编写前端上传表单:
<!-- resources/views/videos/upload.blade.php --> <form action="{{ route('videos.upload') }}" method="POST" enctype="multipart/form-data"> @csrf <div class="form-group"> <label>视频标题</label> <input type="text" name="title" class="form-control" required> </div> <div class="form-group"> <label>视频描述</label> <textarea name="description" class="form-control" rows="3" required></textarea> </div> <div class="form-group"> <label>视频文件</label> <input type="file" name="video" class="form-control-file" accept="video/*" required> <small class="text-muted">支持MP4/MOV/AVI格式,最大100MB</small> </div> <button type="submit" class="btn btn-primary">上传至YouTube</button> @if(session('success')) <div class="alert alert-success mt-3">{{ session('success') }}</div> @endif </form>
4. 配置路由与控制器逻辑
添加路由到routes/web.php:
use App\Http\Controllers\VideoController; Route::get('/videos/upload', [VideoController::class, 'showUploadForm'])->name('videos.upload.form'); Route::post('/videos/upload', [VideoController::class, 'uploadToYouTube'])->name('videos.upload');
创建控制器处理上传请求:
// app/Http/Controllers/VideoController.php namespace App\Http\Controllers; use App\Models\Video; use App\Services\YouTubeService; use Illuminate\Http\Request; class VideoController extends Controller { public function showUploadForm() { return view('videos.upload'); } public function uploadToYouTube(Request $request, YouTubeService $youtubeService) { $validated = $request->validate([ 'title' => 'required|string|max:255', 'description' => 'required|string', 'video' => 'required|file|mimes:mp4,mov,avi|max:102400', ]); // 临时存储上传文件 $videoFile = $request->file('video'); $tempPath = $videoFile->getRealPath(); // 上传到YouTube $youtubeVideo = $youtubeService->uploadVideo( $tempPath, $validated['title'], $validated['description'] ); // 拼接视频URL $videoUrl = "https://www.youtube.com/watch?v={$youtubeVideo->id}"; // 保存到数据库 Video::create([ 'title' => $validated['title'], 'description' => $validated['description'], 'youtube_url' => $videoUrl, 'youtube_video_id' => $youtubeVideo->id, ]); return redirect()->back()->with('success', '视频上传成功,已同步至数据库!'); } }
5. 生成数据库模型与迁移
创建视频模型和数据表:
php artisan make:model Video -m
编辑迁移文件:
// database/migrations/xxxx_xx_xx_xxxxxx_create_videos_table.php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { public function up() { Schema::create('videos', function (Blueprint $table) { $table->id(); $table->string('title'); $table->text('description')->nullable(); $table->string('youtube_url'); $table->string('youtube_video_id')->unique(); $table->timestamps(); }); } public function down() { Schema::dropIfExists('videos'); } };
运行迁移:
php artisan migrate
关键注意事项
- API配额:上传视频会消耗YouTube API配额,需确保配额充足
- 文件限制:调整PHP配置
upload_max_filesize和post_max_size以支持大文件上传 - 令牌有效期:刷新令牌长期有效,但如果授权被撤销需重新获取
- 隐私设置:可修改
uploadVideo方法的privacyStatus参数,支持public/private/unlisted三种状态
内容的提问来源于stack exchange,提问作者stephen Weru
相关产品推荐
相关产品推荐

