123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694 |
- <?php
- /**
- * Created by Aliyun ApsaraVideo VoD.
- * User: https://www.aliyun.com/product/vod
- */
- use vod\Request\V20170321 as vod;
- use OSS\OssClient;
- use OSS\Core\OssUtil;
- class AliyunVodUploader
- {
- public function __construct($accessKeyId, $accessKeySecret, $apiRegionId=null)
- {
- $this->accessKeyId = $accessKeyId;
- $this->accessKeySecret = $accessKeySecret;
- if (empty($apiRegionId)) {
- // VoD的接入地址,国内为cn-shanghai,参考:https://help.aliyun.com/document_detail/98194.html
- $this->apiRegionId = 'cn-beijing';
- }
- else {
- $this->apiRegionId = $apiRegionId;
- }
- // VOD和OSS的连接超时时间,单位秒
- $this->connTimeout = 1;
- // 设置VOD请求超时时间,单位秒
- $this->vodTimeout = 3;
- // 设置OSS请求超时时间,单位秒,默认是7天, 建议不要设置太小,如果上传文件很大,消耗的时间会比较长
- $this->ossTimeout = 86400*7;
- // 失败后的最大重试次数
- $this->maxRetryTimes = 3;
- $this->multipartThreshold = 10 * 1024 * 1024;
- $this->multipartPartSize = 10 * 1024 * 1024;
- $this->multipartThreadsNum = 3;
- $this->vodClient = $this->initVodClient();
- $this->ossClient = null;
- $this->ecsRegionId = null;
- $this->enableSSL = false;
- }
- /**
- * 设置上传脚本部署的ECS区域(如有),当检测上传区域和点播存储区域位于同一区域时,会自动开启内网上传,能节省流量费用且上传速度更快
- * @param string, $regionId 可选值参考:https://help.aliyun.com/document_detail/40654.html,如cn-shanghai
- */
- public function setEcsRegionId($regionId)
- {
- $this->ecsRegionId = $regionId;
- }
- /**
- * 是否启用SSL(网络请求使用HTTPS),默认不启用,以避免相关扩展未安装或配置异常时无法使用
- * @param bool, $isEnable 可选值参考:https://help.aliyun.com/document_detail/40654.html,如cn-shanghai
- */
- public function setEnableSSL($isEnable)
- {
- $this->enableSSL = $isEnable;
- }
- /**
- * 上传本地视频或音频文件到点播,最大支持48.8TB的单个文件,暂不支持断点续传
- * @param UploadVideoRequest $uploadVideoRequest: UploadVideoRequest类的实例,注意filePath为本地文件的绝对路径
- * @return string, $videoId
- * @throws Exception
- */
- public function uploadLocalVideo($uploadVideoRequest)
- {
- $uploadInfo = $this->createUploadVideo($uploadVideoRequest);
- $headers = $this->getUploadHeaders($uploadVideoRequest);
- $this->uploadOssObject($uploadVideoRequest->getFilePath(), $uploadInfo->UploadAddress->FileName, $uploadInfo, $headers);
- return $uploadInfo->VideoId;
- }
- /**
- * 上传网络视频或音频文件到点播,最大支持48.8TB的单个文件(需本地磁盘空间足够);会先下载到本地临时目录,再上传到点播存储
- * @param UploadVideoRequest $uploadVideoRequest: UploadVideoRequest类的实例,注意filePath为网络文件的URL地址
- * @return string, $videoId
- * @throws Exception
- */
- public function uploadWebVideo($uploadVideoRequest)
- {
- // 下载文件
- $uploadVideoRequest = $this->downloadWebMedia($uploadVideoRequest);
- // 上传到点播
- $uploadInfo = $this->createUploadVideo($uploadVideoRequest);
- $headers = $this->getUploadHeaders($uploadVideoRequest);
- $this->uploadOssObject($uploadVideoRequest->getFilePath(), $uploadInfo->UploadAddress->FileName, $uploadInfo, $headers);
- // 删除下载的本地视频
- unlink($uploadVideoRequest->getFilePath());
- return $uploadInfo->VideoId;
- }
- /**
- * 上传本地图片文件到点播,最大支持48.8TB的单个文件
- * @param UploadImageRequest $uploadImageRequest: UploadImageRequest类的实例,注意filePath为本地文件的绝对路径
- * @return array, array('ImageId'=>'xxxxx', 'ImageURL'=>'http://xxx.jpg')
- * @throws Exception
- */
- public function uploadLocalImage($uploadImageRequest)
- {
- $uploadInfo = $this->createUploadImage($uploadImageRequest);
- $this->uploadOssObject($uploadImageRequest->getFilePath(), $uploadInfo->UploadAddress->FileName, $uploadInfo);
- return array('ImageId'=>$uploadInfo->ImageId, 'ImageURL'=>$uploadInfo->ImageURL);
- }
- /**
- * 上传网络图片文件到点播,最大支持48.8TB的单个文件(需本地磁盘空间足够);会先下载到本地临时目录,再上传到点播存储
- * @param UploadImageRequest $uploadVideoRequest: UploadImageRequest类的实例,注意filePath为网络文件的URL地址
- * @return array, array('ImageId'=>'xxxxx', 'ImageURL'=>'http://xxx.jpg')
- * @throws Exception
- */
- public function uploadWebImage($uploadImageRequest)
- {
- // 下载文件
- $uploadImageRequest = $this->downloadWebMedia($uploadImageRequest);
- // 上传到点播
- $uploadInfo = $this->createUploadImage($uploadImageRequest);
- $this->uploadOssObject($uploadImageRequest->getFilePath(), $uploadInfo->UploadAddress->FileName, $uploadInfo);
- // 删除下载的本地图片
- unlink($uploadImageRequest->getFilePath());
- return array('ImageId'=>$uploadInfo->ImageId, 'ImageURL'=>$uploadInfo->ImageURL);
- }
- /**
- * 上传本地辅助媒资文件(如水印、字幕等)到点播,最大支持48.8TB的单个文件
- * @param UploadAttachedMediaRequest $uploadAttachedRequest: UploadAttachedMediaRequest类的实例,注意filePath为本地文件的绝对路径
- * @return array, array('MediaId'=>'xxxxx', 'MediaURL'=>'http://xxx.jpg', 'FileURL'=>'http://xxx.jpg')
- * @throws Exception
- */
- public function uploadLocalAttachedMedia($uploadAttachedRequest)
- {
- $uploadInfo = $this->createUploadAttachedMedia($uploadAttachedRequest);
- $this->uploadOssObject($uploadAttachedRequest->getFilePath(), $uploadInfo->UploadAddress->FileName, $uploadInfo);
- return array('MediaId'=>$uploadInfo->MediaId, 'MediaURL'=>$uploadInfo->MediaURL, 'FileURL'=>$uploadInfo->FileURL);
- }
- /**
- * 上传网络辅助媒资文件(如水印、字幕等)到点播,最大支持48.8TB的单个文件(需本地磁盘空间足够);会先下载到本地临时目录,再上传到点播存储
- * @param UploadAttachedMediaRequest $uploadAttachedRequest: UploadAttachedMediaRequest类的实例,注意filePath为网络文件的URL地址
- * @return array, array('MediaId'=>'xxxxx', 'MediaURL'=>'http://xxx.jpg', 'FileURL'=>'http://xxx.jpg')
- * @throws Exception
- */
- public function uploadWebAttachedMedia($uploadAttachedRequest)
- {
- // 下载文件
- $uploadAttachedRequest = $this->downloadWebMedia($uploadAttachedRequest);
- // 上传到点播
- $uploadInfo = $this->createUploadAttachedMedia($uploadAttachedRequest);
- $this->uploadOssObject($uploadAttachedRequest->getFilePath(), $uploadInfo->UploadAddress->FileName, $uploadInfo);
- // 删除下载的本地文件
- unlink($uploadAttachedRequest->getFilePath());
- return array('MediaId'=>$uploadInfo->MediaId, 'MediaURL'=>$uploadInfo->MediaURL, 'FileURL'=>$uploadInfo->FileURL);
- }
- /**
- * 上传本地m3u8视频或音频文件到点播,m3u8文件和分片文件默认在同一目录($sliceFiles为null时,会按照同一目录去解析分片地址)
- * @param UploadVideoRequest $uploadVideoRequest: 注意filePath为本地m3u8索引文件的绝对路径,
- * 且m3u8文件的分片信息必须是相对地址,不能含有URL或本地绝对路径
- * @param array $sliceFiles: ts分片文件的绝对路径列表,如指定则以此为准,若不指定,则自动解析$uploadVideoRequest里的m3u8文件
- * @return string, $videoId
- * @throws Exception
- */
- public function uploadLocalM3u8($uploadVideoRequest, $sliceFiles)
- {
- if (!is_array($sliceFiles) || empty($sliceFiles)) {
- throw new Exception("m3u8 slice files invalid", AliyunVodError::VOD_INVALID_M3U8_SLICE_FILE);
- }
- // 上传到点播的m3u8索引文件会重写,以此确保分片地址都为相对地址
- $downloader = new AliyunVodDownloader();
- $m3u8LocalDir = $downloader->getSaveLocalDir() . md5($uploadVideoRequest->getFileName()) . '/';
- $downloader->setSaveLocalDir($m3u8LocalDir);
- $m3u8LocalPath = $m3u8LocalDir . basename($uploadVideoRequest->getFileName());
- $this->rewriteM3u8File($uploadVideoRequest->getFilePath(), $m3u8LocalPath);
- // 解析分片文件地址和文件名
- $sliceList = array();
- if (isset($sliceFiles)) {
- foreach ($sliceFiles as $sliceFilePath) {
- $arr = AliyunVodUtils::getFileName($sliceFilePath);
- $sliceList[] = array($sliceFilePath, $arr[1]);
- }
- }
- // 获取上传地址和凭证
- $uploadVideoRequest->setFilePath($m3u8LocalPath);
- $uploadInfo = $this->createUploadVideo($uploadVideoRequest);
- $headers = $this->getUploadHeaders($uploadVideoRequest);
- // 依次上传分片文件
- foreach ($sliceList as $slice) {
- $this->uploadOssObject($slice[0], $uploadInfo->UploadAddress->ObjectPrefix . $slice[1], $uploadInfo, $headers);
- }
- // 上传m3u8索引文件
- $this->uploadOssObject($uploadVideoRequest->getFilePath(), $uploadInfo->UploadAddress->FileName, $uploadInfo, $headers);
- // 删除重写到本地的m3u8文件
- unlink($m3u8LocalPath);
- return $uploadInfo->VideoId;
- }
- /**
- * 上传网络m3u8视频或音频文件到点播,需本地磁盘空间足够,会先下载到本地临时目录,再上传到点播存储
- * @param UploadVideoRequest $uploadVideoRequest: 注意filePath为网络m3u8索引文件的URL地址,
- 且m3u8文件的分片信息必须是相对地址,不能含有URL或本地绝对路径
- * @param array $sliceFileUrls: ts分片文件的URL地址列表;可自行拼接ts分片的URL地址列表,或者使用parseWebM3u8解析
- * @return string, $videoId
- * @throws Exception
- */
- public function uploadWebM3u8($uploadVideoRequest, $sliceFileUrls)
- {
- if (!is_array($sliceFileUrls) || empty($sliceFileUrls)) {
- throw new Exception("m3u8 slice files invalid", AliyunVodError::VOD_INVALID_M3U8_SLICE_FILE);
- }
- // 下载m3u8文件和所有ts分片文件到本地;上传到点播的m3u8索引文件会重写,确保分片地址都为相对地址
- $downloader = new AliyunVodDownloader();
- $m3u8LocalDir = $downloader->getSaveLocalDir() . md5($uploadVideoRequest->getFileName()) . '/';
- $downloader->setSaveLocalDir($m3u8LocalDir);
- $m3u8LocalPath = $m3u8LocalDir . basename($uploadVideoRequest->getFileName());
- $this->rewriteM3u8File($uploadVideoRequest->getFilePath(), $m3u8LocalPath);
- $sliceList = array();
- foreach ($sliceFileUrls as $sliceFileUrl) {
- $arr = AliyunVodUtils::getFileName($sliceFileUrl);
- $sliceLocalPath = $downloader->downloadFile($sliceFileUrl, $arr[1]);
- if ($sliceLocalPath === false) {
- throw new Exception("ts file download fail: ".$sliceFileUrl, AliyunVodError::VOD_ERR_FILE_DOWNLOAD);
- }
- $sliceList[] = array($sliceLocalPath, $arr[1]);
- }
- // 获取上传地址和凭证
- $uploadVideoRequest->setFilePath($m3u8LocalPath);
- $uploadInfo = $this->createUploadVideo($uploadVideoRequest);
- $headers = $this->getUploadHeaders($uploadVideoRequest);
- // 依次上传分片文件
- foreach ($sliceList as $slice) {
- $this->uploadOssObject($slice[0], $uploadInfo->UploadAddress->ObjectPrefix . $slice[1], $uploadInfo, $headers);
- }
- // 上传m3u8索引文件
- $this->uploadOssObject($uploadVideoRequest->getFilePath(), $uploadInfo->UploadAddress->FileName, $uploadInfo, $headers);
- // 删除下载到本地的文件
- unlink($m3u8LocalPath);
- foreach ($sliceList as $slice) {
- unlink($slice[0]);
- }
- rmdir($m3u8LocalDir);
- return $uploadInfo->VideoId;
- }
- /**
- * 解析m3u8文件得到所有分片文件地址列表,原理是将m3u8地址前缀拼接ts分片名称作为后者的地址;同时支持本地、网络m3u8文件的解析
- 本函数解析时会默认分片文件和m3u8文件位于同一目录,如不是则请自行拼接分片文件的地址列表
- * @param m3u8FileUrl: string, m3u8网络文件url,例如:/opt/sample.m3u8 或 http://host/sample.m3u8
- * @return array, $sliceFileUrls
- * @throws Exception
- */
- public function parseM3u8File($m3u8FilePath) {
- $sliceFileUrls = array();
- $str = @file_get_contents(OssUtil::encodePath($m3u8FilePath));
- if ($str === false) {
- throw new Exception("m3u8 file access fail: ".$m3u8FilePath, AliyunVodError::VOD_ERR_FILE_READ);
- }
- $lines = explode("\n", $str);
- foreach ($lines as $line) {
- $sliceFileName = trim($line);
- if (strlen($sliceFileName) <= 0) {
- continue;
- }
- if (AliyunVodUtils::startsWith($sliceFileName,'#')) {
- continue;
- }
- $sliceFile = AliyunVodUtils::replaceFileName($m3u8FilePath, $sliceFileName);
- if ($sliceFile === false) {
- throw new Exception("m3u8 file invalid", AliyunVodError::VOD_INVALID_M3U8_SLICE_FILE);
- }
- $sliceFileUrls[] = $sliceFile;
- }
- return $sliceFileUrls;
- }
- private function rewriteM3u8File($srcM3u8FilePath, $dstM3u8FilePath) {
- $str = @file_get_contents(OssUtil::encodePath($srcM3u8FilePath));
- if ($str === false) {
- throw new Exception("m3u8 file access fail: ".$srcM3u8FilePath, AliyunVodError::VOD_ERR_M3U8_FILE_REWRITE);
- }
- $lines = explode("\n", $str);
- $newM3u8Text = '';
- foreach ($lines as $line) {
- $sliceFileName = trim($line);
- if (strlen($sliceFileName) <= 0) {
- continue;
- }
- if (AliyunVodUtils::startsWith($sliceFileName,'#')) {
- $newM3u8Text .= $sliceFileName . "\n";
- continue;
- }
- $arr = AliyunVodUtils::getFileName($sliceFileName);
- $newM3u8Text .= $arr[1] . "\n";
- }
- $res = AliyunVodUtils::mkDir($dstM3u8FilePath);
- if ($res === false) {
- throw new Exception("m3u8 file mkdir fail: ".$dstM3u8FilePath, AliyunVodError::VOD_ERR_M3U8_FILE_REWRITE);
- }
- $res = @file_put_contents(OssUtil::encodePath($dstM3u8FilePath), $newM3u8Text);
- if ($res === false) {
- throw new Exception("m3u8 file rewrite fail: ".$dstM3u8FilePath, AliyunVodError::VOD_ERR_M3U8_FILE_REWRITE);
- }
- return true;
- }
- private function downloadWebMedia($request)
- {
- // 下载视频文件到本地临时目录
- $downloader = new AliyunVodDownloader();
- $localFileName = sprintf("%s.%s", md5($request->getFileName()), $request->getMediaExt());
- $webFilePath = $request->getFilePath();
- $localFilePath = $downloader->downloadFile($webFilePath, $localFileName);
- if ($localFilePath === false) {
- throw new Exception("file download fail: ".$webFilePath, AliyunVodError::VOD_ERR_FILE_DOWNLOAD);
- }
- // 重新设置上传请求对象
- $request->setFilePath($localFilePath);
- return $request;
- }
- private function initOssClient($uploadAuth, $uploadAddress)
- {
- $endpoint = AliyunVodUtils::convertOssInternal($uploadAddress->Endpoint, $this->ecsRegionId, $this->enableSSL);
- //printf("oss endpoint: %s\n", $endpoint);
- $this->ossClient = new OssClient($uploadAuth->AccessKeyId, $uploadAuth->AccessKeySecret, $endpoint,
- false, $uploadAuth->SecurityToken);
- $this->ossClient->setTimeout($this->ossTimeout);
- $this->ossClient->setConnectTimeout($this->connTimeout);
- return $this->ossClient;
- }
- private function initVodClient()
- {
- HttpHelper::$connectTimeout = $this->connTimeout;
- HttpHelper::$readTimeout = $this->vodTimeout;
- $profile = DefaultProfile::getProfile($this->apiRegionId, $this->accessKeyId, $this->accessKeySecret, $this->securityToken);
- //DefaultProfile::addEndpoint($this->apiRegionId, $this->apiRegionId, "vod", "vod.".$this->apiRegionId.".aliyuncs.com");
- return new DefaultAcsClient($profile);
- }
- private function getUploadHeaders($uploadVideoRequest) {
- $switch = $uploadVideoRequest->getWatermarkSwitch();
- if (is_null($switch)) {
- return null;
- }
- $userData = sprintf("{\"Vod\":{\"UserData\":{\"IsShowWaterMark\": \"%s\"}}}", $switch);
- return array('x-oss-notification' => base64_encode($userData));
- }
- private function createUploadVideo($uploadVideoRequest)
- {
- $request = new vod\CreateUploadVideoRequest();
- $title = AliyunVodUtils::subString($uploadVideoRequest->getTitle(), AliyunVodUtils::VOD_MAX_TITLE_LENGTH);
- $request->setTitle($title);
- $request->setFileName($uploadVideoRequest->getFileName());
- if (!is_null($uploadVideoRequest->getDescription())) {
- $request->setDescription($uploadVideoRequest->getDescription());
- }
- if (!is_null($uploadVideoRequest->getCateId())) {
- $request->setCateId($uploadVideoRequest->getCateId());
- }
- if (!is_null($uploadVideoRequest->getTags())) {
- $request->setTags($uploadVideoRequest->getTags());
- }
- if (!is_null($uploadVideoRequest->getCoverURL())) {
- $request->setCoverURL($uploadVideoRequest->getCoverURL());
- }
- if (!is_null($uploadVideoRequest->getTemplateGroupId())) {
- $request->setTemplateGroupId($uploadVideoRequest->getTemplateGroupId());
- }
- if (!is_null($uploadVideoRequest->getStorageLocation())) {
- $request->setStorageLocation($uploadVideoRequest->getStorageLocation());
- }
- if (!is_null($uploadVideoRequest->getUserData())) {
- $request->setUserData($uploadVideoRequest->getUserData());
- }
- if (!is_null($uploadVideoRequest->getAppId())) {
- $request->setAppId($uploadVideoRequest->getAppId());
- }
- if (!is_null($uploadVideoRequest->getWorkflowId())) {
- $request->setWorkflowId($uploadVideoRequest->getWorkflowId());
- }
- $data = $this->requestUploadInfo($request, 'video');
- AliyunVodLog::printLog("CreateUploadVideo, FilePath: %s, VideoId: %s", $uploadVideoRequest->getFilePath(), $data->VideoId);
- return $data;
- }
- private function requestUploadInfo($request, $mediaType)
- {
- $request->setAcceptFormat('JSON');
- $data = $this->vodClient->getAcsResponse($request, null, null, true, $this->maxRetryTimes);
- $data->OriUploadAddress = $data->UploadAddress;
- $data->OriUploadAuth = $data->UploadAuth;
- $data->UploadAddress = json_decode(base64_decode($data->OriUploadAddress));
- $data->UploadAuth = json_decode(base64_decode($data->OriUploadAuth));
- $data->MediaType = $mediaType;
- if ($mediaType == 'video') {
- $data->MediaId = $data->VideoId;
- }
- elseif ($mediaType == 'image') {
- $data->MediaId = $data->ImageId;
- $data->MediaURL = $data->ImageURL;
- }
- return $data;
- }
- private function refreshUploadVideo($videoId)
- {
- $request = new vod\RefreshUploadVideoRequest();
- $request->setVideoId($videoId);
- $data = $this->requestUploadInfo($request, 'video');
- AliyunVodLog::printLog("RefreshUploadVideo, VideoId: %s", $data->VideoId);
- return $data;
- }
- private function createUploadImage($uploadImageRequest)
- {
- $request = new vod\CreateUploadImageRequest();
- $request->setImageType($uploadImageRequest->getImageType());
- $request->setImageExt($uploadImageRequest->getImageExt());
- if (!is_null($uploadImageRequest->getTitle())) {
- $title = AliyunVodUtils::subString($uploadImageRequest->getTitle(), AliyunVodUtils::VOD_MAX_TITLE_LENGTH);
- $request->setTitle($title);
- }
- if (!is_null($uploadImageRequest->getDescription())) {
- $request->setDescription($uploadImageRequest->getDescription());
- }
- if (!is_null($uploadImageRequest->getCateId())) {
- $request->setCateId($uploadImageRequest->getCateId());
- }
- if (!is_null($uploadImageRequest->getTags())) {
- $request->setTags($uploadImageRequest->getTags());
- }
- if (!is_null($uploadImageRequest->getStorageLocation())) {
- $request->setStorageLocation($uploadImageRequest->getStorageLocation());
- }
- if (!is_null($uploadImageRequest->getUserData())) {
- $request->setUserData($uploadImageRequest->getUserData());
- }
- if (!is_null($uploadImageRequest->getAppId())) {
- $request->setAppId($uploadImageRequest->getAppId());
- }
- if (!is_null($uploadImageRequest->getWorkflowId())) {
- $request->setWorkflowId($uploadImageRequest->getWorkflowId());
- }
- $data = $this->requestUploadInfo($request, 'image');
- AliyunVodLog::printLog("CreateUploadImage, FilePath: %s, ImageId: %s, ImageURL: %s",
- $uploadImageRequest->getFilePath(), $data->ImageId, $data->ImageURL);
- return $data;
- }
- private function createUploadAttachedMedia($uploadAttachedRequest)
- {
- $request = new vod\CreateUploadAttachedMediaRequest();
- $request->setBusinessType($uploadAttachedRequest->getBusinessType());
- $request->setMediaExt($uploadAttachedRequest->getMediaExt());
- if (!is_null($uploadAttachedRequest->getTitle())) {
- $title = AliyunVodUtils::subString($uploadAttachedRequest->getTitle(), AliyunVodUtils::VOD_MAX_TITLE_LENGTH);
- $request->setTitle($title);
- }
- if (!is_null($uploadAttachedRequest->getDescription())) {
- $request->setDescription($uploadAttachedRequest->getDescription());
- }
- if (!is_null($uploadAttachedRequest->getCateId())) {
- $request->setCateId($uploadAttachedRequest->getCateId());
- }
- if (!is_null($uploadAttachedRequest->getTags())) {
- $request->setTags($uploadAttachedRequest->getTags());
- }
- if (!is_null($uploadAttachedRequest->getStorageLocation())) {
- $request->setStorageLocation($uploadAttachedRequest->getStorageLocation());
- }
- if (!is_null($uploadAttachedRequest->getFileSize())) {
- $request->setFileSize($uploadAttachedRequest->getFileSize());
- }
- if (!is_null($uploadAttachedRequest->getUserData())) {
- $request->setUserData($uploadAttachedRequest->getUserData());
- }
- if (!is_null($uploadAttachedRequest->getAppId())) {
- $request->setAppId($uploadAttachedRequest->getAppId());
- }
- if (!is_null($uploadAttachedRequest->getWorkflowId())) {
- $request->setWorkflowId($uploadAttachedRequest->getWorkflowId());
- }
- $data = $this->requestUploadInfo($request, 'attached');
- AliyunVodLog::printLog("CreateUploadAttachedMedia, FilePath: %s, MediaId: %s, MediaURL: %s",
- $uploadAttachedRequest->getFilePath(), $data->MediaId, $data->MediaURL);
- return $data;
- }
- private function uploadOssObject($filePath, $object, $uploadInfo, $headers=null)
- {
- $this->initOssClient($uploadInfo->UploadAuth, $uploadInfo->UploadAddress);
- $this->multipartUploadMediaFile($filePath, $object, $uploadInfo, $headers);
- $bucketHost = str_replace('://', '://'.$uploadInfo->UploadAddress->Bucket.".",
- $uploadInfo->UploadAddress->Endpoint);
- AliyunVodLog::printLog("UploadFile %s Finish, MediaId: %s, FilePath: %s, Destination: %s/%s",
- $uploadInfo->MediaType, $uploadInfo->MediaId, $filePath, $bucketHost, $object);
- }
- // 定义进度条回调函数;$consumedBytes: 已上传的数据量,$totalBytes:总数据量
- public function uploadProgressCallback($mediaId, $consumedBytes, $totalBytes)
- {
- if ($totalBytes > 0) {
- $rate = 100 * (floatval(($consumedBytes) / floatval($totalBytes)));
- }
- else {
- $rate = 0;
- }
- /*printf("[%s]UploadProgress of Media %s, uploaded %s bytes, percent %s%s\n",
- AliyunVodUtils::getCurrentTimeStr(), $mediaId, $consumedBytes, round($rate, 1), '%');*/
- flush();
- }
- // 分片上传函数
- private function multipartUploadMediaFile($filePath, $object, $uploadInfo, $headers=null)
- {
- $uploadFile = OssUtil::encodePath($filePath);
- if (!file_exists($uploadFile)) {
- throw new Exception("file not exists: ".$uploadFile, AliyunVodError::VOD_ERR_FILE_READ);
- }
- $fileSize = @filesize($uploadFile);
- if ($fileSize === false || $fileSize < 0) {
- throw new Exception('The size of file cannot be determined: '.$filePath,AliyunVodError::VOD_ERR_FILE_READ);
- }
- $this->filePartHash = null;
- $bucket = $uploadInfo->UploadAddress->Bucket;
- // 文件大小未超过分片上传阈值,或不到一个分片的大小,则直接简单上传
- if ($fileSize <= $this->multipartThreshold || $fileSize < $this->multipartPartSize) {
- $res = $this->ossClient->uploadFile($bucket, $object, $uploadFile);
- if ($uploadInfo->MediaType == 'video') {
- $this->reportVideoUploadProgress('put', $uploadInfo, $filePath, $fileSize, 0, $fileSize,
- 1, 1, $fileSize);
- }
- return $res;
- }
- // 初始化分片
- $uploadId = $this->ossClient->initiateMultipartUpload($bucket, $object);
- $pieces = $this->ossClient->generateMultiuploadParts($fileSize, $this->multipartPartSize);
- $resUploadPart = array();
- $uploadPosition = 0;
- $isCheckMd5 = false;
- $totalPart = count($pieces);
- // 上传凭证有效期3000秒,如果是音视频,则需要提前刷新
- $startTime = time();
- $expireSeconds = 2500;
- // 逐个上传分片
- foreach ($pieces as $i => $piece) {
- $fromPos = $uploadPosition + (integer)$piece[OssClient::OSS_SEEK_TO];
- $toPos = (integer)$piece[OssClient::OSS_LENGTH] + $fromPos - 1;
- $upOptions = array(
- OssClient::OSS_FILE_UPLOAD => $uploadFile,
- OssClient::OSS_PART_NUM => ($i + 1),
- OssClient::OSS_SEEK_TO => $fromPos,
- OssClient::OSS_LENGTH => $toPos - $fromPos + 1,
- OssClient::OSS_CHECK_MD5 => $isCheckMd5,
- );
- if ($isCheckMd5) {
- $contentMd5 = OssUtil::getMd5SumForFile($uploadFile, $fromPos, $toPos);
- $upOptions[OssClient::OSS_CONTENT_MD5] = $contentMd5;
- }
- // 上传分片
- $resUploadPart[] = $this->ossClient->uploadPart($bucket, $object, $uploadId, $upOptions);
- /*AliyunVodLog::printLog("UploadPart, FilePath: %s, MediaId: %s, MediaType: %s, UploadId: %s, PartNumber: %s, PartSize: %s",
- $uploadFile, $uploadInfo->MediaId, $uploadInfo->MediaType, $uploadId, $upOptions[OssClient::OSS_PART_NUM], $upOptions[OssClient::OSS_LENGTH]);*/
- // 上传进度回调
- $this->uploadProgressCallback($uploadInfo->MediaId, $toPos, $fileSize);
- if ($uploadInfo->MediaType == 'video') {
- // 上报上传进度
- $this->reportVideoUploadProgress('multipart', $uploadInfo, $uploadFile, $fileSize,
- $uploadId, $this->multipartPartSize, $totalPart, $upOptions[OssClient::OSS_PART_NUM], $toPos);
- // 检测视频上传凭证是否过期
- $nowTime = time();
- if ($nowTime - $startTime >= $expireSeconds) {
- $uploadInfo = $this->refreshUploadVideo($uploadInfo->MediaId);
- $this->initOssClient($uploadInfo->UploadAuth, $uploadInfo->UploadAddress);
- $startTime = $nowTime;
- }
- }
- }
- $uploadParts = array();
- foreach ($resUploadPart as $i => $eTag) {
- $uploadParts[] = array(
- 'PartNumber' => ($i + 1),
- 'ETag' => $eTag,
- );
- }
- // 完成上传
- $options = is_null($headers) ? null : array(OssClient::OSS_HEADERS => $headers);
- $res = $this->ossClient->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts, $options);
- if ($uploadInfo->MediaType == 'video') {
- $this->reportVideoUploadProgress('multipart', $uploadInfo, $filePath, $fileSize, $uploadId,
- $this->multipartPartSize, $totalPart, $totalPart, $fileSize);
- }
- return $res;
- }
- private function reportVideoUploadProgress($uploadMethod, $uploadInfo, $filePath, $fileSize, $uploadId, $partSize,
- $totalPart, $donePartsCount, $doneBytes)
- {
- if (is_null($this->filePartHash)) {
- $this->filePartHash = AliyunVodReportUpload::generateFilePartHash($this->accessKeyId, $filePath, $fileSize);
- }
- $uploadPoint = array('upMethod'=>$uploadMethod, 'threshold'=>$this->multipartThreshold,
- 'partSize'=>$this->multipartPartSize, 'doneBytes'=>$doneBytes);
- $progressInfo = array('FileName'=>$filePath, 'FileHash'=>$this->filePartHash, 'FileSize'=>$fileSize, 'UploadId'=>$uploadId,
- 'PartSize'=>$partSize, 'TotalPart'=>$totalPart, 'DonePartsCount'=>$donePartsCount,
- 'UploadPoint'=>json_encode($uploadPoint), 'UploadAddress'=>$uploadInfo->OriUploadAddress);
- AliyunVodReportUpload::reportUploadProgress($this->accessKeyId, $uploadInfo->MediaId, $progressInfo);
- }
- private $accessKeyId;
- private $accessKeySecret;
- private $apiRegionId;
- private $ecsRegionId;
- private $connTimeout;
- private $ossTimeout;
- private $vodTimeout;
- private $vodClient;
- private $ossClient;
- private $maxRetryTimes;
- private $filePartHash;
- private $enableSSL;
- private $securityToken = null;
- // 分片上传的阈值,超过此值开启分片上传
- private $multipartThreshold;
- // 分片大小,单位byte
- private $multipartPartSize;
- // 分片上传时并行上传的线程数,暂时为串行上传,不支持并行,后续会支持。
- private $multipartThreadsNum;
- }
|