初始化仓库

This commit is contained in:
wangxiaowei
2025-04-22 14:09:52 +08:00
commit 8b100110bb
5155 changed files with 664201 additions and 0 deletions

View File

@ -0,0 +1,123 @@
<?php
namespace Qiniu\Storage;
use Qiniu\Auth;
use Qiniu\Config;
use Qiniu\Zone;
use Qiniu\Http\Client;
use Qiniu\Http\Error;
/**
* 主要涉及了内容审核接口的实现,具体的接口规格可以参考
*
* @link https://developer.qiniu.com/censor/api/5620/video-censor
*/
final class ArgusManager
{
private $auth;
private $config;
public function __construct(Auth $auth, Config $config = null)
{
$this->auth = $auth;
if ($config == null) {
$this->config = new Config();
} else {
$this->config = $config;
}
}
/**
* 视频审核
*
* @param string $body body信息
*
* @return array 成功返回NULL失败返回对象Qiniu\Http\Error
* @link https://developer.qiniu.com/censor/api/5620/video-censor
*/
public function censorVideo($body)
{
$path = '/v3/video/censor';
return $this->arPost($path, $body);
}
/**
* 图片审核
*
* @param string $body
*
* @return array 成功返回NULL失败返回对象Qiniu\Http\Error
* @link https://developer.qiniu.com/censor/api/5588/image-censor
*/
public function censorImage($body)
{
$path = '/v3/image/censor';
return $this->arPost($path, $body);
}
/**
* 查询视频审核结果
*
* @param string $jobid 任务ID
* @return array
* @link https://developer.qiniu.com/censor/api/5620/video-censor
*/
public function censorStatus($jobid)
{
$scheme = "http://";
if ($this->config->useHTTPS === true) {
$scheme = "https://";
}
$url = $scheme . Config::ARGUS_HOST . "/v3/jobs/video/$jobid";
$response = $this->get($url);
if (!$response->ok()) {
print("statusCode: " . $response->statusCode);
return array(null, new Error($url, $response));
}
return array($response->json(), null);
}
private function getArHost()
{
$scheme = "http://";
if ($this->config->useHTTPS === true) {
$scheme = "https://";
}
return $scheme . Config::ARGUS_HOST;
}
private function arPost($path, $body = null)
{
$url = $this->getArHost() . $path;
return $this->post($url, $body);
}
private function get($url)
{
$headers = $this->auth->authorizationV2($url, 'GET');
return Client::get($url, $headers);
}
private function post($url, $body)
{
$headers = $this->auth->authorizationV2($url, 'POST', $body, 'application/json');
$headers['Content-Type'] = 'application/json';
$ret = Client::post($url, $body, $headers);
if (!$ret->ok()) {
print("statusCode: " . $ret->statusCode);
return array(null, new Error($url, $ret));
}
$r = ($ret->body === null) ? array() : $ret->json();
if (strstr($url, "video")) {
$jobid = $r['job'];
return array($jobid, null);
}
return array($r, null);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,140 @@
<?php
namespace Qiniu\Storage;
use Qiniu\Http\Error;
use Qiniu\Http\Client;
final class FormUploader
{
/**
* 上传二进制流到七牛, 内部使用
*
* @param string $upToken 上传凭证
* @param string $key 上传文件名
* @param string $data 上传二进制流
* @param string $config 上传配置
* @param string $params 自定义变量,规格参考
* https://developer.qiniu.com/kodo/manual/1235/vars#xvar
* @param string $mime 上传数据的mimeType
*
* @param string $fname
*
* @return array 包含已上传文件的信息,类似:
* [
* "hash" => "<Hash string>",
* "key" => "<Key string>"
* ]
*/
public static function put(
$upToken,
$key,
$data,
$config,
$params,
$mime,
$fname
) {
$fields = array('token' => $upToken);
if ($key === null) {
} else {
$fields['key'] = $key;
}
//enable crc32 check by default
$fields['crc32'] = \Qiniu\crc32_data($data);
if ($params) {
foreach ($params as $k => $v) {
$fields[$k] = $v;
}
}
list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken);
if ($err != null) {
return array(null, $err);
}
$upHost = $config->getUpHost($accessKey, $bucket);
$response = Client::multipartPost($upHost, $fields, 'file', $fname, $data, $mime);
if (!$response->ok()) {
return array(null, new Error($upHost, $response));
}
return array($response->json(), null);
}
/**
* 上传文件到七牛,内部使用
*
* @param string $upToken 上传凭证
* @param string $key 上传文件名
* @param string $filePath 上传文件的路径
* @param string $config 上传配置
* @param string $params 自定义变量,规格参考
* https://developer.qiniu.com/kodo/manual/1235/vars#xvar
* @param string $mime 上传数据的mimeType
*
* @return array 包含已上传文件的信息,类似:
* [
* "hash" => "<Hash string>",
* "key" => "<Key string>"
* ]
*/
public static function putFile(
$upToken,
$key,
$filePath,
$config,
$params,
$mime
) {
$fields = array('token' => $upToken, 'file' => self::createFile($filePath, $mime));
if ($key !== null) {
$fields['key'] = $key;
}
$fields['crc32'] = \Qiniu\crc32_file($filePath);
if ($params) {
foreach ($params as $k => $v) {
$fields[$k] = $v;
}
}
$fields['key'] = $key;
$headers = array('Content-Type' => 'multipart/form-data');
list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken);
if ($err != null) {
return array(null, $err);
}
$upHost = $config->getUpHost($accessKey, $bucket);
$response = Client::post($upHost, $fields, $headers);
if (!$response->ok()) {
return array(null, new Error($upHost, $response));
}
return array($response->json(), null);
}
private static function createFile($filename, $mime)
{
// PHP 5.5 introduced a CurlFile object that deprecates the old @filename syntax
// See: https://wiki.php.net/rfc/curl-file-upload
if (function_exists('curl_file_create')) {
return curl_file_create($filename, $mime);
}
// Use the old style if using an older version of PHP
$value = "@{$filename}";
if (!empty($mime)) {
$value .= ';type=' . $mime;
}
return $value;
}
}

View File

@ -0,0 +1,383 @@
<?php
namespace Qiniu\Storage;
use Qiniu\Config;
use Qiniu\Http\Client;
use Qiniu\Http\Error;
/**
* 断点续上传类, 该类主要实现了断点续上传中的分块上传,
* 以及相应地创建块和创建文件过程.
*
* @link http://developer.qiniu.com/docs/v6/api/reference/up/mkblk.html
* @link http://developer.qiniu.com/docs/v6/api/reference/up/mkfile.html
*/
final class ResumeUploader
{
private $upToken;
private $key;
private $inputStream;
private $size;
private $params;
private $mime;
private $contexts;
private $finishedEtags;
private $host;
private $bucket;
private $currentUrl;
private $config;
private $resumeRecordFile;
private $version;
private $partSize;
/**
* 上传二进制流到七牛
*
* @param string $upToken 上传凭证
* @param string $key 上传文件名
* @param string $inputStream 上传二进制流
* @param string $size 上传流的大小
* @param string $params 自定义变量
* @param string $mime 上传数据的mimeType
* @param string $config
* @param string $resumeRecordFile 断点续传的已上传的部分信息记录文件
* @param string $version 分片上传版本 目前支持v1/v2版本 默认v1
* @param string $partSize 分片上传v2字段 默认大小为4MB 分片大小范围为1 MB - 1 GB
*
* @link http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar
*/
public function __construct(
$upToken,
$key,
$inputStream,
$size,
$params,
$mime,
$config,
$resumeRecordFile = null,
$version = 'v1',
$partSize = config::BLOCK_SIZE
) {
$this->upToken = $upToken;
$this->key = $key;
$this->inputStream = $inputStream;
$this->size = $size;
$this->params = $params;
$this->mime = $mime;
$this->contexts = array();
$this->finishedEtags = array("etags"=>array(), "uploadId"=>"", "expiredAt"=>0, "uploaded"=>0);
$this->config = $config;
$this->resumeRecordFile = $resumeRecordFile ? $resumeRecordFile : null;
$this->version = $version ? $version : 'v1';
$this->partSize = $partSize ? $partSize : config::BLOCK_SIZE;
list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken);
$this->bucket = $bucket;
if ($err != null) {
return array(null, $err);
}
$upHost = $config->getUpHost($accessKey, $bucket);
if ($err != null) {
throw new \Exception($err->message(), 1);
}
$this->host = $upHost;
}
/**
* 上传操作
*/
public function upload($fname)
{
$uploaded = 0;
if ($this->version == 'v2') {
$partNumber = 1;
$encodedObjectName = $this->key? \Qiniu\base64_urlSafeEncode($this->key) : '~';
};
// get upload record from resumeRecordFile
if ($this->resumeRecordFile != null) {
$blkputRets = null;
if (file_exists($this->resumeRecordFile)) {
$stream = fopen($this->resumeRecordFile, 'r');
if ($stream) {
$streamLen = filesize($this->resumeRecordFile);
if ($streamLen > 0) {
$contents = fread($stream, $streamLen);
fclose($stream);
if ($contents) {
$blkputRets = json_decode($contents, true);
if ($blkputRets === null) {
error_log("resumeFile contents decode error");
}
} else {
error_log("read resumeFile failed");
}
} else {
error_log("resumeFile is empty");
}
} else {
error_log("resumeFile open failed");
}
} else {
error_log("resumeFile not exists");
}
if ($blkputRets) {
if ($this->version == 'v1') {
if (isset($blkputRets['contexts']) && isset($blkputRets['uploaded']) &&
is_array($blkputRets['contexts']) && is_int($blkputRets['uploaded'])) {
$this->contexts = $blkputRets['contexts'];
$uploaded = $blkputRets['uploaded'];
}
} elseif ($this->version == 'v2') {
if (isset($blkputRets["etags"]) && isset($blkputRets["uploadId"]) &&
isset($blkputRets["expiredAt"]) && $blkputRets["expiredAt"] > time()
&& $blkputRets["uploaded"] > 0 && is_array($blkputRets["etags"]) &&
is_string($blkputRets["uploadId"]) && is_int($blkputRets["expiredAt"])) {
$this->finishedEtags['etags'] = $blkputRets["etags"];
$this->finishedEtags["uploadId"] = $blkputRets["uploadId"];
$this->finishedEtags["expiredAt"] = $blkputRets["expiredAt"];
$this->finishedEtags["uploaded"] = $blkputRets["uploaded"];
$uploaded = $blkputRets["uploaded"];
$partNumber = count($this->finishedEtags["etags"]) + 1;
} else {
$this->makeInitReq($encodedObjectName);
}
} else {
throw new \Exception("only support v1/v2 now!");
}
} else {
if ($this->version == 'v2') {
$this->makeInitReq($encodedObjectName);
}
}
} else {
// init a Multipart Upload task if choose v2
if ($this->version == 'v2') {
$this->makeInitReq($encodedObjectName);
}
}
while ($uploaded < $this->size) {
$blockSize = $this->blockSize($uploaded);
$data = fread($this->inputStream, $blockSize);
if ($data === false) {
throw new \Exception("file read failed", 1);
}
if ($this->version == 'v1') {
$crc = \Qiniu\crc32_data($data);
$response = $this->makeBlock($data, $blockSize);
} else {
$md5 = md5($data);
$response = $this->uploadPart($data, $partNumber, $this->finishedEtags["uploadId"], $encodedObjectName);
}
$ret = null;
if ($response->ok() && $response->json() != null) {
$ret = $response->json();
}
if ($response->statusCode < 0) {
list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($this->upToken);
if ($err != null) {
return array(null, $err);
}
$upHostBackup = $this->config->getUpBackupHost($accessKey, $bucket);
$this->host = $upHostBackup;
}
if ($this->version == 'v1') {
if ($response->needRetry() || !isset($ret['crc32']) || $crc != $ret['crc32']) {
$response = $this->makeBlock($data, $blockSize);
$ret = $response->json();
}
if (!$response->ok() || !isset($ret['crc32']) || $crc != $ret['crc32']) {
return array(null, new Error($this->currentUrl, $response));
}
array_push($this->contexts, $ret['ctx']);
} else {
if ($response->needRetry() || !isset($ret['md5']) || $md5 != $ret['md5']) {
$response = $this->uploadPart(
$data,
$partNumber,
$this->finishedEtags["uploadId"],
$encodedObjectName
);
$ret = $response->json();
}
if (!$response->ok() || !isset($ret['md5']) || $md5 != $ret['md5']) {
return array(null, new Error($this->currentUrl, $response));
}
$blockStatus = array('etag' => $ret['etag'], 'partNumber' => $partNumber);
array_push($this->finishedEtags['etags'], $blockStatus);
$partNumber += 1;
}
$uploaded += $blockSize;
if ($this->version == 'v2') {
$this->finishedEtags['uploaded'] = $uploaded;
}
if ($this->resumeRecordFile !== null) {
if ($this->version == 'v1') {
$recordData = array(
'contexts' => $this->contexts,
'uploaded' => $uploaded
);
$recordData = json_encode($recordData);
} else {
$recordData = json_encode($this->finishedEtags);
}
if ($recordData) {
$isWritten = file_put_contents($this->resumeRecordFile, $recordData);
if ($isWritten === false) {
error_log("write resumeRecordFile failed");
}
} else {
error_log('resumeRecordData encode failed');
}
}
}
if ($this->version == 'v1') {
return $this->makeFile($fname);
} else {
return $this->completeParts($fname, $this->finishedEtags['uploadId'], $encodedObjectName);
}
}
/**
* 创建块
*/
private function makeBlock($block, $blockSize)
{
$url = $this->host . '/mkblk/' . $blockSize;
return $this->post($url, $block);
}
private function fileUrl($fname)
{
$url = $this->host . '/mkfile/' . $this->size;
$url .= '/mimeType/' . \Qiniu\base64_urlSafeEncode($this->mime);
if ($this->key != null) {
$url .= '/key/' . \Qiniu\base64_urlSafeEncode($this->key);
}
$url .= '/fname/' . \Qiniu\base64_urlSafeEncode($fname);
if (!empty($this->params)) {
foreach ($this->params as $key => $value) {
$val = \Qiniu\base64_urlSafeEncode($value);
$url .= "/$key/$val";
}
}
return $url;
}
/**
* 创建文件
*/
private function makeFile($fname)
{
$url = $this->fileUrl($fname);
$body = implode(',', $this->contexts);
$response = $this->post($url, $body);
if ($response->needRetry()) {
$response = $this->post($url, $body);
}
if (!$response->ok()) {
return array(null, new Error($this->currentUrl, $response));
}
return array($response->json(), null);
}
private function post($url, $data)
{
$this->currentUrl = $url;
$headers = array('Authorization' => 'UpToken ' . $this->upToken);
return Client::post($url, $data, $headers);
}
private function blockSize($uploaded)
{
if ($this->size < $uploaded + $this->partSize) {
return $this->size - $uploaded;
}
return $this->partSize;
}
private function makeInitReq($encodedObjectName)
{
$res = $this->initReq($encodedObjectName);
$this->finishedEtags["uploadId"] = $res['uploadId'];
$this->finishedEtags["expiredAt"] = $res['expireAt'];
}
/**
* 初始化上传任务
*/
private function initReq($encodedObjectName)
{
$url = $this->host.'/buckets/'.$this->bucket.'/objects/'.$encodedObjectName.'/uploads';
$headers = array(
'Authorization' => 'UpToken ' . $this->upToken,
'Content-Type' => 'application/json'
);
$response = $this->postWithHeaders($url, null, $headers);
return $response->json();
}
/**
* 分块上传v2
*/
private function uploadPart($block, $partNumber, $uploadId, $encodedObjectName)
{
$headers = array(
'Authorization' => 'UpToken ' . $this->upToken,
'Content-Type' => 'application/octet-stream',
'Content-MD5' => $block
);
$url = $this->host.'/buckets/'.$this->bucket.'/objects/'.$encodedObjectName.
'/uploads/'.$uploadId.'/'.$partNumber;
$response = $this->put($url, $block, $headers);
return $response;
}
private function completeParts($fname, $uploadId, $encodedObjectName)
{
$headers = array(
'Authorization' => 'UpToken '.$this->upToken,
'Content-Type' => 'application/json'
);
$etags = $this->finishedEtags['etags'];
$sortedEtags = \Qiniu\arraySort($etags, 'partNumber');
$body = array(
'fname' => $fname,
'$mimeType' => $this->mime,
'customVars' => $this->params,
'parts' => $sortedEtags
);
$jsonBody = json_encode($body);
$url = $this->host.'/buckets/'.$this->bucket.'/objects/'.$encodedObjectName.'/uploads/'.$uploadId;
$response = $this->postWithHeaders($url, $jsonBody, $headers);
if ($response->needRetry()) {
$response = $this->postWithHeaders($url, $jsonBody, $headers);
}
if (!$response->ok()) {
return array(null, new Error($this->currentUrl, $response));
}
return array($response->json(), null);
}
private function put($url, $data, $headers)
{
$this->currentUrl = $url;
return Client::put($url, $data, $headers);
}
private function postWithHeaders($url, $data, $headers)
{
$this->currentUrl = $url;
return Client::post($url, $data, $headers);
}
}

View File

@ -0,0 +1,152 @@
<?php
namespace Qiniu\Storage;
use Qiniu\Config;
use Qiniu\Http\HttpClient;
use Qiniu\Storage\ResumeUploader;
use Qiniu\Storage\FormUploader;
/**
* 主要涉及了资源上传接口的实现
*
* @link http://developer.qiniu.com/docs/v6/api/reference/up/
*/
final class UploadManager
{
private $config;
public function __construct(Config $config = null)
{
if ($config === null) {
$config = new Config();
}
$this->config = $config;
}
/**
* 上传二进制流到七牛
*
* @param $upToken 上传凭证
* @param $key 上传文件名
* @param $data 上传二进制流
* @param $params 自定义变量,规格参考
* http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar
* @param $mime 上传数据的mimeType
* @param $checkCrc 是否校验crc32
*
* @return array 包含已上传文件的信息,类似:
* [
* "hash" => "<Hash string>",
* "key" => "<Key string>"
* ]
*/
public function put(
$upToken,
$key,
$data,
$params = null,
$mime = 'application/octet-stream',
$fname = "default_filename"
) {
$params = self::trimParams($params);
return FormUploader::put(
$upToken,
$key,
$data,
$this->config,
$params,
$mime,
$fname
);
}
/**
* 上传文件到七牛
*
* @param $upToken 上传凭证
* @param $key 上传文件名
* @param $filePath 上传文件的路径
* @param $params 自定义变量,规格参考
* http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar
* @param $mime 上传数据的mimeType
* @param $checkCrc 是否校验crc32
* @param $version 分片上传版本 目前支持v1/v2版本 默认v1
* @param $partSize 分片上传v2字段 默认大小为4MB 分片大小范围为1 MB - 1 GB
* @param $resumeRecordFile 断点续传文件路径 默认为null
* @return array 包含已上传文件的信息,类似:
* [
* "hash" => "<Hash string>",
* "key" => "<Key string>"
* ]
*/
public function putFile(
$upToken,
$key,
$filePath,
$params = null,
$mime = 'application/octet-stream',
$checkCrc = false,
$resumeRecordFile = null,
$version = 'v1',
$partSize = config::BLOCK_SIZE
) {
$file = fopen($filePath, 'rb');
if ($file === false) {
throw new \Exception("file can not open", 1);
}
$params = self::trimParams($params);
$stat = fstat($file);
$size = $stat['size'];
if ($size <= Config::BLOCK_SIZE) {
$data = fread($file, $size);
fclose($file);
if ($data === false) {
throw new \Exception("file can not read", 1);
}
return FormUploader::put(
$upToken,
$key,
$data,
$this->config,
$params,
$mime,
basename($filePath)
);
}
$up = new ResumeUploader(
$upToken,
$key,
$file,
$size,
$params,
$mime,
$this->config,
$resumeRecordFile,
$version,
$partSize
);
$ret = $up->upload(basename($filePath));
fclose($file);
return $ret;
}
public static function trimParams($params)
{
if ($params === null) {
return null;
}
$ret = array();
foreach ($params as $k => $v) {
$pos1 = strpos($k, 'x:');
$pos2 = strpos($k, 'x-qn-meta-');
if (($pos1 === 0 || $pos2 === 0) && !empty($v)) {
$ret[$k] = $v;
}
}
return $ret;
}
}