diff --git a/Plugin.php b/Plugin.php new file mode 100644 index 0000000..431c73e --- /dev/null +++ b/Plugin.php @@ -0,0 +1,602 @@ +uploadHandle = array('Qiniu_Plugin', 'uploadHandle'); + Typecho_Plugin::factory('Widget_Upload')->modifyHandle = array('Qiniu_Plugin', 'modifyHandle'); + Typecho_Plugin::factory('Widget_Upload')->deleteHandle = array('Qiniu_Plugin', 'deleteHandle'); + Typecho_Plugin::factory('Widget_Upload')->attachmentHandle = array('Qiniu_Plugin', 'attachmentHandle'); + + // 添加文章内容输出时的EXIF信息显示 + Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = array('Qiniu_Plugin', 'parseContent'); + Typecho_Plugin::factory('Widget_Abstract_Contents')->excerptEx = array('Qiniu_Plugin', 'parseContent'); + + // 使用安全的CSS加载方式 + Typecho_Plugin::factory('Widget_Archive')->footer = array('Qiniu_Plugin', 'footer'); + + return _t('插件已激活,请先配置七牛云信息!'); + } + + // 禁用插件 + public static function deactivate() + { + return _t('插件已禁用'); + } + + // 插件配置面板 + public static function config(Typecho_Widget_Helper_Form $form) + { + $bucket = new Typecho_Widget_Helper_Form_Element_Text('bucket', null, null, _t('空间名称:'), _t('七牛云存储空间名称')); + $bucket->addRule('required', _t('"空间名称"不能为空!')); + $form->addInput($bucket); + + $accesskey = new Typecho_Widget_Helper_Form_Element_Text('accesskey', null, null, _t('AccessKey:'), _t('从七牛云控制台获取')); + $form->addInput($accesskey->addRule('required', _t('AccessKey不能为空!'))); + + $secretkey = new Typecho_Widget_Helper_Form_Element_Text('secretkey', null, null, _t('SecretKey:'), _t('从七牛云控制台获取')); + $form->addInput($secretkey->addRule('required', _t('SecretKey不能为空!'))); + + $domain = new Typecho_Widget_Helper_Form_Element_Text('domain', null, 'https://', _t('绑定域名:'), _t('空间绑定的域名,如:https://cdn.example.com')); + $form->addInput($domain->addRule('required', _t('请填写空间绑定的域名!'))->addRule('url', _t('您输入的域名格式错误!'))); + + $savepath = new Typecho_Widget_Helper_Form_Element_Text('savepath', null, 'typecho/{year}/{month}/', _t('保存路径前缀'), _t('可使用变量:{year}, {month}, {day}, {random}')); + $form->addInput($savepath); + + // WebP转换开关 + $webp = new Typecho_Widget_Helper_Form_Element_Radio('webp', + array('0' => _t('关闭'), '1' => _t('开启')), + '0', + _t('WebP自动转换:'), + _t('开启后上传的JPEG/PNG图片将自动转换为WebP格式')); + $form->addInput($webp); + + // 图片质量设置 + $quality = new Typecho_Widget_Helper_Form_Element_Text('quality', null, '85', _t('图片质量:'), + _t('设置图片压缩质量(1-100),仅对JPEG/PNG/WEBP格式有效。85为推荐值')); + $quality->addRule('required', _t('图片质量不能为空!')) + ->addRule('isInteger', _t('必须输入数字!')) + ->addRule('range', _t('请输入1-100之间的数字!'), array(1, 100)); + $form->addInput($quality); + + // EXIF信息开关 + $exif = new Typecho_Widget_Helper_Form_Element_Radio('exif', + array('0' => _t('关闭'), '1' => _t('开启')), + '0', + _t('EXIF信息显示:'), + _t('开启后文章图片悬停时会显示拍摄信息(相机型号、光圈、快门等)')); + $form->addInput($exif); + } + + // 个人用户配置面板 + public static function personalConfig(Typecho_Widget_Helper_Form $form) + { + } + + // 获得插件配置信息 + public static function getConfig() + { + return Typecho_Widget::widget('Widget_Options')->plugin('Qiniu'); + } + + // 安全的CSS加载方式 + public static function footer() + { + $option = self::getConfig(); + if ($option->exif && !self::$_cssLoaded) { + // 只在文章页面加载CSS + $widget = Typecho_Widget::widget('Widget_Archive'); + if ($widget->is('single')) { + echo ''; + self::$_cssLoaded = true; + } + } + } + + // 输出CSS内容 + private static function echoCss() + { + echo '.qiniu-exif-container { + display: inline-block; + position: relative; + max-width: 100%; +} +.qiniu-exif-info { + position: absolute; + top: 0; + left: 0; + right: 0; + background: rgba(0, 0, 0, 0.85); + color: white; + padding: 8px 10px; + font-size: 12px; + line-height: 1.4; + opacity: 0; + visibility: hidden; + transition: opacity 0.3s ease, visibility 0.3s ease; + z-index: 9999; + border-radius: 4px; + box-shadow: 0 2px 8px rgba(0,0,0,0.2); + pointer-events: none; +} +.qiniu-exif-container:hover .qiniu-exif-info { + opacity: 1; + visibility: visible; +} +.qiniu-exif-info div { + margin: 3px 0; +} +.qiniu-exif-info strong { + font-weight: 600; + color: #fff; +}'; + } + + /** + * 解析文章内容,为图片添加EXIF容器 + */ + public static function parseContent($content, $widget, $lastResult) + { + $content = $lastResult ? $lastResult : $content; + $option = self::getConfig(); + + if (!$option->exif || !$widget->is('single')) { + return $content; + } + + $pattern = '/]*src=["\']([^"\']+)["\'][^>]*>/i'; + return preg_replace_callback($pattern, function($matches) { + $imgTag = $matches[0]; + $src = $matches[1]; + + $option = self::getConfig(); + $domain = rtrim($option->domain, '/'); + + // 检查是否是七牛云的图片 + if (strpos($src, $domain) === false) { + return $imgTag; + } + + // 从URL中提取文件路径 + $path = str_replace($domain, '', $src); + $path = ltrim(parse_url($path, PHP_URL_PATH), '/'); + + // 去除图片处理参数 + if (strpos($path, '?') !== false) { + $path = substr($path, 0, strpos($path, '?')); + } + + // 从数据库获取EXIF信息 + $db = Typecho_Db::get(); + $row = $db->fetchRow($db->select()->from('table.contents') + ->where('type = ?', 'attachment') + ->where('text LIKE ?', '%"path":"' . $path . '"%') + ->limit(1)); + + if ($row) { + $attachment = unserialize($row['text']); + + if (isset($attachment['exif']) && !empty($attachment['exif'])) { + $exifData = $attachment['exif']; + + // 生成简化的EXIF信息HTML + $exifHtml = '
'; + + if (!empty($exifData['camera'])) { + $exifHtml .= '
' . htmlspecialchars($exifData['camera']) . '
'; + } + + $details = array(); + if (!empty($exifData['exposure'])) { + $details[] = '快门:' . htmlspecialchars($exifData['exposure']); + } + if (!empty($exifData['aperture'])) { + $details[] = '光圈:f/' . htmlspecialchars($exifData['aperture']); + } + if (!empty($exifData['iso'])) { + $details[] = 'ISO:' . htmlspecialchars($exifData['iso']); + } + if (!empty($exifData['focal_length'])) { + $details[] = '焦距:' . htmlspecialchars($exifData['focal_length']) . 'mm'; + } + + if (!empty($details)) { + $exifHtml .= '
' . implode(' ', $details) . '
'; + } + + $exifHtml .= '
'; + + return '
' . $imgTag . $exifHtml . '
'; + } + } + + return $imgTag; + }, $content); + } + + /** + * 提取EXIF信息 + */ + private static function extractExif($filePath) + { + if (!function_exists('exif_read_data')) { + return array(); + } + + $exif = @exif_read_data($filePath); + if (!$exif) { + return array(); + } + + $result = array(); + + // 相机型号 + if (!empty($exif['Make']) || !empty($exif['Model'])) { + $make = !empty($exif['Make']) ? trim($exif['Make']) : ''; + $model = !empty($exif['Model']) ? trim($exif['Model']) : ''; + $result['camera'] = trim($make . ' ' . $model); + } + + // 曝光时间 + if (!empty($exif['ExposureTime'])) { + $result['exposure'] = $exif['ExposureTime']; + } + + // 光圈值 + if (!empty($exif['FNumber'])) { + $fnumber = is_array($exif['FNumber']) ? $exif['FNumber'][0] / $exif['FNumber'][1] : $exif['FNumber']; + $result['aperture'] = number_format($fnumber, 1); + } + + // ISO + if (!empty($exif['ISOSpeedRatings'])) { + $result['iso'] = $exif['ISOSpeedRatings']; + } + + // 焦距 + if (!empty($exif['FocalLength'])) { + if (is_array($exif['FocalLength'])) { + $focal = $exif['FocalLength'][0] / $exif['FocalLength'][1]; + } else { + $focal = $exif['FocalLength']; + } + $result['focal_length'] = number_format($focal, 1); + } + + // 拍摄时间 + if (!empty($exif['DateTimeOriginal'])) { + $result['date'] = date('Y-m-d H:i', strtotime($exif['DateTimeOriginal'])); + } + + return $result; + } + + /** + * 检测是否支持WebP转换 + */ + private static function canConvertWebp() + { + if (!extension_loaded('gd')) { + return false; + } + + $gdInfo = gd_info(); + return isset($gdInfo['WebP Support']) && $gdInfo['WebP Support']; + } + + /** + * 压缩图片并转换格式 + */ + private static function compressAndConvert($sourcePath, $targetExt, $quality) + { + $imageInfo = @getimagesize($sourcePath); + if (!$imageInfo) { + return $sourcePath; + } + + $mime = $imageInfo['mime']; + + // 创建图像资源 + switch ($mime) { + case 'image/jpeg': + $image = imagecreatefromjpeg($sourcePath); + break; + case 'image/png': + $image = imagecreatefrompng($sourcePath); + imagepalettetotruecolor($image); + imagealphablending($image, false); + imagesavealpha($image, true); + break; + case 'image/gif': + $image = imagecreatefromgif($sourcePath); + break; + default: + return $sourcePath; + } + + if (!$image) { + return $sourcePath; + } + + $tempFile = tempnam(sys_get_temp_dir(), 'img_') . '.' . $targetExt; + + $success = false; + switch ($targetExt) { + case 'jpg': + case 'jpeg': + $success = imagejpeg($image, $tempFile, $quality); + break; + case 'png': + $pngQuality = 9 - round(($quality / 100) * 9); + $success = imagepng($image, $tempFile, $pngQuality); + break; + case 'webp': + if (self::canConvertWebp()) { + $success = imagewebp($image, $tempFile, $quality); + } + break; + } + + imagedestroy($image); + + if ($success && file_exists($tempFile)) { + return $tempFile; + } + + return $sourcePath; + } + + /** + * 使用七牛基本图片处理 + */ + private static function applyQiniuStyle($url, $option) + { + $pathInfo = pathinfo($url); + $currentExt = isset($pathInfo['extension']) ? strtolower($pathInfo['extension']) : ''; + + $needQuality = $option->quality && $option->quality != 85; + $needWebP = $option->webp && $currentExt != 'webp'; + + if (!$needQuality && !$needWebP) { + return $url; + } + + $params = array(); + + if ($needQuality) { + $params[] = 'q/' . intval($option->quality); + } + + if ($needWebP) { + $params[] = 'format/webp'; + } + + if (!empty($params)) { + $separator = (strpos($url, '?') === false) ? '?' : '&'; + $url .= $separator . 'imageView2/2/' . implode('/', $params); + } + + return $url; + } + + /** + * 删除文件 + */ + public static function deleteFile($filepath) + { + try { + $option = self::getConfig(); + $auth = new Auth($option->accesskey, $option->secretkey); + $bucketMgr = new BucketManager($auth); + + $err = $bucketMgr->delete($option->bucket, $filepath); + + return $err === null; + } catch (Exception $e) { + return false; + } + } + + /** + * 上传文件到七牛云 - 修复中文文件名问题 + */ + public static function uploadFile($file, $content = null) + { + error_reporting(0); + + if (empty($file['name']) || !isset($file['tmp_name'])) { + return array('error' => 1, 'message' => '上传文件无效'); + } + + // 获取原始文件名 + $originalName = basename($file['name']); + + // 使用pathinfo正确处理中文字符 + $pathInfo = pathinfo($originalName); + $originalExt = isset($pathInfo['extension']) ? strtolower($pathInfo['extension']) : ''; + $baseName = isset($pathInfo['filename']) ? $pathInfo['filename'] : ''; + + // 校验扩展名 + if (!Widget_Upload::checkFileType($originalExt)) { + return array('error' => 1, 'message' => '不允许上传此类型文件'); + } + + $option = self::getConfig(); + + if (empty($option->bucket) || empty($option->accesskey) || empty($option->secretkey) || empty($option->domain)) { + return array('error' => 1, 'message' => '请先正确配置七牛云插件'); + } + + $date = new Typecho_Date(Typecho_Widget::widget('Widget_Options')->gmtTime); + + // 提取EXIF信息 + $exifData = array(); + if ($option->exif && in_array($originalExt, array('jpg', 'jpeg'))) { + $exifData = self::extractExif($file['tmp_name']); + } + + // 处理图片压缩和转换 + $tempFile = null; + $uploadPath = $file['tmp_name']; + $finalExt = $originalExt; + + $supportedImages = array('jpg', 'jpeg', 'png', 'gif'); + if (in_array($originalExt, $supportedImages)) { + $quality = isset($option->quality) ? intval($option->quality) : 85; + $quality = max(1, min(100, $quality)); + + $targetExt = $originalExt; + if ($option->webp && self::canConvertWebp() && $originalExt != 'gif') { + $targetExt = 'webp'; + } + + if ($targetExt != $originalExt || $quality != 85) { + $processedPath = self::compressAndConvert($file['tmp_name'], $targetExt, $quality); + + if ($processedPath != $file['tmp_name']) { + $uploadPath = $processedPath; + $finalExt = $targetExt; + $tempFile = $processedPath; + } + } + } + + // 生成存储路径 - 保持原始文件名,只替换文件系统不允许的字符 + // 处理文件名,保留中文字符,只替换特殊字符 + $safeName = $baseName; + + // 替换文件系统不允许的字符,但保留中文字符 + $safeName = preg_replace('/[<>:"\/\\|?*]/', '_', $safeName); + // 移除首尾空格 + $safeName = trim($safeName); + // 如果名称为空,使用时间戳 + if (empty($safeName)) { + $safeName = 'image_' . time(); + } + + if (isset($content)) { + $filePath = $content['attachment']->path; + self::deleteFile($filePath); + } else { + $savepath = preg_replace(array('/\{year\}/', '/\{month\}/', '/\{day\}/', '/\{random\}/'), + array($date->year, $date->month, $date->day, uniqid()), + $option->savepath); + $filePath = rtrim($savepath, '/') . '/' . $safeName . '.' . $finalExt; + } + + if (!file_exists($uploadPath)) { + return array('error' => 1, 'message' => '上传文件不存在'); + } + + try { + $upManager = new UploadManager(); + $auth = new Auth($option->accesskey, $option->secretkey); + $token = $auth->uploadToken($option->bucket); + + // 七牛云SDK会自动处理文件名编码 + list($ret, $error) = $upManager->putFile($token, $filePath, $uploadPath); + + if ($tempFile && file_exists($tempFile) && $tempFile != $file['tmp_name']) { + @unlink($tempFile); + } + + if ($error == null) { + $rawUrl = Typecho_Common::url($filePath, $option->domain); + $processedUrl = self::applyQiniuStyle($rawUrl, $option); + + $fileSize = @filesize($uploadPath); + + $result = array( + 'name' => $originalName, // 使用原始文件名 + 'path' => $filePath, + 'size' => $fileSize ? (int)$fileSize : 0, + 'type' => $finalExt, + 'mime' => $finalExt == 'webp' ? 'image/webp' : Typecho_Common::mimeContentType($uploadPath), + 'url' => $processedUrl + ); + + if (!empty($exifData)) { + $result['exif'] = $exifData; + } + + return $result; + } else { + return array('error' => 1, 'message' => '七牛云上传失败: ' . $error->message()); + } + } catch (Exception $e) { + if ($tempFile && file_exists($tempFile) && $tempFile != $file['tmp_name']) { + @unlink($tempFile); + } + return array('error' => 1, 'message' => '上传异常: ' . $e->getMessage()); + } + } + + // 上传文件处理函数 + public static function uploadHandle($file) + { + return self::uploadFile($file); + } + + // 修改文件处理函数 + public static function modifyHandle($content, $file) + { + return self::uploadFile($file, $content); + } + + // 删除文件处理函数 + public static function deleteHandle(array $content) + { + if (isset($content['attachment'])) { + self::deleteFile($content['attachment']->path); + } + } + + // 获取实际文件绝对访问路径 + public static function attachmentHandle(array $content) + { + $option = self::getConfig(); + if (isset($content['attachment'])) { + $rawUrl = Typecho_Common::url($content['attachment']->path, $option->domain); + return self::applyQiniuStyle($rawUrl, $option); + } + return ''; + } +} \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..97d16ff --- /dev/null +++ b/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "qiniu/php-sdk": "^7.14" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..e20d4a2 --- /dev/null +++ b/composer.lock @@ -0,0 +1,142 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "e53b7aa650906cf4c75020ac18b97155", + "packages": [ + { + "name": "myclabs/php-enum", + "version": "1.8.5", + "source": { + "type": "git", + "url": "https://github.com/myclabs/php-enum.git", + "reference": "e7be26966b7398204a234f8673fdad5ac6277802" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/e7be26966b7398204a234f8673fdad5ac6277802", + "reference": "e7be26966b7398204a234f8673fdad5ac6277802", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "1.*", + "vimeo/psalm": "^4.6.2 || ^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "MyCLabs\\Enum\\": "src/" + }, + "classmap": [ + "stubs/Stringable.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP Enum contributors", + "homepage": "https://github.com/myclabs/php-enum/graphs/contributors" + } + ], + "description": "PHP Enum implementation", + "homepage": "https://github.com/myclabs/php-enum", + "keywords": [ + "enum" + ], + "support": { + "issues": "https://github.com/myclabs/php-enum/issues", + "source": "https://github.com/myclabs/php-enum/tree/1.8.5" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum", + "type": "tidelift" + } + ], + "time": "2025-01-14T11:49:03+00:00" + }, + { + "name": "qiniu/php-sdk", + "version": "v7.14.0", + "source": { + "type": "git", + "url": "https://github.com/qiniu/php-sdk.git", + "reference": "ee752ffa7263ce99fca0bd7340cf13c486a3516c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/qiniu/php-sdk/zipball/ee752ffa7263ce99fca0bd7340cf13c486a3516c", + "reference": "ee752ffa7263ce99fca0bd7340cf13c486a3516c", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-xml": "*", + "myclabs/php-enum": "~1.5.2 || ~1.6.6 || ~1.7.7 || ~1.8.4", + "php": ">=5.3.3" + }, + "require-dev": { + "paragonie/random_compat": ">=2", + "phpunit/phpunit": "^4.8 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4", + "squizlabs/php_codesniffer": "^2.3 || ~3.6" + }, + "type": "library", + "autoload": { + "files": [ + "src/Qiniu/functions.php", + "src/Qiniu/Http/Middleware/Middleware.php" + ], + "psr-4": { + "Qiniu\\": "src/Qiniu" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Qiniu", + "email": "sdk@qiniu.com", + "homepage": "http://www.qiniu.com" + } + ], + "description": "Qiniu Resource (Cloud) Storage SDK for PHP", + "homepage": "http://developer.qiniu.com/", + "keywords": [ + "cloud", + "qiniu", + "sdk", + "storage" + ], + "support": { + "issues": "https://github.com/qiniu/php-sdk/issues", + "source": "https://github.com/qiniu/php-sdk/tree/v7.14.0" + }, + "time": "2024-10-25T08:39:01+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.0.0" +} diff --git a/php-sdk/.github/workflows/test-ci.yml b/php-sdk/.github/workflows/test-ci.yml new file mode 100644 index 0000000..00f964e --- /dev/null +++ b/php-sdk/.github/workflows/test-ci.yml @@ -0,0 +1,71 @@ +name: PHP CI with Composer + +on: [push, pull_request] + +jobs: + build: + strategy: + fail-fast: false + matrix: + php-versions: ['5.3', '5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup php for mock server + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: '1.21.x' + + - name: Setup build-in server + run: | + nohup php -S localhost:9000 -t ./tests/mock-server/ > phpd.log 2>&1 & + echo $! > mock-server.pid + + cd tests/socks5-server/ + nohup go run main.go > ../../socks5.log 2>&1 & + echo $! > ../../socks-server.pid + + - name: Setup php + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + + - name: Install dependencies + run: | + composer self-update + composer install --no-interaction --prefer-source --dev + + - name: Run cases + run: | + ./vendor/bin/phpcs --standard=PSR2 src + ./vendor/bin/phpcs --standard=PSR2 examples + ./vendor/bin/phpcs --standard=PSR2 tests + ./vendor/bin/phpunit --coverage-clover=coverage.xml + cat mock-server.pid | xargs kill + cat socks-server.pid | xargs kill + + env: + QINIU_ACCESS_KEY: ${{ secrets.QINIU_ACCESS_KEY }} + QINIU_SECRET_KEY: ${{ secrets.QINIU_SECRET_KEY }} + QINIU_TEST_BUCKET: ${{ secrets.QINIU_TEST_BUCKET }} + QINIU_TEST_DOMAIN: ${{ secrets.QINIU_TEST_DOMAIN }} + + - name: Print mock server log + if: ${{ failure() }} + run: | + cat phpd.log + + - name: Print socks5 server log + if: ${{ failure() }} + run: | + cat socks5.log + + - name: After_success + run: bash <(curl -s https://codecov.io/bash) diff --git a/php-sdk/.github/workflows/version-check.yml b/php-sdk/.github/workflows/version-check.yml new file mode 100644 index 0000000..983a98f --- /dev/null +++ b/php-sdk/.github/workflows/version-check.yml @@ -0,0 +1,19 @@ +name: PHP SDK Version Check +on: + push: + tags: + - "v[0-9]+.[0-9]+.[0-9]+" +jobs: + linux: + name: Version Check + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Set env + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV + - name: Check + run: | + set -e + grep -qF "## ${RELEASE_VERSION}" CHANGELOG.md + grep -qF "const SDK_VER = '${RELEASE_VERSION}';" src/Qiniu/Config.php diff --git a/php-sdk/.gitignore b/php-sdk/.gitignore new file mode 100644 index 0000000..4c842c8 --- /dev/null +++ b/php-sdk/.gitignore @@ -0,0 +1,12 @@ +*.phar +*.zip +build/artifacts +phpunit.xml +phpunit.functional.xml +.DS_Store +.swp +.build +composer.lock +vendor +src/package.xml +.idea/ diff --git a/php-sdk/.scrutinizer.yml b/php-sdk/.scrutinizer.yml new file mode 100644 index 0000000..6a2d0d8 --- /dev/null +++ b/php-sdk/.scrutinizer.yml @@ -0,0 +1,42 @@ +filter: + excluded_paths: [tests/*] +checks: + php: + code_rating: true + remove_extra_empty_lines: true + remove_php_closing_tag: true + remove_trailing_whitespace: true + fix_use_statements: + remove_unused: true + preserve_multiple: false + preserve_blanklines: true + order_alphabetically: true + fix_php_opening_tag: true + fix_linefeed: true + fix_line_ending: true + fix_identation_4spaces: true + fix_doc_comments: true +tools: + external_code_coverage: + timeout: 1200 + runs: 3 + php_analyzer: true + php_code_coverage: false + php_code_sniffer: + config: + standard: PSR2 + filter: + paths: ['src'] + php_loc: + enabled: true + excluded_dirs: [vendor, tests] + php_cpd: + enabled: true + excluded_dirs: [vendor, tests] +build: + nodes: + analysis: + tests: + override: + - php-scrutinizer-run + diff --git a/php-sdk/CHANGELOG.md b/php-sdk/CHANGELOG.md new file mode 100644 index 0000000..6f8da5d --- /dev/null +++ b/php-sdk/CHANGELOG.md @@ -0,0 +1,196 @@ +# Changelog + +## 7.14.0 (2024-10-16) +* 对象存储,持久化处理支持工作流模版 + +## 7.13.0 (2024-09-05) +* 对象存储,验证回调方法新增支持 Qiniu 签名 +* 对象存储,调整查询空间区域域名顺序与默认空间管理域名 +* 支持闲时任务配置 + +## 7.12.1 (2024-02-21) +* 对象存储,添加上传策略部分字段 + +## 7.12.0 (2023-12-11) +* 对象存储,支持归档直读存储 +* 对象存储,批量操作支持自动查询 rs 服务域名 + +## 7.11.0 (2023-09-05) +* 支持代理 + +## 7.10.1 (2023-08-04) +* 修复部分 API 调用中间件合并失败(#417) + +## 7.10.0 (2023-06-20) +* 对象存储,新增请求中间件逻辑,方便拓展请求逻辑 +* 对象存储,新增备用 UC 域名用于查询区域域名 +* 对象存储,修复分片上传初始化失败无法快速失败 +* 对象存储,移除首尔区域 + +## 7.9.0 (2023-03-31) +* 对象存储,修复无法对 key 为空字符串的对象进行操作 +* 修复 301 重定向无法正确获取 header 信息 +* 对象存储,新增查询区域域名过期时间 +* 对象存储,更新获取区域域名的接口 +* 对象存储,更新查询 bucket 域名为 uc 服务 +* 对象存储,新增 uc 服务可配置 + +## 7.8.0 (2022-10-25) +* 移除不推荐域名,并增加区域亚太-首尔和华东-浙江2 +* 对象存储,修复断点上传的文件内容不正确 +* 对象存储,优化分片上传 ctx 超时检测 + +## 7.7.0 (2022-09-02) +* 对象存储,新增支持设置文件级别生命周期 setObjectLifecycle API +* 对象存储,内置增加七牛新建存储区域域名信息 +* 修复当前已知问题 + +## 7.6.0 (2022-06-08) +* 对象存储,管理类 API 发送请求时增加 [X-Qiniu-Date](https://developer.qiniu.com/kodo/3924/common-request-headers) (生成请求的时间) header + + +## 7.5.0 (2022-04-18) +* 对象存储,新增支持 [深度归档存储类型](https://developer.qiniu.com/kodo/3956/kodo-category#deep_archive) + +## 7.4.3 (2022-04-01) +* 优化签名算法逻辑 + +## 7.4.2(2022-03-01) +* 修复已知关于请求 Header 处理不当问题,比如没有处理为大小写不敏感等问题 + +## 7.4.1(2021-09-24) +* 修复了 分片上传 v2 已知问题,明确给出了参数不合理情况下对应的错误提示信息 + +## 7.4.0 (2021-07-19) +* 【对象存储】支持 [分片上传 v2](https://developer.qiniu.com/kodo/7458/multipartupload) 和 断点续传,使用方式见 [开发者文档](https://developer.qiniu.com/kodo/1241/php#resume-upload-file) + +## 7.3.0 (2020-09-24) +### 新增 +* 【对象存储】增加异步抓取方法与demo +* 【融合cdn】增加查询CDN刷新记录、查询CDN预取记录方法与demo +* 【云短信】增加查询短信发送记录的方法 +* 【实时音视频】增加rtc停止房间的合流转推方法 +* 【内容审核】增加图片审核、视频审核方法与demo + +### 修复 +* 【对象存储】修复签算 token 时上传策略中的 forceSaveKey 字段不生效的问题 +* 【对象存储】修复更新空间事件通知规则方法 + +### 优化 +* 【对象存储】创建空间迁移到mkbucketv3 api +* 优化对 http2 返回头的判断 +* 优化 demo 中的文档注释说明 +* docs 目录下的 rtc demo 移动至 examples/rtc 目录下 +* docs 目录下的 sms demo 移动至 examples/sms 目录下 + +## 7.2.10 (2019-10-28) +* 去除云短信类类型指定 +* 修改不传文件名时存在表单上传错误的情况 + +## 7.2.9 (2019-07-09) +* 添加空间管理、云短信接口 +* 去除无效参数 + +## 7.2.7 (2018-11-06) +* 添加 QVM 内网上传到 KODO 的 zone 设置 + +## 7.2.6 (2018-05-18) +* 修复rs,rsf在不同机房默认的https域名 + +## 7.2.5 (2018-05-10) +* 修复表单上传中多余的参数checkCrc导致的fname错位问题 + +## 7.2.4 (2018-05-09) +### 增加 +* 连麦功能 + +## 7.2.3 (2018-01-20) +### 增加 +* 新加坡机房 +### 修正 +* 获取域名的入口域名 +* http回复头部兼容大小写 + +## 7.2.2 (2017-11-06) +### 增加 +* Qiniu算法的鉴权方法 + +## 7.1.4 (2017-06-21) +### 增加 +* cdn 文件/目录 刷新 +* cdn 获取 流量/带宽 +* cdn 获取域名的访问日志列表 +* cdn 对资源链接进行时间戳防盗链签名 + +## 7.1.3 (2016-11-18) +### 增加 +* move, copy操作增加force参数 + +## 7.1.2 (2016-11-12) +### 修正 +* 明确抛出获取各区域域名失败时的报错 + +## 7.1.1 (2016-11-02) +### 修正 +* 多区域配置文件存储目录从home修改到tmp目录 + + +## 7.1.0 (2016-10-22) +### 增加 +* 多存储区域的支持 + +## 7.0.8 (2016-07-19) +### 增加 +* demo +* https url 支持 +* deleteAfterDays 策略 +* 添加图片处理链接统一拼接方法 by @SherlockRen + +## 7.0.7 (2016-01-12) +### 修正 +* PersistentFop参数pipeline和notify_url失效 +* resume 模式 close file inputstream + +## 7.0.6 (2015-12-05) +### 修正 +* php7.0 Json 对空字符串解析单元测试报错 +* 开启安全模式或者设置可操作目录树时,设置CURLOPT_FOLLOWLOCATION报错, by @twocabbages +* fetch 支持不指定key, by @sinkcup + +## 7.0.5 (2015-10-29) +### 增加 +* 增加上传策略最小文件大小限制 fsizeMin +* 增加常见examples + +## 7.0.4 (2015-07-23) +### 修正 +* 一些地方的严格比较检查 +* resumeupload 备用地址失效 + +## 7.0.3 (2015-07-10) +### 修改 +* 多zone 支持 + +## 7.0.2 (2015-04-18) +### 修改 +* fetch 接口返回内容调整 +* pfop 接口调整 + +###修正 +* exception 类调用 + +## 7.0.1 (2015-03-27) +### 增加 +* 增加代码注释 + +## 7.0.0 (2015-02-03) + +### 增加 +* 简化上传接口 +* 自动选择断点续上传还是直传 +* 重构代码,接口和内部结构更清晰 +* 改变mime +* 代码覆盖度报告 +* policy改为array, 便于灵活增加,并加入过期字段检查 +* 文件列表支持目录形式 +* 利用元编程方式支持 fop 和 pfop diff --git a/php-sdk/CONTRIBUTING.md b/php-sdk/CONTRIBUTING.md new file mode 100644 index 0000000..0466bf9 --- /dev/null +++ b/php-sdk/CONTRIBUTING.md @@ -0,0 +1,30 @@ +# 贡献代码指南 + +我们非常欢迎大家来贡献代码,我们会向贡献者致以最诚挚的敬意。 + +一般可以通过在Github上提交[Pull Request](https://github.com/qiniu/php-sdk)来贡献代码。 + +## Pull Request要求 + +- **[PSR-2 编码风格标准](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** 。要通过项目中的code sniffer检查。 + +- **代码格式** 提交前 请按 ./vendor/bin/phpcbf --standard=PSR2 进行格式化。 + +- **必须添加测试!** - 如果没有测试(单元测试、集成测试都可以),那么提交的补丁是不会通过的。 + +- **记得更新文档** - 保证`README.md`以及其他相关文档及时更新,和代码的变更保持一致性。 + +- **考虑我们的发布周期** - 我们的版本号会服从[SemVer v2.0.0](http://semver.org/),我们绝对不会随意变更对外的API。 + +- **创建feature分支** - 最好不要从你的master分支提交 pull request。 + +- **一个feature提交一个pull请求** - 如果你的代码变更了多个操作,那就提交多个pull请求吧。 + +- **清晰的commit历史** - 保证你的pull请求的每次commit操作都是有意义的。如果你开发中需要执行多次的即时commit操作,那么请把它们放到一起再提交pull请求。 + +## 运行测试 + +``` bash +./vendor/bin/phpunit tests/Qiniu/Tests/ + +``` diff --git a/php-sdk/LICENSE b/php-sdk/LICENSE new file mode 100644 index 0000000..ba646be --- /dev/null +++ b/php-sdk/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 Qiniu, Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/php-sdk/README.md b/php-sdk/README.md new file mode 100644 index 0000000..784d735 --- /dev/null +++ b/php-sdk/README.md @@ -0,0 +1,76 @@ +# Qiniu Cloud SDK for PHP +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE) +[![Build Status](https://travis-ci.org/qiniu/php-sdk.svg)](https://travis-ci.org/qiniu/php-sdk) +[![GitHub release](https://img.shields.io/github/v/tag/qiniu/php-sdk.svg?label=release)](https://github.com/qiniu/php-sdk/releases) +[![Latest Stable Version](https://img.shields.io/packagist/v/qiniu/php-sdk.svg)](https://packagist.org/packages/qiniu/php-sdk) +[![Total Downloads](https://img.shields.io/packagist/dt/qiniu/php-sdk.svg)](https://packagist.org/packages/qiniu/php-sdk) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/qiniu/php-sdk/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/qiniu/php-sdk/?branch=master) +[![Coverage Status](https://codecov.io/gh/qiniu/php-sdk/branch/master/graph/badge.svg)](https://codecov.io/gh/qiniu/php-sdk) +[![Join Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/qiniu/php-sdk?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![@qiniu on weibo](http://img.shields.io/badge/weibo-%40qiniutek-blue.svg)](http://weibo.com/qiniutek) + + +## 安装 + +推荐使用 `composer` 进行安装。可以使用 composer.json 声明依赖,或者运行下面的命令。SDK 包已经放到这里 [`qiniu/php-sdk`][install-packagist] 。 + +```bash +$ composer require qiniu/php-sdk +``` + +## 运行环境 + +| Qiniu SDK版本 | PHP 版本 | +|:--------------------:|:-----------------------------------------------:| +| 7.x | cURL extension, 5.3 - 5.6, 7.0 - 7.4, 8.0-8.1 | +| 6.x | cURL extension, 5.2 - 5.6 | + +## 使用方法 + +### 上传 +```php +use Qiniu\Storage\UploadManager; +use Qiniu\Auth; +... + $uploadMgr = new UploadManager(); + $auth = new Auth($accessKey, $secretKey); + $token = $auth->uploadToken($bucket); + list($ret, $error) = $uploadMgr->putFile($token, 'key', 'filePath'); +... +``` + +## 测试 + +``` bash +$ ./vendor/bin/phpunit tests/Qiniu/Tests/ +``` + +## 常见问题 + +- `$error` 保留了请求响应的信息,失败情况下 `ret` 为 `none`, 将 `$error` 可以打印出来,提交给我们。 +- API 的使用 demo 可以参考 [examples](https://github.com/qiniu/php-sdk/tree/master/examples)。 + +## 代码贡献 + +详情参考[代码提交指南](https://github.com/qiniu/php-sdk/blob/master/CONTRIBUTING.md)。 + +## 贡献记录 + +- [所有贡献者](https://github.com/qiniu/php-sdk/contributors) + +## 联系我们 + +- 如果需要帮助,请提交工单(在portal右侧点击咨询和建议提交工单,或者直接向 support@qiniu.com 发送邮件) +- 如果有什么问题,可以到问答社区提问,[问答社区](https://qiniu.segmentfault.com/) +- 更详细的文档,见[官方文档站](https://developer.qiniu.com/) +- 如果发现了 bug, 欢迎提交 [issue](https://github.com/qiniu/php-sdk/issues) +- 如果有功能需求,欢迎提交 [issue](https://github.com/qiniu/php-sdk/issues) +- 如果要提交代码,欢迎提交 pull request +- 欢迎关注我们的[微信](https://www.qiniu.com/#weixin) [微博](https://weibo.com/qiniutek),及时获取动态信息。 + +## 代码许可 + +The MIT License (MIT).详情见 [License文件](https://github.com/qiniu/php-sdk/blob/master/LICENSE). + +[packagist]: http://packagist.org +[install-packagist]: https://packagist.org/packages/qiniu/php-sdk diff --git a/php-sdk/autoload.php b/php-sdk/autoload.php new file mode 100644 index 0000000..9efddd7 --- /dev/null +++ b/php-sdk/autoload.php @@ -0,0 +1,19 @@ +=5.3.3", + "ext-xml": "*", + "ext-curl": "*", + "myclabs/php-enum": "~1.5.2 || ~1.6.6 || ~1.7.7 || ~1.8.4" + }, + "require-dev": { + "paragonie/random_compat": ">=2", + "phpunit/phpunit": "^4.8 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4", + "squizlabs/php_codesniffer": "^2.3 || ~3.6" + }, + "autoload": { + "psr-4": { + "Qiniu\\": "src/Qiniu" + }, + "files": [ + "src/Qiniu/functions.php", + "src/Qiniu/Http/Middleware/Middleware.php" + ] + } +} diff --git a/php-sdk/examples/README.md b/php-sdk/examples/README.md new file mode 100644 index 0000000..b7b4f98 --- /dev/null +++ b/php-sdk/examples/README.md @@ -0,0 +1,10 @@ +# examples + +这些 examples 旨在帮助你快速了解使用七牛的 SDK。这些 demo 都是可以直接运行的, 但是在运行之前需要填上您自己的参数。 + +比如: + +* `$bucket` 需要填上您想操作的 [bucket名字](https://portal.qiniu.com/kodo/bucket)。 +* `$accessKey` 和 `$secretKey` 可以在我们的[管理后台](https://portal.qiniu.com/user/key)找到。 +* 在进行`视频转码`, `压缩文件`等异步操作时 需要使用到的队列名称也可以在我们[管理后台](https://portal.qiniu.com/dora/media-gate/pipeline)新建。 + diff --git a/php-sdk/examples/bucket_lifecycleRule.php b/php-sdk/examples/bucket_lifecycleRule.php new file mode 100644 index 0000000..f51524c --- /dev/null +++ b/php-sdk/examples/bucket_lifecycleRule.php @@ -0,0 +1,42 @@ +bucketLifecycleRule( + $bucket, + $name, + $prefix, + $delete_after_days, + $to_line_after_days, + $to_archive_after_days, + $to_deep_archive_after_days, + $to_archive_ir_after_days +); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/cdn_get_bandwidth.php b/php-sdk/examples/cdn_get_bandwidth.php new file mode 100644 index 0000000..c9de0e6 --- /dev/null +++ b/php-sdk/examples/cdn_get_bandwidth.php @@ -0,0 +1,41 @@ +getBandwidthData( + $domains, + $startDate, + $endDate, + $granularity +); + +if ($getBandwidthErr != null) { + var_dump($getBandwidthErr); +} else { + echo "get bandwidth data success\n"; + print_r($bandwidthData); +} diff --git a/php-sdk/examples/cdn_get_flux.php b/php-sdk/examples/cdn_get_flux.php new file mode 100644 index 0000000..57df808 --- /dev/null +++ b/php-sdk/examples/cdn_get_flux.php @@ -0,0 +1,35 @@ +getFluxData($domains, $startDate, $endDate, $granularity); +if ($getFluxErr != null) { + var_dump($getFluxErr); +} else { + echo "get flux data success\n"; + print_r($fluxData); +} diff --git a/php-sdk/examples/cdn_get_log_list.php b/php-sdk/examples/cdn_get_log_list.php new file mode 100644 index 0000000..2b3f7dd --- /dev/null +++ b/php-sdk/examples/cdn_get_log_list.php @@ -0,0 +1,31 @@ +getCdnLogList($domains, $logDate); +if ($getLogErr != null) { + var_dump($getLogErr); +} else { + echo "get cdn log list success\n"; + print_r($logListData); +} diff --git a/php-sdk/examples/cdn_get_prefetch_list.php b/php-sdk/examples/cdn_get_prefetch_list.php new file mode 100644 index 0000000..958e5eb --- /dev/null +++ b/php-sdk/examples/cdn_get_prefetch_list.php @@ -0,0 +1,46 @@ +getCdnPrefetchList( + $requestId, + $urls, + $state, + $pageNo, + $pageSize, + $startTime, + $endTime +); +echo "\n====> query prefetch list: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/cdn_get_refresh_list.php b/php-sdk/examples/cdn_get_refresh_list.php new file mode 100644 index 0000000..ad4fca2 --- /dev/null +++ b/php-sdk/examples/cdn_get_refresh_list.php @@ -0,0 +1,48 @@ +getCdnRefreshList( + $requestId, + $isDir, + $urls, + $state, + $pageNo, + $pageSize, + $startTime, + $endTime +); +echo "\n====> query refresh list: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/cdn_refresh_urls_dirs.php b/php-sdk/examples/cdn_refresh_urls_dirs.php new file mode 100644 index 0000000..2140378 --- /dev/null +++ b/php-sdk/examples/cdn_refresh_urls_dirs.php @@ -0,0 +1,59 @@ +refreshUrlsAndDirs($urls, $dirs); +if ($refreshErr != null) { + var_dump($refreshErr); +} else { + echo "refresh request sent\n"; + print_r($refreshResult); +} + +//---------------------------------------- demo2 ---------------------------------------- +// 刷新文件 + +list($refreshResult, $refreshErr) = $cdnManager->refreshUrls($urls); +if ($refreshErr != null) { + var_dump($refreshErr); +} else { + echo "refresh urls request sent\n"; + print_r($refreshResult); +} + +//---------------------------------------- demo3 ---------------------------------------- +// 刷新目录 + +list($refreshResult, $refreshErr) = $cdnManager->refreshDirs($dirs); +if ($refreshErr != null) { + var_dump($refreshErr); +} else { + echo "refresh dirs request sent\n"; + print_r($refreshResult); +} diff --git a/php-sdk/examples/cdn_timestamp_antileech.php b/php-sdk/examples/cdn_timestamp_antileech.php new file mode 100644 index 0000000..f2d7855 --- /dev/null +++ b/php-sdk/examples/cdn_timestamp_antileech.php @@ -0,0 +1,20 @@ +censorImage($body); +echo "\n====> Result is: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/censor_video.php b/php-sdk/examples/censor_video.php new file mode 100644 index 0000000..7ac056f --- /dev/null +++ b/php-sdk/examples/censor_video.php @@ -0,0 +1,52 @@ +censorVideo($body); +echo "\n====> Result is: \n"; +if ($err !== null) { + var_dump($err); +} else { + echo "job_id is: $jobid\n"; +} + +// 查询视频审核结果 +list($ret, $err) = $argusManager->censorStatus($jobid); +echo "\n====> job status: \n"; + +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/delete_bucket.php b/php-sdk/examples/delete_bucket.php new file mode 100644 index 0000000..325a47a --- /dev/null +++ b/php-sdk/examples/delete_bucket.php @@ -0,0 +1,27 @@ +deleteBucket($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/delete_bucketEvent.php b/php-sdk/examples/delete_bucketEvent.php new file mode 100644 index 0000000..7eb744d --- /dev/null +++ b/php-sdk/examples/delete_bucketEvent.php @@ -0,0 +1,28 @@ +deleteBucketEvent($bucket, $name); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/delete_bucketLifecycleRule.php b/php-sdk/examples/delete_bucketLifecycleRule.php new file mode 100644 index 0000000..2146b1b --- /dev/null +++ b/php-sdk/examples/delete_bucketLifecycleRule.php @@ -0,0 +1,27 @@ +deleteBucketLifecycleRule($bucket, $name); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/get_bucketEvents.php b/php-sdk/examples/get_bucketEvents.php new file mode 100644 index 0000000..2379584 --- /dev/null +++ b/php-sdk/examples/get_bucketEvents.php @@ -0,0 +1,26 @@ +getBucketEvents($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/get_bucketLifecycleRules.php b/php-sdk/examples/get_bucketLifecycleRules.php new file mode 100644 index 0000000..a35feed --- /dev/null +++ b/php-sdk/examples/get_bucketLifecycleRules.php @@ -0,0 +1,26 @@ +getBucketLifecycleRules($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/get_bucketList.php b/php-sdk/examples/get_bucketList.php new file mode 100644 index 0000000..6a2f7b0 --- /dev/null +++ b/php-sdk/examples/get_bucketList.php @@ -0,0 +1,26 @@ +listbuckets($region); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/get_bucketQuota.php b/php-sdk/examples/get_bucketQuota.php new file mode 100644 index 0000000..93474b5 --- /dev/null +++ b/php-sdk/examples/get_bucketQuota.php @@ -0,0 +1,26 @@ +getBucketQuota($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/get_bucketinfo.php b/php-sdk/examples/get_bucketinfo.php new file mode 100644 index 0000000..98fd9f7 --- /dev/null +++ b/php-sdk/examples/get_bucketinfo.php @@ -0,0 +1,25 @@ +bucketInfo($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/get_bucketinfos.php b/php-sdk/examples/get_bucketinfos.php new file mode 100644 index 0000000..5eec1d8 --- /dev/null +++ b/php-sdk/examples/get_bucketinfos.php @@ -0,0 +1,26 @@ +bucketInfos($region); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/get_corsRules.php b/php-sdk/examples/get_corsRules.php new file mode 100644 index 0000000..58e28be --- /dev/null +++ b/php-sdk/examples/get_corsRules.php @@ -0,0 +1,26 @@ +getCorsRules($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/image_url_builder.php b/php-sdk/examples/image_url_builder.php new file mode 100644 index 0000000..20e2b00 --- /dev/null +++ b/php-sdk/examples/image_url_builder.php @@ -0,0 +1,74 @@ + + */ +$thumbLink = $imageUrlBuilder->thumbnail($url, 1, 100, 100); + +// 函数方式调用 也可拼接多个操作参数 图片+水印 +$thumbLink2 = \Qiniu\thumbnail($url2, 1, 100, 100); +var_dump($thumbLink, $thumbLink2); + +/** + * 图片水印 + * + * @param string $url 图片链接 + * @param string $image 水印图片链接 + * @param int $dissolve 透明度 [可选] + * @param string $gravity 水印位置 [可选] + * @param int $dx 横轴边距 [可选] + * @param int $dy 纵轴边距 [可选] + * @param int $watermarkScale 自适应原图的短边比例 [可选] + * @link https://developer.qiniu.com/dora/api/1316/image-watermarking-processing-watermark + * @return string + * @author Sherlock Ren + */ +$waterLink = $imageUrlBuilder->waterImg($url, $waterImage); +// 函数调用方法 +//$waterLink = \Qiniu\waterImg($url, $waterImage); +var_dump($waterLink); + +/** + * 文字水印 + * + * @param string $url 图片链接 + * @param string $text 文字 + * @param string $font 文字字体 + * @param string $fontSize 文字字号 + * @param string $fontColor 文字颜色 [可选] + * @param int $dissolve 透明度 [可选] + * @param string $gravity 水印位置 [可选] + * @param int $dx 横轴边距 [可选] + * @param int $dy 纵轴边距 [可选] + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html#text-watermark + * @return string + * @author Sherlock Ren + */ +$textLink = $imageUrlBuilder->waterText($url, '你瞅啥', '微软雅黑', 300); +// 函数调用方法 +// $textLink = \Qiniu\waterText($url, '你瞅啥', '微软雅黑', 300); +var_dump($textLink); diff --git a/php-sdk/examples/persistent_fop_init.php b/php-sdk/examples/persistent_fop_init.php new file mode 100644 index 0000000..baca846 --- /dev/null +++ b/php-sdk/examples/persistent_fop_init.php @@ -0,0 +1,18 @@ +useHTTPS=true; + +// 初始化 +$pfop = new PersistentFop($auth, $config); diff --git a/php-sdk/examples/persistent_fop_status.php b/php-sdk/examples/persistent_fop_status.php new file mode 100644 index 0000000..73e85a3 --- /dev/null +++ b/php-sdk/examples/persistent_fop_status.php @@ -0,0 +1,19 @@ +status($persistentId); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/pfop_mkzip.php b/php-sdk/examples/pfop_mkzip.php new file mode 100644 index 0000000..fb95cc2 --- /dev/null +++ b/php-sdk/examples/pfop_mkzip.php @@ -0,0 +1,58 @@ +execute($bucket, $key, $fops, $pipeline, $notify_url, $force); + +echo "\n====> pfop mkzip result: \n"; +if ($err != null) { + var_dump($err); +} else { + echo "PersistentFop Id: $id\n"; +} + +// 查询转码的进度和状态 +list($ret, $err) = $pfop->status($id); +echo "\n====> pfop mkzip status: \n"; +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/pfop_vframe.php b/php-sdk/examples/pfop_vframe.php new file mode 100644 index 0000000..49fd36d --- /dev/null +++ b/php-sdk/examples/pfop_vframe.php @@ -0,0 +1,55 @@ +useHTTPS = true; +$pfop = new PersistentFop($auth, $config); + +// 视频处理完毕后保存到空间中的名称 +$saveasKey = 'qiniu_480x360.jpg'; + +// 进行视频截帧操作 +$fops = "vframe/jpg/offset/1/w/480/h/360/rotate/90|saveas/" . + \Qiniu\base64_urlSafeEncode("$bucket:$saveasKey"); + +list($id, $err) = $pfop->execute($bucket, $key, $fops, $pipeline, $notifyUrl, $force); +echo "\n====> pfop avthumb result: \n"; +if ($err != null) { + var_dump($err); +} else { + echo "PersistentFop Id: $id\n"; +} + +// 查询转码的进度和状态 +list($ret, $err) = $pfop->status($id); +echo "\n====> pfop avthumb status: \n"; +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/pfop_video_avthumb.php b/php-sdk/examples/pfop_video_avthumb.php new file mode 100644 index 0000000..986aa8c --- /dev/null +++ b/php-sdk/examples/pfop_video_avthumb.php @@ -0,0 +1,55 @@ +useHTTPS=true; + +// 视频处理完毕后保存到空间中的名称 +$saveasKey = 'qiniu_640x360.mp4'; + +$pfop = new PersistentFop($auth, $config); + +// 进行视频转码操作 +$fops = "avthumb/mp4/s/640x360/vb/1.4m|saveas/" . \Qiniu\base64_urlSafeEncode("$bucket:$saveasKey"); + +list($id, $err) = $pfop->execute($bucket, $key, $fops, $pipeline, $notifyUrl, $force); +echo "\n====> pfop avthumb result: \n"; +if ($err != null) { + var_dump($err); +} else { + echo "PersistentFop Id: $id\n"; +} + +// 查询转码的进度和状态 +list($ret, $err) = $pfop->status($id); +echo "\n====> pfop avthumb status: \n"; +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/pfop_watermark.php b/php-sdk/examples/pfop_watermark.php new file mode 100644 index 0000000..ea3d6bc --- /dev/null +++ b/php-sdk/examples/pfop_watermark.php @@ -0,0 +1,59 @@ +useHTTPS=true; +$pfop = new PersistentFop($auth, $config); + +// 图片水印的源路径,也就是给视频打图片水印的图片 +$base64URL = Qiniu\base64_urlSafeEncode('http://test-2.qiniudn.com/logo.png'); + +// 视频处理完毕后保存到空间中的名称 +$saveasKey = 'qiniu_watermark.mp4'; + +// 进行视频打图片水印操作 +$fops = "avthumb/mp4/wmImage/" . $base64URL . "|saveas/" + . \Qiniu\base64_urlSafeEncode("$bucket:$saveasKey"); + +list($id, $err) = $pfop->execute($bucket, $key, $fops, $pipeline, $notifyUrl, $force); +echo "\n====> pfop avthumb result: \n"; +if ($err != null) { + var_dump($err); +} else { + echo "PersistentFop Id: $id\n"; +} + +// 查询转码的进度和状态 +list($ret, $err) = $pfop->status($id); +echo "\n====> pfop avthumb status: \n"; +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/php-logo.png b/php-sdk/examples/php-logo.png new file mode 100644 index 0000000..77e051f Binary files /dev/null and b/php-sdk/examples/php-logo.png differ diff --git a/php-sdk/examples/prefop.php b/php-sdk/examples/prefop.php new file mode 100644 index 0000000..1b8950a --- /dev/null +++ b/php-sdk/examples/prefop.php @@ -0,0 +1,27 @@ +useHTTPS=true; + +$pfop = new PersistentFop($auth, $config); + +$id = "z2.01z201c4oyre6q1hgy00murnel0002nh"; + +// 查询持久化处理的进度和状态 +list($ret, $err) = $pfop->status($id); +echo "\n====> pfop avthumb status: \n"; +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/put_bucketAccessMode.php b/php-sdk/examples/put_bucketAccessMode.php new file mode 100644 index 0000000..638ae3c --- /dev/null +++ b/php-sdk/examples/put_bucketAccessMode.php @@ -0,0 +1,27 @@ +putBucketAccessMode($bucket, $private); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/put_bucketAccessStyleMode.php b/php-sdk/examples/put_bucketAccessStyleMode.php new file mode 100644 index 0000000..3cc2aec --- /dev/null +++ b/php-sdk/examples/put_bucketAccessStyleMode.php @@ -0,0 +1,27 @@ +putBucketAccessStyleMode($bucket, $mode); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/put_bucketEvent.php b/php-sdk/examples/put_bucketEvent.php new file mode 100644 index 0000000..f3c830d --- /dev/null +++ b/php-sdk/examples/put_bucketEvent.php @@ -0,0 +1,32 @@ +putBucketEvent($bucket, $name, $prefix, $suffix, $event, $callbackURL); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/put_bucketMaxAge.php b/php-sdk/examples/put_bucketMaxAge.php new file mode 100644 index 0000000..4890174 --- /dev/null +++ b/php-sdk/examples/put_bucketMaxAge.php @@ -0,0 +1,27 @@ +putBucketMaxAge($bucket, $maxAge); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/put_bucketQuota.php b/php-sdk/examples/put_bucketQuota.php new file mode 100644 index 0000000..b00ec48 --- /dev/null +++ b/php-sdk/examples/put_bucketQuota.php @@ -0,0 +1,29 @@ +putBucketQuota($bucket, $size, $count); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/put_referAntiLeech.php b/php-sdk/examples/put_referAntiLeech.php new file mode 100644 index 0000000..7d56d1e --- /dev/null +++ b/php-sdk/examples/put_referAntiLeech.php @@ -0,0 +1,30 @@ +putReferAntiLeech($bucket, $mode, $norefer, $pattern); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/qetag.php b/php-sdk/examples/qetag.php new file mode 100644 index 0000000..1fe90d1 --- /dev/null +++ b/php-sdk/examples/qetag.php @@ -0,0 +1,14 @@ +useHTTPS = true; // 接口是否使用 HTTPS 协议 + +$bucketManager = new BucketManager($auth, $config); + +// 异步第三方资源抓取 +// 参考文档:https://developer.qiniu.com/kodo/api/4097/asynch-fetch + +// 需要抓取的文件 URL +$url = 'http://devtools.qiniu.com/qiniu.png'; + +//回调 URL(需要可以公网访问,并能够相应 200 OK) +$callbackurl = "http://your.domain.com/upload_verify_callback.php"; + +// 回调Body +$callbackbody = '{"key":"$(key)","hash":"$(etag)","w":"$(imageInfo.width)","h":"$(imageInfo.height)"}'; + + +//---------------------------------------- demo1 ---------------------------------------- +// 指定抓取的文件保存到七牛云空间中的名称 + +$key = time() . '.png'; +list($ret, $err) = $bucketManager->asynchFetch($url, $bucket, null, $key, null, null, $callbackurl, $callbackbody); +echo "=====> asynch fetch $url to bucket: $bucket key: $key\n"; +if ($err !== null) { + var_dump($err); +} else { + $id = $ret['id']; + echo "id is: $id\n"; +} + +//---------------------------------------- demo2 ---------------------------------------- +// 不指定 key 时,以文件内容的 hash 作为文件名 + +$key = null; +list($ret, $err) = $bucketManager->asynchFetch($url, $bucket, null, $key, null, null, $callbackurl, $callbackbody); +echo "=====> asynch fetch $url to bucket: $bucket key: $(etag)\n"; +if ($err !== null) { + var_dump($err); +} else { + $id = $ret['id']; + echo "id is: $id\n"; +} + +// 查询异步抓取的进度和状态 + +// 华东:z0,华北:z1,华南:z2,北美:na0,东南亚:as0 +$zone = 'z2'; + +sleep(10); // 由于异步抓取需要耗时,等待 10 秒后再查询状态 +list($ret, $err) = $bucketManager->asynchFetchStatus($zone, $id); +echo "\n====> asynch fetch status: \n"; +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_batch_change_mime.php b/php-sdk/examples/rs_batch_change_mime.php new file mode 100644 index 0000000..c5bd6b4 --- /dev/null +++ b/php-sdk/examples/rs_batch_change_mime.php @@ -0,0 +1,32 @@ + 'video/x-mp4', + 'qiniu.png' => 'image/x-png', + 'qiniu.jpg' => 'image/x-jpg' +); + +$ops = $bucketManager->buildBatchChangeMime($bucket, $keyMimePairs); +list($ret, $err) = $bucketManager->batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_batch_change_type.php b/php-sdk/examples/rs_batch_change_type.php new file mode 100644 index 0000000..a19d0d4 --- /dev/null +++ b/php-sdk/examples/rs_batch_change_type.php @@ -0,0 +1,45 @@ +batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_batch_copy.php b/php-sdk/examples/rs_batch_copy.php new file mode 100644 index 0000000..66c4d4d --- /dev/null +++ b/php-sdk/examples/rs_batch_copy.php @@ -0,0 +1,40 @@ +buildBatchCopy($srcBucket, $keyPairs, $destBucket, true); +list($ret, $err) = $bucketManager->batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_batch_delete.php b/php-sdk/examples/rs_batch_delete.php new file mode 100644 index 0000000..ebcdbe6 --- /dev/null +++ b/php-sdk/examples/rs_batch_delete.php @@ -0,0 +1,32 @@ +buildBatchDelete($bucket, $keys); +list($ret, $err) = $bucketManager->batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_batch_delete_after_days.php b/php-sdk/examples/rs_batch_delete_after_days.php new file mode 100644 index 0000000..928dd14 --- /dev/null +++ b/php-sdk/examples/rs_batch_delete_after_days.php @@ -0,0 +1,39 @@ +buildBatchDeleteAfterDays($bucket, $keyDayPairs); +list($ret, $err) = $bucketManager->batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_batch_move.php b/php-sdk/examples/rs_batch_move.php new file mode 100644 index 0000000..01d8c91 --- /dev/null +++ b/php-sdk/examples/rs_batch_move.php @@ -0,0 +1,40 @@ +buildBatchMove($srcBucket, $keyPairs, $destBucket, true); +list($ret, $err) = $bucketManager->batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_batch_restore_ar.php b/php-sdk/examples/rs_batch_restore_ar.php new file mode 100644 index 0000000..b2f79d0 --- /dev/null +++ b/php-sdk/examples/rs_batch_restore_ar.php @@ -0,0 +1,41 @@ +batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_batch_stat.php b/php-sdk/examples/rs_batch_stat.php new file mode 100644 index 0000000..88bc32e --- /dev/null +++ b/php-sdk/examples/rs_batch_stat.php @@ -0,0 +1,32 @@ +buildBatchStat($bucket, $keys); +list($ret, $err) = $bucketManager->batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_bucket_domains.php b/php-sdk/examples/rs_bucket_domains.php new file mode 100644 index 0000000..3cc9cb3 --- /dev/null +++ b/php-sdk/examples/rs_bucket_domains.php @@ -0,0 +1,26 @@ +domains($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_buckets.php b/php-sdk/examples/rs_buckets.php new file mode 100644 index 0000000..84263a9 --- /dev/null +++ b/php-sdk/examples/rs_buckets.php @@ -0,0 +1,25 @@ +buckets(true); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_change_mime.php b/php-sdk/examples/rs_change_mime.php new file mode 100644 index 0000000..f4442aa --- /dev/null +++ b/php-sdk/examples/rs_change_mime.php @@ -0,0 +1,29 @@ +changeMime($bucket, $key, $newMime); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_change_status.php b/php-sdk/examples/rs_change_status.php new file mode 100644 index 0000000..bedf61c --- /dev/null +++ b/php-sdk/examples/rs_change_status.php @@ -0,0 +1,29 @@ +changeStatus($bucket, $key, $status); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_change_type.php b/php-sdk/examples/rs_change_type.php new file mode 100644 index 0000000..8b3201f --- /dev/null +++ b/php-sdk/examples/rs_change_type.php @@ -0,0 +1,36 @@ +changeType($bucket, $key, $fileType); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_copy.php b/php-sdk/examples/rs_copy.php new file mode 100644 index 0000000..aae4d96 --- /dev/null +++ b/php-sdk/examples/rs_copy.php @@ -0,0 +1,33 @@ +copy($srcBucket, $srcKey, $destBucket, $destKey, true); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_delete.php b/php-sdk/examples/rs_delete.php new file mode 100644 index 0000000..ad97266 --- /dev/null +++ b/php-sdk/examples/rs_delete.php @@ -0,0 +1,27 @@ +delete($bucket, $key); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_delete_after_days.php b/php-sdk/examples/rs_delete_after_days.php new file mode 100644 index 0000000..96e55de --- /dev/null +++ b/php-sdk/examples/rs_delete_after_days.php @@ -0,0 +1,26 @@ +deleteAfterDays($bucket, $key, $days); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_download_urls.php b/php-sdk/examples/rs_download_urls.php new file mode 100644 index 0000000..e803ddc --- /dev/null +++ b/php-sdk/examples/rs_download_urls.php @@ -0,0 +1,19 @@ +/,一定要带访问协议,也就是 http:// 或者 https:// +$baseUrl = 'http://if-pri.qiniudn.com/qiniu.png?imageView2/1/h/500'; + +// 对链接进行签名,参考文档:https://developer.qiniu.com/kodo/manual/1656/download-private +$signedUrl = $auth->privateDownloadUrl($baseUrl); + +echo $signedUrl; diff --git a/php-sdk/examples/rs_fetch.php b/php-sdk/examples/rs_fetch.php new file mode 100644 index 0000000..5c1a5ab --- /dev/null +++ b/php-sdk/examples/rs_fetch.php @@ -0,0 +1,43 @@ +fetch($url, $bucket, $key); +echo "=====> fetch $url to bucket: $bucket key: $key\n"; +if ($err !== null) { + var_dump($err); +} else { + print_r($ret); +} + +//---------------------------------------- demo2 ---------------------------------------- +// 不指定 key 时,以文件内容的 hash 作为文件名 + +$key = null; +list($ret, $err) = $bucketManager->fetch($url, $bucket, $key); +echo "=====> fetch $url to bucket: $bucket key: $(etag)\n"; +if ($err !== null) { + var_dump($err); +} else { + print_r($ret); +} diff --git a/php-sdk/examples/rs_move.php b/php-sdk/examples/rs_move.php new file mode 100644 index 0000000..a399665 --- /dev/null +++ b/php-sdk/examples/rs_move.php @@ -0,0 +1,29 @@ +move($srcBucket, $srcKey, $destBucket, $destKey, true); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_prefetch.php b/php-sdk/examples/rs_prefetch.php new file mode 100644 index 0000000..28af115 --- /dev/null +++ b/php-sdk/examples/rs_prefetch.php @@ -0,0 +1,25 @@ +prefetch($bucket, $key); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_restore.php b/php-sdk/examples/rs_restore.php new file mode 100644 index 0000000..a3bf070 --- /dev/null +++ b/php-sdk/examples/rs_restore.php @@ -0,0 +1,28 @@ +restoreAr($bucket, $key, 1); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rs_stat.php b/php-sdk/examples/rs_stat.php new file mode 100644 index 0000000..36e863e --- /dev/null +++ b/php-sdk/examples/rs_stat.php @@ -0,0 +1,28 @@ +stat($bucket, $key); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rsf_list_bucket.php b/php-sdk/examples/rsf_list_bucket.php new file mode 100644 index 0000000..97a5838 --- /dev/null +++ b/php-sdk/examples/rsf_list_bucket.php @@ -0,0 +1,47 @@ +listFiles($bucket, $prefix, $marker, $limit, $delimiter); + if ($err !== null) { + echo "\n====> list file err: \n"; + var_dump($err); + } else { + $marker = null; + if (array_key_exists('marker', $ret)) { + $marker = $ret['marker']; + } + echo "Marker: $marker\n"; + echo "\nList Items====>\n"; + //var_dump($ret['items']); + print('items count:' . count($ret['items']) . "\n"); + if (array_key_exists('commonPrefixes', $ret)) { + print_r($ret['commonPrefixes']); + } + } +} while (!empty($marker)); diff --git a/php-sdk/examples/rsf_list_files.php b/php-sdk/examples/rsf_list_files.php new file mode 100644 index 0000000..31c455b --- /dev/null +++ b/php-sdk/examples/rsf_list_files.php @@ -0,0 +1,39 @@ +listFiles($bucket, $prefix, $marker, $limit, $delimiter); +if ($err !== null) { + echo "\n====> list file err: \n"; + var_dump($err); +} else { + if (array_key_exists('marker', $ret)) { + echo "Marker:" . $ret["marker"] . "\n"; + } + echo "\nList Iterms====>\n"; +} diff --git a/php-sdk/examples/rsf_v2list_bucket.php b/php-sdk/examples/rsf_v2list_bucket.php new file mode 100644 index 0000000..5f9d763 --- /dev/null +++ b/php-sdk/examples/rsf_v2list_bucket.php @@ -0,0 +1,34 @@ +listFilesv2($bucket, $prefix, $marker, $limit, $delimiter, true); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/rtc/README.md b/php-sdk/examples/rtc/README.md new file mode 100644 index 0000000..c7fff4d --- /dev/null +++ b/php-sdk/examples/rtc/README.md @@ -0,0 +1,34 @@ +# Rtc Streaming Cloud Server-Side Library For PHP + +## Features + +- RoomToken 签发 + - [x] 生成 RoomToken: client->appToken() + +- App 管理 + - [x] 创建应用: client->createApp() + - [x] 获取应用配置信息: client->getApp() + - [x] 更新应用配置信息: client->updateApp() + - [x] 删除应用: client->deleteApp() + +- 房间管理 + - [x] 列举房间下的所有用户: client->listUser() + - [x] 指定一个用户踢出房间: client->kickUser() + - [x] 停止一个房间的合流转推: client->stopMerge() + - [x] 获取当前所有活跃的房间: client->listActiveRooms() + +## Demo +- RoomToken 签发 + - [生成 RoomToken](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_create_roomToken.php) + +- App 管理 + - [创建应用](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_createApp.php) + - [获取应用配置信息](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_getApp.php) + - [更新应用配置信息](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_updateApp.php) + - [删除应用](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_deleteApp.php) + +- 房间管理 + - [列举房间下的所有用户](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_rooms_listUser.php) + - [指定一个用户踢出房间](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_rooms_kickUser.php) + - [停止一个房间的合流转推](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_rooms_stopMerge.php) + - [获取当前所有活跃的房间](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_rooms_listActiveRooms.php) \ No newline at end of file diff --git a/php-sdk/examples/rtc/rtc_createApp.php b/php-sdk/examples/rtc/rtc_createApp.php new file mode 100644 index 0000000..039eadd --- /dev/null +++ b/php-sdk/examples/rtc/rtc_createApp.php @@ -0,0 +1,32 @@ +createApp($hub, $title, $maxUsers); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Create Successfully: \n"; + var_dump($ret); +} diff --git a/php-sdk/examples/rtc/rtc_create_roomToken.php b/php-sdk/examples/rtc/rtc_create_roomToken.php new file mode 100644 index 0000000..6a62aa2 --- /dev/null +++ b/php-sdk/examples/rtc/rtc_create_roomToken.php @@ -0,0 +1,34 @@ +appToken($appId, $roomName, $userId, $expireAt, $permission); +echo "\n====> Create RoomToken Successfully: \n"; +var_dump($RoomToken); diff --git a/php-sdk/examples/rtc/rtc_deleteApp.php b/php-sdk/examples/rtc/rtc_deleteApp.php new file mode 100644 index 0000000..68bff33 --- /dev/null +++ b/php-sdk/examples/rtc/rtc_deleteApp.php @@ -0,0 +1,25 @@ +deleteApp($appId); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Delete $appId Successfully \n"; +} diff --git a/php-sdk/examples/rtc/rtc_getApp.php b/php-sdk/examples/rtc/rtc_getApp.php new file mode 100644 index 0000000..9f8e374 --- /dev/null +++ b/php-sdk/examples/rtc/rtc_getApp.php @@ -0,0 +1,26 @@ +getApp($appId); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> $appId Conf: \n"; + var_dump($ret); +} diff --git a/php-sdk/examples/rtc/rtc_rooms_kickUser.php b/php-sdk/examples/rtc/rtc_rooms_kickUser.php new file mode 100644 index 0000000..019c3f2 --- /dev/null +++ b/php-sdk/examples/rtc/rtc_rooms_kickUser.php @@ -0,0 +1,31 @@ +kickUser($appId, $roomName, $userId); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Kick User $userId Successfully \n"; +} diff --git a/php-sdk/examples/rtc/rtc_rooms_listActiveRooms.php b/php-sdk/examples/rtc/rtc_rooms_listActiveRooms.php new file mode 100644 index 0000000..16e6027 --- /dev/null +++ b/php-sdk/examples/rtc/rtc_rooms_listActiveRooms.php @@ -0,0 +1,35 @@ +listActiveRooms($appId, $prefix, $offset, $limit); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Active Rooms:\n"; + var_dump($ret); +} diff --git a/php-sdk/examples/rtc/rtc_rooms_listUser.php b/php-sdk/examples/rtc/rtc_rooms_listUser.php new file mode 100644 index 0000000..a839728 --- /dev/null +++ b/php-sdk/examples/rtc/rtc_rooms_listUser.php @@ -0,0 +1,29 @@ +listUser($appId, $roomName); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> User List: \n"; + var_dump($ret); +} diff --git a/php-sdk/examples/rtc/rtc_rooms_stopMerge.php b/php-sdk/examples/rtc/rtc_rooms_stopMerge.php new file mode 100644 index 0000000..e140907 --- /dev/null +++ b/php-sdk/examples/rtc/rtc_rooms_stopMerge.php @@ -0,0 +1,28 @@ +stopMerge($appId, $roomName); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Stop Merge Successfully \n"; +} diff --git a/php-sdk/examples/rtc/rtc_updateApp.php b/php-sdk/examples/rtc/rtc_updateApp.php new file mode 100644 index 0000000..f771075 --- /dev/null +++ b/php-sdk/examples/rtc/rtc_updateApp.php @@ -0,0 +1,40 @@ +updateApp($appId, $hub, $title, $maxUsers, false, $mergePublishRtmp); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Update $appId Conf Successfully: \n"; + var_dump($ret); +} diff --git a/php-sdk/examples/saveas.php b/php-sdk/examples/saveas.php new file mode 100644 index 0000000..5d51ef4 --- /dev/null +++ b/php-sdk/examples/saveas.php @@ -0,0 +1,33 @@ +为生成缩略图的文件名 +$entry = ':'; + +// 生成的值 +$encodedEntryURI = \Qiniu\base64_urlSafeEncode($entry); + +// 使用 SecretKey 对新的下载 URL 进行 HMAC1-SHA1 签名 +$newurl = "78re52.com1.z0.glb.clouddn.com/resource/Ship.jpg?imageView2/2/w/200/h/200|saveas/" . $encodedEntryURI; + +$sign = hash_hmac("sha1", $newurl, $secretKey, true); + +// 对签名进行 URL 安全的 Base64 编码 +$encodedSign = \Qiniu\base64_urlSafeEncode($sign); + +// 最终得到的完整下载 URL +$finalURL = "http://" . $newurl . "/sign/" . $accessKey . ":" . $encodedSign; + +$callbackBody = file_get_contents("$finalURL"); + +echo $callbackBody; diff --git a/php-sdk/examples/sms/README.md b/php-sdk/examples/sms/README.md new file mode 100644 index 0000000..8c80a38 --- /dev/null +++ b/php-sdk/examples/sms/README.md @@ -0,0 +1,45 @@ +# SMS Server-Side Library For PHP + +## Features + +- 签名管理 + - [x] 创建签名: client->createSignature() + - [x] 列出签名: client->checkSignature() + - [x] 查询单个签名: client->checkSingleSignature() + - [x] 编辑签名: client->updateSignature() + - [x] 删除签名: client->deleteSignature() + +- 模板管理 + - [x] 创建模板: client->createTemplate() + - [x] 列出模板: client->queryTemplate() + - [x] 查询单个模板: client->querySingleTemplate() + - [x] 编辑模板: client->updateTemplate() + - [x] 删除模板: client->deleteTemplate() + +- 发送短信 + - [x] 发送短信: client->sendMessage() + +- 查询发送记录 + - [x] 查询发送记录: client->querySendSms() + +## Demo + +- 签名管理 + - [创建签名](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_create_signature.php) + - [列出签名](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_query_signature.php) + - [查询单个签名](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_query_single_signature.php) + - [编辑签名](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_edit_signature.php) + - [删除签名](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_delete_signature.php) + +- 模板管理 + - [创建模板](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_create_template.php) + - [列出模板](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_query_template.php) + - [查询单个模板](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_query_single_template.php) + - [编辑模板](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_edit_template.php) + - [删除模板](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_delete_template.php) + +- 发送短信 + - [发送短信](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_send_message.php) + +- 查询发送记录 + - [查询发送记录](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_query_send_sms.php) diff --git a/php-sdk/examples/sms/sms_create_signature.php b/php-sdk/examples/sms/sms_create_signature.php new file mode 100644 index 0000000..ea1f158 --- /dev/null +++ b/php-sdk/examples/sms/sms_create_signature.php @@ -0,0 +1,29 @@ +createSignature($signature, $source, $pics); + +echo "\n====> create signature result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/sms/sms_create_template.php b/php-sdk/examples/sms/sms_create_template.php new file mode 100644 index 0000000..3cb3874 --- /dev/null +++ b/php-sdk/examples/sms/sms_create_template.php @@ -0,0 +1,33 @@ +createTemplate($name, $template, $type, $description, $signature_id); + +echo "\n====> create signature result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/sms/sms_delete_signature.php b/php-sdk/examples/sms/sms_delete_signature.php new file mode 100644 index 0000000..fd873fa --- /dev/null +++ b/php-sdk/examples/sms/sms_delete_signature.php @@ -0,0 +1,25 @@ +deleteSignature($signature_id); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Delete Signature $signature_id Successfully\n"; +} diff --git a/php-sdk/examples/sms/sms_delete_template.php b/php-sdk/examples/sms/sms_delete_template.php new file mode 100644 index 0000000..4590835 --- /dev/null +++ b/php-sdk/examples/sms/sms_delete_template.php @@ -0,0 +1,25 @@ +deleteTemplate($template_id); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Delete Template $template_id Successfully\n"; +} diff --git a/php-sdk/examples/sms/sms_edit_signature.php b/php-sdk/examples/sms/sms_edit_signature.php new file mode 100644 index 0000000..edf14e0 --- /dev/null +++ b/php-sdk/examples/sms/sms_edit_signature.php @@ -0,0 +1,30 @@ +updateSignature($id, $signature, $source, $pics); + +echo "\n====> edit signature result: \n"; +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Update Signature Successfully\n"; +} diff --git a/php-sdk/examples/sms/sms_edit_template.php b/php-sdk/examples/sms/sms_edit_template.php new file mode 100644 index 0000000..1be5509 --- /dev/null +++ b/php-sdk/examples/sms/sms_edit_template.php @@ -0,0 +1,31 @@ +updateTemplate($template_id, $name, $template, $description, $signature_id); + +echo "\n====> edit template result: \n"; +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Update Template Successfully\n"; +} diff --git a/php-sdk/examples/sms/sms_query_send_sms.php b/php-sdk/examples/sms/sms_query_send_sms.php new file mode 100644 index 0000000..cdbbe71 --- /dev/null +++ b/php-sdk/examples/sms/sms_query_send_sms.php @@ -0,0 +1,50 @@ +querySendSms( + $job_id, + $message_id, + $mobile, + $status, + $template_id, + $type, + $start, + $end, + $page, + $page_size +); +echo "\n====> query send sms result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/sms/sms_query_signature.php b/php-sdk/examples/sms/sms_query_signature.php new file mode 100644 index 0000000..224d09b --- /dev/null +++ b/php-sdk/examples/sms/sms_query_signature.php @@ -0,0 +1,28 @@ +querySignature($audit_status, $page, $page_size); +echo "\n====> query signature result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/sms/sms_query_single_signature.php b/php-sdk/examples/sms/sms_query_single_signature.php new file mode 100644 index 0000000..8afb4d5 --- /dev/null +++ b/php-sdk/examples/sms/sms_query_single_signature.php @@ -0,0 +1,26 @@ +checkSingleSignature($signature_id); +echo "\n====> query single signature result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/sms/sms_query_single_template.php b/php-sdk/examples/sms/sms_query_single_template.php new file mode 100644 index 0000000..8e0b279 --- /dev/null +++ b/php-sdk/examples/sms/sms_query_single_template.php @@ -0,0 +1,26 @@ +querySingleTemplate($template_id); +echo "\n====> query single template result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/sms/sms_query_template.php b/php-sdk/examples/sms/sms_query_template.php new file mode 100644 index 0000000..6be260e --- /dev/null +++ b/php-sdk/examples/sms/sms_query_template.php @@ -0,0 +1,28 @@ +queryTemplate($audit_status, $page, $page_size); +echo "\n====> query template result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/sms/sms_send_message.php b/php-sdk/examples/sms/sms_send_message.php new file mode 100644 index 0000000..d943e52 --- /dev/null +++ b/php-sdk/examples/sms/sms_send_message.php @@ -0,0 +1,32 @@ + 'xxxx'); + +list($ret, $err) = $client->sendMessage($template_id, $mobiles, $code); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Send Message Successfully: \n"; + var_dump($ret); +} diff --git a/php-sdk/examples/update_bucketEvent.php b/php-sdk/examples/update_bucketEvent.php new file mode 100644 index 0000000..7b0d1d0 --- /dev/null +++ b/php-sdk/examples/update_bucketEvent.php @@ -0,0 +1,31 @@ +updateBucketEvent($bucket, $name, $prefix, $suffix, $event, $callbackURL); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/update_bucketLifecycleRule.php b/php-sdk/examples/update_bucketLifecycleRule.php new file mode 100644 index 0000000..73f0f56 --- /dev/null +++ b/php-sdk/examples/update_bucketLifecycleRule.php @@ -0,0 +1,36 @@ +updateBucketLifecycleRule( + $bucket, + $name, + $prefix, + $delete_after_days, + $to_line_after_days +); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/upload_and_callback.php b/php-sdk/examples/upload_and_callback.php new file mode 100644 index 0000000..a0c793a --- /dev/null +++ b/php-sdk/examples/upload_and_callback.php @@ -0,0 +1,31 @@ + 'http://your.domain.com/upload_verify_callback.php', + 'callbackBody' => 'filename=$(fname)&filesize=$(fsize)' +); +$uptoken = $auth->uploadToken($bucket, null, 3600, $policy); + +// 上传文件的本地路径 +$filePath = './php-logo.png'; + +$uploadMgr = new UploadManager(); +list($ret, $err) = $uploadMgr->putFile($uptoken, null, $filePath); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/upload_and_pfop.php b/php-sdk/examples/upload_and_pfop.php new file mode 100644 index 0000000..32c1eb5 --- /dev/null +++ b/php-sdk/examples/upload_and_pfop.php @@ -0,0 +1,49 @@ + $pfop, + 'persistentNotifyUrl' => $notifyUrl, + 'persistentPipeline' => $pipeline +); +$token = $auth->uploadToken($bucket, null, 3600, $policy); + +list($ret, $err) = $uploadMgr->putFile($token, $key, $filePath); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/upload_mgr_init.php b/php-sdk/examples/upload_mgr_init.php new file mode 100644 index 0000000..1164c90 --- /dev/null +++ b/php-sdk/examples/upload_mgr_init.php @@ -0,0 +1,19 @@ +uploadToken($bucket); + +// 构建 UploadManager 对象 +$uploadMgr = new UploadManager(); diff --git a/php-sdk/examples/upload_multi_demos.php b/php-sdk/examples/upload_multi_demos.php new file mode 100644 index 0000000..d724235 --- /dev/null +++ b/php-sdk/examples/upload_multi_demos.php @@ -0,0 +1,89 @@ +uploadToken($bucket); +$uploadMgr = new UploadManager(); + +//---------------------------------------- upload demo1 ---------------------------------------- +// 上传字符串到七牛 + +list($ret, $err) = $uploadMgr->put($token, null, 'content string'); +echo "\n====> put result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} + + +//---------------------------------------- upload demo2 ---------------------------------------- +// 上传文件到七牛 + +$filePath = './php-logo.png'; +$key = 'php-logo.png'; +list($ret, $err) = $uploadMgr->putFile($token, $key, $filePath); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} + + +//---------------------------------------- upload demo3 ---------------------------------------- +// 上传文件到七牛后, 七牛将文件名和文件大小回调给业务服务器. +// 可参考文档: https://developer.qiniu.com/kodo/manual/1206/put-policy + +$policy = array( + 'callbackUrl' => 'http://172.30.251.210/upload_verify_callback.php', + 'callbackBody' => 'filename=$(fname)&filesize=$(fsize)' +// 'callbackBodyType' => 'application/json', +// 'callbackBody' => '{"filename":$(fname), "filesize": $(fsize)}' //设置application/json格式回调 +); +$token = $auth->uploadToken($bucket, null, 3600, $policy); + + +list($ret, $err) = $uploadMgr->putFile($token, null, $key); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} + + +//---------------------------------------- upload demo4 ---------------------------------------- +// 上传视频,上传完成后进行 m3u8 的转码, 并给视频打水印 + +$wmImg = Qiniu\base64_urlSafeEncode('http://devtools.qiniudn.com/qiniu.png'); +$pfop = "avthumb/m3u8/wmImage/$wmImg"; + +// 转码完成后回调到业务服务器。(公网可以访问,并相应 200 OK) +$notifyUrl = 'http://notify.fake.com'; + +$policy = array( + 'persistentOps' => $pfop, + 'persistentNotifyUrl' => $notifyUrl, + 'persistentPipeline' => $pipeline +); +$token = $auth->uploadToken($bucket, null, 3600, $policy); +print($token); +list($ret, $err) = $uploadMgr->putFile($token, null, $key); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/upload_simple_file.php b/php-sdk/examples/upload_simple_file.php new file mode 100644 index 0000000..f495a02 --- /dev/null +++ b/php-sdk/examples/upload_simple_file.php @@ -0,0 +1,37 @@ +uploadToken($bucket); + +// 要上传文件的本地路径 +$filePath = './php-logo.png'; + +// 上传到七牛存储后保存的文件名 +$key = 'my-php-logo.png'; + +// 初始化 UploadManager 对象并进行文件的上传。 +$uploadMgr = new UploadManager(); + +// 调用 UploadManager 的 putFile 方法进行文件的上传,该方法会判断文件大小,进而决定使用表单上传还是分片上传,无需手动配置。 +list($ret, $err) = $uploadMgr->putFile($token, $key, $filePath); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/upload_tokens.php b/php-sdk/examples/upload_tokens.php new file mode 100644 index 0000000..d2cf02c --- /dev/null +++ b/php-sdk/examples/upload_tokens.php @@ -0,0 +1,82 @@ +uploadToken($bucket, null, $expires, $policy, true); +print($upToken . "\n"); + +//---------------------------------------- demo2 ---------------------------------------- +// 自定义凭证有效期(示例2小时) + +$expires = 7200; +$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true); +print($upToken . "\n"); + +//---------------------------------------- demo3 ---------------------------------------- +// 覆盖上传凭证 + +$expires = 3600; +$keyToOverwrite = 'qiniu.mp4'; +$upToken = $auth->uploadToken($bucket, $keyToOverwrite, $expires, $policy, true); +print($upToken . "\n"); + +//---------------------------------------- demo4 ---------------------------------------- +// 自定义上传回复(非callback模式)凭证 + +$returnBody = '{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}'; +$policy = array( + 'returnBody' => $returnBody +); +$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true); +print($upToken . "\n"); + +//---------------------------------------- demo5 ---------------------------------------- +// 带回调业务服务器的凭证(application/json) + +$policy = array( + 'callbackUrl' => 'http://api.example.com/qiniu/upload/callback', + 'callbackBody' => '{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}', + 'callbackBodyType' => 'application/json' +); +$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true); +print($upToken . "\n"); + +//---------------------------------------- demo6 ---------------------------------------- +// 带回调业务服务器的凭证(application/x-www-form-urlencoded) + +$policy = array( + 'callbackUrl' => 'http://api.example.com/qiniu/upload/callback', + 'callbackBody' => 'key=$(key)&hash=$(etag)&bucket=$(bucket)&fsize=$(fsize)&name=$(x:name)' +); +$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true); +print($upToken . "\n"); + +//---------------------------------------- demo7 ---------------------------------------- +// 带数据处理的凭证 + +$saveMp4Entry = \Qiniu\base64_urlSafeEncode($bucket . ":avthumb_test_target.mp4"); +$saveJpgEntry = \Qiniu\base64_urlSafeEncode($bucket . ":vframe_test_target.jpg"); +$avthumbMp4Fop = "avthumb/mp4|saveas/" . $saveMp4Entry; +$vframeJpgFop = "vframe/jpg/offset/1|saveas/" . $saveJpgEntry; +$policy = array( + 'persistentOps' => $avthumbMp4Fop . ";" . $vframeJpgFop, + 'persistentPipeline' => "video-pipe", + 'persistentNotifyUrl' => "http://api.example.com/qiniu/pfop/notify", +); +$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true); +print($upToken . "\n"); diff --git a/php-sdk/examples/upload_verify_callback.php b/php-sdk/examples/upload_verify_callback.php new file mode 100644 index 0000000..dcb64c9 --- /dev/null +++ b/php-sdk/examples/upload_verify_callback.php @@ -0,0 +1,34 @@ +verifyCallback($contentType, $authorization, $url, $callbackBody); + +if ($isQiniuCallback) { + $resp = array('ret' => 'success'); +} else { + $resp = array('ret' => 'failed'); +} + +echo json_encode($resp); diff --git a/php-sdk/examples/upload_with_qvmzone.php b/php-sdk/examples/upload_with_qvmzone.php new file mode 100644 index 0000000..ce2b21f --- /dev/null +++ b/php-sdk/examples/upload_with_qvmzone.php @@ -0,0 +1,40 @@ +uploadToken($bucket); + +// 上传文件的本地路径 +$filePath = './php-logo.png'; + +// 七牛云主机QVM和七牛对象存储KODO内网上传,目前支持华东1区域(杭州)和华北2区域(北京)的云主机可以访问同区域的对象存储服务 +// 参考文档:https://developer.qiniu.com/qvm/manual/4269/qvm-kodo + +$zone = Zone::qvmZonez0(); // 华东:z0,华北:z1 +$config = new Config($zone); +$config->useHTTPS = true; + +// 指定 config +$uploadMgr = new UploadManager($config); + +list($ret, $err) = $uploadMgr->putFile($uptoken, $key, $filePath); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/examples/upload_with_zone.php b/php-sdk/examples/upload_with_zone.php new file mode 100644 index 0000000..6192666 --- /dev/null +++ b/php-sdk/examples/upload_with_zone.php @@ -0,0 +1,39 @@ +uploadToken($bucket); + +// 上传文件的本地路径 +$filePath = './php-logo.png'; + +// 指定 zone 上传 +// 参考文档:https://developer.qiniu.com/kodo/manual/1671/region-endpoint +$zone = Zone::zonez0(); // 华东:z0,华北:z1,华南:z2,北美:na0,东南亚:as0 +$config = new Config($zone); +$config->useHTTPS = true; + +// 指定 config +$uploadMgr = new UploadManager($config); + +list($ret, $err) = $uploadMgr->putFile($uptoken, $key, $filePath); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/php-sdk/phpunit.xml.dist b/php-sdk/phpunit.xml.dist new file mode 100644 index 0000000..840f6e5 --- /dev/null +++ b/php-sdk/phpunit.xml.dist @@ -0,0 +1,18 @@ + + + + + tests + + + + diff --git a/php-sdk/src/Qiniu/Auth.php b/php-sdk/src/Qiniu/Auth.php new file mode 100644 index 0000000..6da2be4 --- /dev/null +++ b/php-sdk/src/Qiniu/Auth.php @@ -0,0 +1,285 @@ +accessKey = $accessKey; + $this->secretKey = $secretKey; + $defaultOptions = array( + 'disableQiniuTimestampSignature' => null + ); + if ($options == null) { + $options = $defaultOptions; + } + $this->options = array_merge($defaultOptions, $options); + } + + public function getAccessKey() + { + return $this->accessKey; + } + + public function sign($data) + { + $hmac = hash_hmac('sha1', $data, $this->secretKey, true); + return $this->accessKey . ':' . \Qiniu\base64_urlSafeEncode($hmac); + } + + public function signWithData($data) + { + $encodedData = \Qiniu\base64_urlSafeEncode($data); + return $this->sign($encodedData) . ':' . $encodedData; + } + + public function signRequest($urlString, $body, $contentType = null) + { + $url = parse_url($urlString); + $data = ''; + if (array_key_exists('path', $url)) { + $data = $url['path']; + } + if (array_key_exists('query', $url)) { + $data .= '?' . $url['query']; + } + $data .= "\n"; + + if ($body !== null && $contentType === 'application/x-www-form-urlencoded') { + $data .= $body; + } + return $this->sign($data); + } + + /** + * @param string $urlString + * @param string $method + * @param string $body + * @param null|Header $headers + */ + public function signQiniuAuthorization($urlString, $method = "GET", $body = "", $headers = null) + { + $url = parse_url($urlString); + if (!$url) { + return array(null, new \Exception("parse_url error")); + } + + // append method, path and query + if ($method === "") { + $data = "GET "; + } else { + $data = $method . " "; + } + if (isset($url["path"])) { + $data .= $url["path"]; + } + if (isset($url["query"])) { + $data .= "?" . $url["query"]; + } + + // append Host + $data .= "\n"; + $data .= "Host: "; + if (isset($url["host"])) { + $data .= $url["host"]; + } + if (isset($url["port"]) && $url["port"] > 0) { + $data .= ":" . $url["port"]; + } + + // try to append content type + if ($headers != null && isset($headers["Content-Type"])) { + // append content type + $data .= "\n"; + $data .= "Content-Type: " . $headers["Content-Type"]; + } + + // try append xQiniuHeaders + if ($headers != null) { + $headerLines = array(); + $keyPrefix = "X-Qiniu-"; + foreach ($headers as $k => $v) { + if (strlen($k) > strlen($keyPrefix) && strpos($k, $keyPrefix) === 0) { + array_push( + $headerLines, + $k . ": " . $v + ); + } + } + if (count($headerLines) > 0) { + $data .= "\n"; + sort($headerLines); + $data .= implode("\n", $headerLines); + } + } + + // append body + $data .= "\n\n"; + if (!is_null($body) + && strlen($body) > 0 + && isset($headers["Content-Type"]) + && $headers["Content-Type"] != "application/octet-stream" + ) { + $data .= $body; + } + + return array($this->sign($data), null); + } + + public function verifyCallback( + $contentType, + $originAuthorization, + $url, + $body, + $method = "GET", + $headers = array() + ) { + if (strpos($originAuthorization, 'Qiniu') === 0) { + $qnHeaders = new Header($headers); + if (!isset($qnHeaders['Content-Type'])) { + $qnHeaders['Content-Type'] = $contentType; + } + list($sign, $err) = $this->signQiniuAuthorization( + $url, + $method, + $body, + $qnHeaders + ); + if ($err !== null) { + return false; + } + $authorization = 'Qiniu ' . $sign; + } else { + $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType); + } + return $originAuthorization === $authorization; + } + + public function privateDownloadUrl($baseUrl, $expires = 3600) + { + $deadline = time() + $expires; + + $pos = strpos($baseUrl, '?'); + if ($pos !== false) { + $baseUrl .= '&e='; + } else { + $baseUrl .= '?e='; + } + $baseUrl .= $deadline; + + $token = $this->sign($baseUrl); + return "$baseUrl&token=$token"; + } + + public function uploadToken($bucket, $key = null, $expires = 3600, $policy = null, $strictPolicy = true) + { + $deadline = time() + $expires; + $scope = $bucket; + if ($key !== null) { + $scope .= ':' . $key; + } + + $args = self::copyPolicy($args, $policy, $strictPolicy); + $args['scope'] = $scope; + $args['deadline'] = $deadline; + + $b = json_encode($args); + return $this->signWithData($b); + } + + /** + *上传策略,参数规格详见 + *http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html + */ + private static $policyFields = array( + 'callbackUrl', + 'callbackBody', + 'callbackHost', + 'callbackBodyType', + 'callbackFetchKey', + + 'returnUrl', + 'returnBody', + + 'endUser', + 'saveKey', + 'forceSaveKey', + 'insertOnly', + + 'detectMime', + 'mimeLimit', + 'fsizeMin', + 'fsizeLimit', + + 'persistentOps', // 与 persistentWorkflowTemplateID 二选一 + 'persistentNotifyUrl', + 'persistentPipeline', + 'persistentType', // 为 `1` 时开启闲时任务 + 'persistentWorkflowTemplateID', // 与 persistentOps 二选一 + + 'deleteAfterDays', + 'fileType', + 'isPrefixalScope', + + 'transform', // deprecated + 'transformFallbackKey', // deprecated + 'transformFallbackMode', // deprecated + ); + + private static function copyPolicy(&$policy, $originPolicy, $strictPolicy) + { + if ($originPolicy === null) { + return array(); + } + foreach ($originPolicy as $key => $value) { + if (!$strictPolicy || in_array((string)$key, self::$policyFields, true)) { + $policy[$key] = $value; + } + } + return $policy; + } + + public function authorization($url, $body = null, $contentType = null) + { + $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType); + return array('Authorization' => $authorization); + } + + public function authorizationV2($url, $method, $body = null, $contentType = null) + { + $headers = new Header(); + $result = array(); + if ($contentType != null) { + $headers['Content-Type'] = $contentType; + $result['Content-Type'] = $contentType; + } + + $signDate = gmdate('Ymd\THis\Z', time()); + if ($this->options['disableQiniuTimestampSignature'] !== null) { + if (!$this->options['disableQiniuTimestampSignature']) { + $headers['X-Qiniu-Date'] = $signDate; + $result['X-Qiniu-Date'] = $signDate; + } + } elseif (getenv("DISABLE_QINIU_TIMESTAMP_SIGNATURE")) { + if (strtolower(getenv("DISABLE_QINIU_TIMESTAMP_SIGNATURE")) !== "true") { + $headers['X-Qiniu-Date'] = $signDate; + $result['X-Qiniu-Date'] = $signDate; + } + } else { + $headers['X-Qiniu-Date'] = $signDate; + $result['X-Qiniu-Date'] = $signDate; + } + + list($sign) = $this->signQiniuAuthorization($url, $method, $body, $headers); + $result['Authorization'] = 'Qiniu ' . $sign; + return $result; + } +} diff --git a/php-sdk/src/Qiniu/Cdn/CdnManager.php b/php-sdk/src/Qiniu/Cdn/CdnManager.php new file mode 100644 index 0000000..60052d3 --- /dev/null +++ b/php-sdk/src/Qiniu/Cdn/CdnManager.php @@ -0,0 +1,263 @@ +auth = $auth; + $this->server = 'http://fusion.qiniuapi.com'; + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + /** + * @param array $urls 待刷新的文件链接数组 + * @return array + */ + public function refreshUrls(array $urls) + { + return $this->refreshUrlsAndDirs($urls, array()); + } + + /** + * @param array $dirs 待刷新的文件链接数组 + * @return array + * 目前客户默认没有目录刷新权限,刷新会有400038报错,参考:https://developer.qiniu.com/fusion/api/1229/cache-refresh + * 需要刷新目录请工单联系技术支持 https://support.qiniu.com/tickets/category + */ + public function refreshDirs(array $dirs) + { + return $this->refreshUrlsAndDirs(array(), $dirs); + } + + /** + * @param array $urls 待刷新的文件链接数组 + * @param array $dirs 待刷新的目录链接数组 + * + * @return array 刷新的请求回复和错误,参考 examples/cdn_manager.php 代码 + * @link http://developer.qiniu.com/article/fusion/api/refresh.html + * + * 目前客户默认没有目录刷新权限,刷新会有400038报错,参考:https://developer.qiniu.com/fusion/api/1229/cache-refresh + * 需要刷新目录请工单联系技术支持 https://support.qiniu.com/tickets/category + */ + public function refreshUrlsAndDirs(array $urls, array $dirs) + { + $req = array(); + if (!empty($urls)) { + $req['urls'] = $urls; + } + if (!empty($dirs)) { + $req['dirs'] = $dirs; + } + + $url = $this->server . '/v2/tune/refresh'; + $body = json_encode($req); + return $this->post($url, $body); + } + + /** + * 查询 CDN 刷新记录 + * + * @param string $requestId 指定要查询记录所在的刷新请求id + * @param string $isDir 指定是否查询目录,取值为 yes/no,默认不填则为两种类型记录都查询 + * @param array $urls 要查询的url列表,每个url可以是文件url,也可以是目录url + * @param string $state 指定要查询记录的状态,取值processing/success/failure + * @param int $pageNo 要求返回的页号,默认为0 + * @param int $pageSize 要求返回的页长度,默认为100 + * @param string $startTime 指定查询的开始日期,格式2006-01-01 + * @param string $endTime 指定查询的结束日期,格式2006-01-01 + * @return array + * @link https://developer.qiniu.com/fusion/api/1229/cache-refresh#4 + */ + public function getCdnRefreshList( + $requestId = null, + $isDir = null, + $urls = array(), + $state = null, + $pageNo = 0, + $pageSize = 100, + $startTime = null, + $endTime = null + ) { + $req = array(); + \Qiniu\setWithoutEmpty($req, 'requestId', $requestId); + \Qiniu\setWithoutEmpty($req, 'isDir', $isDir); + \Qiniu\setWithoutEmpty($req, 'urls', $urls); + \Qiniu\setWithoutEmpty($req, 'state', $state); + \Qiniu\setWithoutEmpty($req, 'pageNo', $pageNo); + \Qiniu\setWithoutEmpty($req, 'pageSize', $pageSize); + \Qiniu\setWithoutEmpty($req, 'startTime', $startTime); + \Qiniu\setWithoutEmpty($req, 'endTime', $endTime); + + $body = json_encode($req); + $url = $this->server . '/v2/tune/refresh/list'; + return $this->post($url, $body); + } + + /** + * @param array $urls 待预取的文件链接数组 + * + * @return array 预取的请求回复和错误,参考 examples/cdn_manager.php 代码 + * + * @link http://developer.qiniu.com/article/fusion/api/refresh.html + */ + public function prefetchUrls(array $urls) + { + $req = array( + 'urls' => $urls, + ); + + $url = $this->server . '/v2/tune/prefetch'; + $body = json_encode($req); + return $this->post($url, $body); + } + + /** + * 查询 CDN 预取记录 + * + * @param string $requestId 指定要查询记录所在的刷新请求id + * @param array $urls 要查询的url列表,每个url可以是文件url,也可以是目录url + * @param string $state 指定要查询记录的状态,取值processing/success/failure + * @param int $pageNo 要求返回的页号,默认为0 + * @param int $pageSize 要求返回的页长度,默认为100 + * @param string $startTime 指定查询的开始日期,格式2006-01-01 + * @param string $endTime 指定查询的结束日期,格式2006-01-01 + * @return array + * @link https://developer.qiniu.com/fusion/api/1227/file-prefetching#4 + */ + public function getCdnPrefetchList( + $requestId = null, + $urls = array(), + $state = null, + $pageNo = 0, + $pageSize = 100, + $startTime = null, + $endTime = null + ) { + $req = array(); + \Qiniu\setWithoutEmpty($req, 'requestId', $requestId); + \Qiniu\setWithoutEmpty($req, 'urls', $urls); + \Qiniu\setWithoutEmpty($req, 'state', $state); + \Qiniu\setWithoutEmpty($req, 'pageNo', $pageNo); + \Qiniu\setWithoutEmpty($req, 'pageSize', $pageSize); + \Qiniu\setWithoutEmpty($req, 'startTime', $startTime); + \Qiniu\setWithoutEmpty($req, 'endTime', $endTime); + + $body = json_encode($req); + $url = $this->server . '/v2/tune/prefetch/list'; + return $this->post($url, $body); + } + + /** + * @param array $domains 待获取带宽数据的域名数组 + * @param string $startDate 开始的日期,格式类似 2017-01-01 + * @param string $endDate 结束的日期,格式类似 2017-01-01 + * @param string $granularity 获取数据的时间间隔,可以是 5min, hour 或者 day + * + * @return array 带宽数据和错误信息,参考 examples/cdn_manager.php 代码 + * + * @link http://developer.qiniu.com/article/fusion/api/traffic-bandwidth.html + */ + public function getBandwidthData(array $domains, $startDate, $endDate, $granularity) + { + $req = array(); + $req['domains'] = implode(';', $domains); + $req['startDate'] = $startDate; + $req['endDate'] = $endDate; + $req['granularity'] = $granularity; + + $url = $this->server . '/v2/tune/bandwidth'; + $body = json_encode($req); + return $this->post($url, $body); + } + + /** + * @param array $domains 待获取流量数据的域名数组 + * @param string $startDate 开始的日期,格式类似 2017-01-01 + * @param string $endDate 结束的日期,格式类似 2017-01-01 + * @param string $granularity 获取数据的时间间隔,可以是 5min, hour 或者 day + * + * @return array 流量数据和错误信息,参考 examples/cdn_manager.php 代码 + * + * @link http://developer.qiniu.com/article/fusion/api/traffic-bandwidth.html + */ + public function getFluxData(array $domains, $startDate, $endDate, $granularity) + { + $req = array(); + $req['domains'] = implode(';', $domains); + $req['startDate'] = $startDate; + $req['endDate'] = $endDate; + $req['granularity'] = $granularity; + + $url = $this->server . '/v2/tune/flux'; + $body = json_encode($req); + return $this->post($url, $body); + } + + /** + * @param array $domains 待获取日志下载链接的域名数组 + * @param string $logDate 获取指定日期的日志下载链接,格式类似 2017-01-01 + * + * @return array 日志下载链接数据和错误信息,参考 examples/cdn_manager.php 代码 + * + * @link http://developer.qiniu.com/article/fusion/api/log.html + */ + public function getCdnLogList(array $domains, $logDate) + { + $req = array(); + $req['domains'] = implode(';', $domains); + $req['day'] = $logDate; + + $url = $this->server . '/v2/tune/log/list'; + $body = json_encode($req); + return $this->post($url, $body); + } + + private function post($url, $body) + { + $headers = $this->auth->authorization($url, $body, 'application/json'); + $headers['Content-Type'] = 'application/json'; + $ret = Client::post($url, $body, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = ($ret->body === null) ? array() : $ret->json(); + return array($r, null); + } + + /** + * 构建时间戳防盗链鉴权的访问外链 + * + * @param string $rawUrl 需要签名的资源url + * @param string $encryptKey 时间戳防盗链密钥 + * @param string $durationInSeconds 链接的有效期(以秒为单位) + * + * @return string 带鉴权信息的资源外链,参考 examples/cdn_timestamp_antileech.php 代码 + */ + public static function createTimestampAntiLeechUrl($rawUrl, $encryptKey, $durationInSeconds) + { + $parsedUrl = parse_url($rawUrl); + $deadline = time() + $durationInSeconds; + $expireHex = dechex($deadline); + $path = isset($parsedUrl['path']) ? $parsedUrl['path'] : ''; + $strToSign = $encryptKey . $path . $expireHex; + $signStr = md5($strToSign); + if (isset($parsedUrl['query'])) { + $signedUrl = $rawUrl . '&sign=' . $signStr . '&t=' . $expireHex; + } else { + $signedUrl = $rawUrl . '?sign=' . $signStr . '&t=' . $expireHex; + } + return $signedUrl; + } +} diff --git a/php-sdk/src/Qiniu/Config.php b/php-sdk/src/Qiniu/Config.php new file mode 100644 index 0000000..3ce7fa5 --- /dev/null +++ b/php-sdk/src/Qiniu/Config.php @@ -0,0 +1,398 @@ +zone = $z; + $this->useHTTPS = false; + $this->useCdnDomains = false; + $this->regionCache = array(); + $this->ucHost = Config::UC_HOST; + $this->queryRegionHost = Config::QUERY_REGION_HOST; + $this->backupQueryRegionHosts = array( + "kodo-config.qiniuapi.com", + "uc.qbox.me", + ); + $this->backupUcHostsRetryTimes = 2; + } + + public function setUcHost($ucHost) + { + $this->ucHost = $ucHost; + $this->setQueryRegionHost($ucHost); + } + + public function getUcHost() + { + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return $scheme . $this->ucHost; + } + + public function setQueryRegionHost($host, $backupHosts = array()) + { + $this->queryRegionHost = $host; + $this->backupQueryRegionHosts = $backupHosts; + } + + public function getQueryRegionHost() + { + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return $scheme . $this->queryRegionHost; + } + + public function setBackupQueryRegionHosts($hosts = array()) + { + $this->backupQueryRegionHosts = $hosts; + } + + public function getBackupQueryRegionHosts() + { + return $this->backupQueryRegionHosts; + } + + public function getUpHost($accessKey, $bucket, $reqOpt = null) + { + $region = $this->getRegion($accessKey, $bucket, $reqOpt); + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + $host = $region->srcUpHosts[0]; + if ($this->useCdnDomains === true) { + $host = $region->cdnUpHosts[0]; + } + + return $scheme . $host; + } + + public function getUpHostV2($accessKey, $bucket, $reqOpt = null) + { + list($region, $err) = $this->getRegionV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + $host = $region->srcUpHosts[0]; + if ($this->useCdnDomains === true) { + $host = $region->cdnUpHosts[0]; + } + + return array($scheme . $host, null); + } + + public function getUpBackupHost($accessKey, $bucket, $reqOpt = null) + { + $region = $this->getRegion($accessKey, $bucket, $reqOpt); + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + $host = $region->cdnUpHosts[0]; + if ($this->useCdnDomains === true) { + $host = $region->srcUpHosts[0]; + } + + return $scheme . $host; + } + + public function getUpBackupHostV2($accessKey, $bucket, $reqOpt = null) + { + list($region, $err) = $this->getRegionV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + $host = $region->cdnUpHosts[0]; + if ($this->useCdnDomains === true) { + $host = $region->srcUpHosts[0]; + } + + return array($scheme . $host, null); + } + + public function getRsHost($accessKey, $bucket, $reqOpt = null) + { + $region = $this->getRegion($accessKey, $bucket, $reqOpt); + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return $scheme . $region->rsHost; + } + + public function getRsHostV2($accessKey, $bucket, $reqOpt = null) + { + list($region, $err) = $this->getRegionV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return array($scheme . $region->rsHost, null); + } + + public function getRsfHost($accessKey, $bucket, $reqOpt = null) + { + $region = $this->getRegion($accessKey, $bucket, $reqOpt); + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return $scheme . $region->rsfHost; + } + + public function getRsfHostV2($accessKey, $bucket, $reqOpt = null) + { + list($region, $err) = $this->getRegionV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return array($scheme . $region->rsfHost, null); + } + + public function getIovipHost($accessKey, $bucket, $reqOpt = null) + { + $region = $this->getRegion($accessKey, $bucket, $reqOpt); + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return $scheme . $region->iovipHost; + } + + public function getIovipHostV2($accessKey, $bucket, $reqOpt = null) + { + list($region, $err) = $this->getRegionV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return array($scheme . $region->iovipHost, null); + } + + public function getApiHost($accessKey, $bucket, $reqOpt = null) + { + $region = $this->getRegion($accessKey, $bucket, $reqOpt); + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return $scheme . $region->apiHost; + } + + public function getApiHostV2($accessKey, $bucket, $reqOpt = null) + { + list($region, $err) = $this->getRegionV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return array($scheme . $region->apiHost, null); + } + + + /** + * 从缓存中获取区域 + * + * @param string $cacheId 缓存 ID + * @return null|Region + */ + private function getRegionCache($cacheId) + { + if (isset($this->regionCache[$cacheId]) && + isset($this->regionCache[$cacheId]["deadline"]) && + time() < $this->regionCache[$cacheId]["deadline"]) { + return $this->regionCache[$cacheId]["region"]; + } + + return null; + } + + /** + * 将区域设置到缓存中 + * + * @param string $cacheId 缓存 ID + * @param Region $region 缓存 ID + * @return void + */ + private function setRegionCache($cacheId, $region) + { + $this->regionCache[$cacheId] = array( + "region" => $region, + ); + if (isset($region->ttl)) { + $this->regionCache[$cacheId]["deadline"] = time() + $region->ttl; + } + } + + /** + * 从缓存中获取区域 + * + * @param string $accessKey + * @param string $bucket + * @return Region + * + * @throws \Exception + */ + private function getRegion($accessKey, $bucket, $reqOpt = null) + { + if (isset($this->zone)) { + return $this->zone; + } + + $cacheId = "$accessKey:$bucket"; + $regionCache = $this->getRegionCache($cacheId); + if ($regionCache) { + return $regionCache; + } + + $region = Zone::queryZone( + $accessKey, + $bucket, + $this->getQueryRegionHost(), + $this->getBackupQueryRegionHosts(), + $this->backupUcHostsRetryTimes, + $reqOpt + ); + if (is_array($region)) { + list($region, $err) = $region; + if ($err != null) { + throw new \Exception($err->message()); + } + } + + $this->setRegionCache($cacheId, $region); + return $region; + } + + private function getRegionV2($accessKey, $bucket, $reqOpt = null) + { + if (isset($this->zone)) { + return array($this->zone, null); + } + + $cacheId = "$accessKey:$bucket"; + $regionCache = $this->getRegionCache($cacheId); + if (isset($regionCache)) { + return array($regionCache, null); + } + + $region = Zone::queryZone( + $accessKey, + $bucket, + $this->getQueryRegionHost(), + $this->getBackupQueryRegionHosts(), + $this->backupUcHostsRetryTimes, + $reqOpt + ); + if (is_array($region)) { + list($region, $err) = $region; + return array($region, $err); + } + + $this->setRegionCache($cacheId, $region); + return array($region, null); + } +} diff --git a/php-sdk/src/Qiniu/Enum/QiniuEnum.php b/php-sdk/src/Qiniu/Enum/QiniuEnum.php new file mode 100644 index 0000000..8399b54 --- /dev/null +++ b/php-sdk/src/Qiniu/Enum/QiniuEnum.php @@ -0,0 +1,53 @@ + $val) { + array_push($data, '--' . $mimeBoundary); + array_push($data, "Content-Disposition: form-data; name=\"$key\""); + array_push($data, ''); + array_push($data, $val); + } + + array_push($data, '--' . $mimeBoundary); + $finalMimeType = empty($mimeType) ? 'application/octet-stream' : $mimeType; + $finalFileName = self::escapeQuotes($fileName); + array_push($data, "Content-Disposition: form-data; name=\"$name\"; filename=\"$finalFileName\""); + array_push($data, "Content-Type: $finalMimeType"); + array_push($data, ''); + array_push($data, $fileBody); + + array_push($data, '--' . $mimeBoundary . '--'); + array_push($data, ''); + + $body = implode("\r\n", $data); + $contentType = 'multipart/form-data; boundary=' . $mimeBoundary; + $headers['Content-Type'] = $contentType; + $request = new Request('POST', $url, $headers, $body, $opt); + return self::sendRequest($request); + } + + private static function userAgent() + { + $sdkInfo = "QiniuPHP/" . Config::SDK_VER; + + $systemInfo = php_uname("s"); + $machineInfo = php_uname("m"); + + $envInfo = "($systemInfo/$machineInfo)"; + + $phpVer = phpversion(); + + $ua = "$sdkInfo $envInfo PHP/$phpVer"; + return $ua; + } + + /** + * @param Request $request + * @return Response + */ + public static function sendRequestWithMiddleware($request) + { + $middlewares = $request->opt->middlewares; + $handle = Middleware\compose($middlewares, function ($req) { + return Client::sendRequest($req); + }); + return $handle($request); + } + + /** + * @param Request $request + * @return Response + */ + public static function sendRequest($request) + { + $t1 = microtime(true); + $ch = curl_init(); + $options = array( + CURLOPT_USERAGENT => self::userAgent(), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_NOBODY => false, + CURLOPT_CUSTOMREQUEST => $request->method, + CURLOPT_URL => $request->url, + ); + foreach ($request->opt->getCurlOpt() as $k => $v) { + $options[$k] = $v; + } + // Handle open_basedir & safe mode + if (!ini_get('safe_mode') && !ini_get('open_basedir')) { + $options[CURLOPT_FOLLOWLOCATION] = true; + } + if (!empty($request->headers)) { + $headers = array(); + foreach ($request->headers as $key => $val) { + array_push($headers, "$key: $val"); + } + $options[CURLOPT_HTTPHEADER] = $headers; + } + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); + if (!empty($request->body)) { + $options[CURLOPT_POSTFIELDS] = $request->body; + } + curl_setopt_array($ch, $options); + $result = curl_exec($ch); + $t2 = microtime(true); + $duration = round($t2 - $t1, 3); + $ret = curl_errno($ch); + if ($ret !== 0) { + $r = new Response(-1, $duration, array(), null, curl_error($ch)); + curl_close($ch); + return $r; + } + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $headers = Header::parseRawText(substr($result, 0, $header_size)); + $body = substr($result, $header_size); + curl_close($ch); + return new Response($code, $duration, $headers, $body, null); + } + + private static function escapeQuotes($str) + { + if (is_null($str)) { + return null; + } + $find = array("\\", "\""); + $replace = array("\\\\", "\\\""); + return str_replace($find, $replace, $str); + } +} diff --git a/php-sdk/src/Qiniu/Http/Error.php b/php-sdk/src/Qiniu/Http/Error.php new file mode 100644 index 0000000..8fba74f --- /dev/null +++ b/php-sdk/src/Qiniu/Http/Error.php @@ -0,0 +1,38 @@ + + * {"error" : "detailed error message"} + * + */ +final class Error +{ + private $url; + /** + * @var Response + */ + private $response; + + public function __construct($url, $response) + { + $this->url = $url; + $this->response = $response; + } + + public function code() + { + return $this->response->statusCode; + } + + public function getResponse() + { + return $this->response; + } + + public function message() + { + return $this->response->error; + } +} diff --git a/php-sdk/src/Qiniu/Http/Header.php b/php-sdk/src/Qiniu/Http/Header.php new file mode 100644 index 0000000..1dcf328 --- /dev/null +++ b/php-sdk/src/Qiniu/Http/Header.php @@ -0,0 +1,291 @@ + $values) { + $normalizedKey = self::normalizeKey($key); + $normalizedValues = array(); + if (!is_array($values)) { + array_push( + $normalizedValues, + self::normalizeValue($values) + ); + } else { + foreach ($values as $value) { + array_push( + $normalizedValues, + self::normalizeValue($value) + ); + } + } + $this->data[$normalizedKey] = $normalizedValues; + } + return $this; + } + + /** + * return origin headers, which is field name case-sensitive + * + * @param string $raw + * + * @return array + */ + public static function parseRawText($raw) + { + $multipleHeaders = explode("\r\n\r\n", trim($raw)); + $headers = array(); + $headerLines = explode("\r\n", end($multipleHeaders)); + foreach ($headerLines as $line) { + $headerLine = trim($line); + $kv = explode(':', $headerLine); + if (count($kv) <= 1) { + continue; + } + // for http2 [Pseudo-Header Fields](https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.1) + if ($kv[0] == "") { + $fieldName = ":" . $kv[1]; + } else { + $fieldName = $kv[0]; + } + $fieldValue = trim(substr($headerLine, strlen($fieldName . ":"))); + if (isset($headers[$fieldName])) { + array_push($headers[$fieldName], $fieldValue); + } else { + $headers[$fieldName] = array($fieldValue); + } + } + return $headers; + } + + /** + * @param string $raw + * + * @return Header + */ + public static function fromRawText($raw) + { + return new Header(self::parseRawText($raw)); + } + + /** + * @param string $key + * + * @return string + */ + public static function normalizeKey($key) + { + $key = trim($key); + + if (!self::isValidKeyName($key)) { + return $key; + } + + return \Qiniu\ucwords(strtolower($key), '-'); + } + + /** + * @param string|numeric $value + * + * @return string|numeric + */ + public static function normalizeValue($value) + { + if (is_numeric($value)) { + return $value + 0; + } + return trim($value); + } + + /** + * @return array + */ + public function getRawData() + { + return $this->data; + } + + /** + * @param $offset string + * + * @return boolean + */ + #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x + public function offsetExists($offset) + { + $key = self::normalizeKey($offset); + return isset($this->data[$key]); + } + + /** + * @param $offset string + * + * @return string|null + */ + #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x + public function offsetGet($offset) + { + $key = self::normalizeKey($offset); + if (isset($this->data[$key]) && count($this->data[$key])) { + return $this->data[$key][0]; + } else { + return null; + } + } + + /** + * @param $offset string + * @param $value string + * + * @return void + */ + #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x + public function offsetSet($offset, $value) + { + $key = self::normalizeKey($offset); + if (isset($this->data[$key]) && count($this->data[$key]) > 0) { + $this->data[$key][0] = self::normalizeValue($value); + } else { + $this->data[$key] = array(self::normalizeValue($value)); + } + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x + public function offsetUnset($offset) + { + $key = self::normalizeKey($offset); + unset($this->data[$key]); + } + + /** + * @return \ArrayIterator + */ + #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x + public function getIterator() + { + $arr = array(); + foreach ($this->data as $k => $v) { + $arr[$k] = $v[0]; + } + return new \ArrayIterator($arr); + } + + /** + * @return int + */ + #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x + public function count() + { + return count($this->data); + } + + private static $isTokenTable = array( + '!' => true, + '#' => true, + '$' => true, + '%' => true, + '&' => true, + '\'' => true, + '*' => true, + '+' => true, + '-' => true, + '.' => true, + '0' => true, + '1' => true, + '2' => true, + '3' => true, + '4' => true, + '5' => true, + '6' => true, + '7' => true, + '8' => true, + '9' => true, + 'A' => true, + 'B' => true, + 'C' => true, + 'D' => true, + 'E' => true, + 'F' => true, + 'G' => true, + 'H' => true, + 'I' => true, + 'J' => true, + 'K' => true, + 'L' => true, + 'M' => true, + 'N' => true, + 'O' => true, + 'P' => true, + 'Q' => true, + 'R' => true, + 'S' => true, + 'T' => true, + 'U' => true, + 'W' => true, + 'V' => true, + 'X' => true, + 'Y' => true, + 'Z' => true, + '^' => true, + '_' => true, + '`' => true, + 'a' => true, + 'b' => true, + 'c' => true, + 'd' => true, + 'e' => true, + 'f' => true, + 'g' => true, + 'h' => true, + 'i' => true, + 'j' => true, + 'k' => true, + 'l' => true, + 'm' => true, + 'n' => true, + 'o' => true, + 'p' => true, + 'q' => true, + 'r' => true, + 's' => true, + 't' => true, + 'u' => true, + 'v' => true, + 'w' => true, + 'x' => true, + 'y' => true, + 'z' => true, + '|' => true, + '~' => true, + ); + + /** + * @param string $str + * + * @return boolean + */ + private static function isValidKeyName($str) + { + for ($i = 0; $i < strlen($str); $i += 1) { + if (!isset(self::$isTokenTable[$str[$i]])) { + return false; + } + } + return true; + } +} diff --git a/php-sdk/src/Qiniu/Http/Middleware/Middleware.php b/php-sdk/src/Qiniu/Http/Middleware/Middleware.php new file mode 100644 index 0000000..fe8a64c --- /dev/null +++ b/php-sdk/src/Qiniu/Http/Middleware/Middleware.php @@ -0,0 +1,31 @@ + $middlewares + * @param callable(Request): Response $handler + * @return callable(Request): Response + */ +function compose($middlewares, $handler) +{ + $next = $handler; + foreach (array_reverse($middlewares) as $middleware) { + $next = function ($request) use ($middleware, $next) { + return $middleware->send($request, $next); + }; + } + return $next; +} diff --git a/php-sdk/src/Qiniu/Http/Middleware/RetryDomainsMiddleware.php b/php-sdk/src/Qiniu/Http/Middleware/RetryDomainsMiddleware.php new file mode 100644 index 0000000..829ab87 --- /dev/null +++ b/php-sdk/src/Qiniu/Http/Middleware/RetryDomainsMiddleware.php @@ -0,0 +1,76 @@ + backup domains. + */ + private $backupDomains; + + /** + * @var numeric max retry times for each backup domains. + */ + private $maxRetryTimes; + + /** + * @var callable args response and request; returns bool; If true will retry with backup domains. + */ + private $retryCondition; + + /** + * @param array $backupDomains + * @param numeric $maxRetryTimes + */ + public function __construct($backupDomains, $maxRetryTimes = 2, $retryCondition = null) + { + $this->backupDomains = $backupDomains; + $this->maxRetryTimes = $maxRetryTimes; + $this->retryCondition = $retryCondition; + } + + private function shouldRetry($resp, $req) + { + if (is_callable($this->retryCondition)) { + return call_user_func($this->retryCondition, $resp, $req); + } + + return !$resp || $resp->needRetry(); + } + + /** + * @param Request $request + * @param callable(Request): Response $next + * @return Response + */ + public function send($request, $next) + { + $response = null; + $urlComponents = parse_url($request->url); + + foreach (array_merge(array($urlComponents["host"]), $this->backupDomains) as $backupDomain) { + $urlComponents["host"] = $backupDomain; + $request->url = \Qiniu\unparse_url($urlComponents); + $retriedTimes = 0; + + while ($retriedTimes < $this->maxRetryTimes) { + $response = $next($request); + + $retriedTimes += 1; + + if (!$this->shouldRetry($response, $request)) { + return $response; + } + } + } + + if (!$response) { + $response = $next($request); + } + + return $response; + } +} diff --git a/php-sdk/src/Qiniu/Http/Proxy.php b/php-sdk/src/Qiniu/Http/Proxy.php new file mode 100644 index 0000000..fac6ba1 --- /dev/null +++ b/php-sdk/src/Qiniu/Http/Proxy.php @@ -0,0 +1,34 @@ +proxy = $proxy; + $this->proxy_auth = $proxy_auth; + $this->proxy_user_password = $proxy_user_password; + } + + public function makeReqOpt() + { + $reqOpt = new RequestOptions(); + if ($this->proxy !== null) { + $reqOpt->proxy = $this->proxy; + } + if ($this->proxy_auth !== null) { + $reqOpt->proxy_auth = $this->proxy_auth; + } + if ($this->proxy_user_password !== null) { + $reqOpt->proxy_user_password = $this->proxy_user_password; + } + return $reqOpt; + } +} diff --git a/php-sdk/src/Qiniu/Http/Request.php b/php-sdk/src/Qiniu/Http/Request.php new file mode 100644 index 0000000..5a31bf6 --- /dev/null +++ b/php-sdk/src/Qiniu/Http/Request.php @@ -0,0 +1,42 @@ + + */ + public $headers; + + /** + * @var mixed|null + */ + public $body; + + /** + * @var string + */ + public $method; + + /** + * @var RequestOptions + */ + public $opt; + + public function __construct($method, $url, array $headers = array(), $body = null, $opt = null) + { + $this->method = strtoupper($method); + $this->url = $url; + $this->headers = $headers; + $this->body = $body; + if ($opt === null) { + $opt = new RequestOptions(); + } + $this->opt = $opt; + } +} diff --git a/php-sdk/src/Qiniu/Http/RequestOptions.php b/php-sdk/src/Qiniu/Http/RequestOptions.php new file mode 100644 index 0000000..be0c6d5 --- /dev/null +++ b/php-sdk/src/Qiniu/Http/RequestOptions.php @@ -0,0 +1,104 @@ + + */ + public $middlewares; + + public function __construct( + $connection_timeout = null, + $connection_timeout_ms = null, + $timeout = null, + $timeout_ms = null, + $middlewares = array(), + $proxy = null, + $proxy_auth = null, + $proxy_user_password = null + ) { + $this->connection_timeout = $connection_timeout; + $this->connection_timeout_ms = $connection_timeout_ms; + $this->timeout = $timeout; + $this->timeout_ms = $timeout_ms; + $this->proxy = $proxy; + $this->proxy_auth = $proxy_auth; + $this->proxy_user_password = $proxy_user_password; + $this->middlewares = $middlewares; + } + + public function getCurlOpt() + { + $result = array(); + if ($this->connection_timeout != null) { + $result[CURLOPT_CONNECTTIMEOUT] = $this->connection_timeout; + } + if ($this->connection_timeout_ms != null) { + $result[CURLOPT_CONNECTTIMEOUT_MS] = $this->connection_timeout_ms; + } + if ($this->timeout != null) { + $result[CURLOPT_TIMEOUT] = $this->timeout; + } + if ($this->timeout_ms != null) { + $result[CURLOPT_TIMEOUT_MS] = $this->timeout_ms; + } + if ($this->proxy != null) { + $result[CURLOPT_PROXY] = $this->proxy; + } + if ($this->proxy_auth != null) { + $result[CURLOPT_PROXYAUTH] = $this->proxy_auth; + } + if ($this->proxy_user_password != null) { + $result[CURLOPT_PROXYUSERPWD] = $this->proxy_user_password; + } + return $result; + } +} diff --git a/php-sdk/src/Qiniu/Http/Response.php b/php-sdk/src/Qiniu/Http/Response.php new file mode 100644 index 0000000..cd77903 --- /dev/null +++ b/php-sdk/src/Qiniu/Http/Response.php @@ -0,0 +1,220 @@ + 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-Status', + 208 => 'Already Reported', + 226 => 'IM Used', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 307 => 'Temporary Redirect', + 308 => 'Permanent Redirect', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 422 => 'Unprocessable Entity', + 423 => 'Locked', + 424 => 'Failed Dependency', + 425 => 'Reserved for WebDAV advanced collections expired proposal', + 426 => 'Upgrade required', + 428 => 'Precondition Required', + 429 => 'Too Many Requests', + 431 => 'Request Header Fields Too Large', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates (Experimental)', + 507 => 'Insufficient Storage', + 508 => 'Loop Detected', + 510 => 'Not Extended', + 511 => 'Network Authentication Required', + ); + + /** + * @param int $code 状态码 + * @param double $duration 请求时长 + * @param array $headers 响应头部 + * @param string $body 响应内容 + * @param string $error 错误描述 + */ + public function __construct($code, $duration, array $headers = array(), $body = null, $error = null) + { + $this->statusCode = $code; + $this->duration = $duration; + $this->headers = array(); + $this->body = $body; + $this->error = $error; + $this->jsonData = null; + + if ($error !== null) { + return; + } + + foreach ($headers as $k => $vs) { + if (is_array($vs)) { + $this->headers[$k] = $vs[count($vs) - 1]; + } else { + $this->headers[$k] = $vs; + } + } + $this->normalizedHeaders = new Header($headers); + + if ($body === null) { + if ($code >= 400) { + $this->error = self::$statusTexts[$code]; + } + return; + } + if (self::isJson($this->normalizedHeaders)) { + try { + $jsonData = self::bodyJson($body); + if ($code >= 400) { + $this->error = $body; + if ($jsonData['error'] !== null) { + $this->error = $jsonData['error']; + } + } + $this->jsonData = $jsonData; + } catch (\InvalidArgumentException $e) { + $this->error = $body; + if ($code >= 200 && $code < 300) { + $this->error = $e->getMessage(); + } + } + } elseif ($code >= 400) { + $this->error = $body; + } + return; + } + + public function json() + { + return $this->jsonData; + } + + public function headers($normalized = false) + { + if ($normalized) { + return $this->normalizedHeaders; + } + return $this->headers; + } + + public function body() + { + return $this->body; + } + + private static function bodyJson($body) + { + return \Qiniu\json_decode((string) $body, true, 512); + } + + public function xVia() + { + $via = $this->normalizedHeaders['X-Via']; + if ($via === null) { + $via = $this->normalizedHeaders['X-Px']; + } + if ($via === null) { + $via = $this->normalizedHeaders['Fw-Via']; + } + return $via; + } + + public function xLog() + { + return $this->normalizedHeaders['X-Log']; + } + + public function xReqId() + { + return $this->normalizedHeaders['X-Reqid']; + } + + public function ok() + { + return $this->statusCode >= 200 && $this->statusCode < 300 && $this->error === null; + } + + public function needRetry() + { + if ($this->statusCode > 0 && $this->statusCode < 500) { + return false; + } + + // https://developer.qiniu.com/fusion/kb/1352/the-http-request-return-a-status-code + if (in_array($this->statusCode, array( + 501, 509, 573, 579, 608, 612, 614, 616, 618, 630, 631, 632, 640, 701 + ))) { + return false; + } + + return true; + } + + private static function isJson($headers) + { + return isset($headers['Content-Type']) && strpos($headers['Content-Type'], 'application/json') === 0; + } +} diff --git a/php-sdk/src/Qiniu/Processing/ImageUrlBuilder.php b/php-sdk/src/Qiniu/Processing/ImageUrlBuilder.php new file mode 100644 index 0000000..f5575ed --- /dev/null +++ b/php-sdk/src/Qiniu/Processing/ImageUrlBuilder.php @@ -0,0 +1,292 @@ + + */ + public function thumbnail( + $url, + $mode, + $width, + $height, + $format = null, + $interlace = null, + $quality = null, + $ignoreError = 1 + ) { + + // url合法效验 + if (!$this->isUrl($url)) { + return $url; + } + + // 参数合法性效验 + if (!in_array(intval($mode), $this->modeArr, true)) { + return $url; + } + + if (!$width || !$height) { + return $url; + } + + $thumbStr = 'imageView2/' . $mode . '/w/' . $width . '/h/' . $height . '/'; + + // 拼接输出格式 + if (!is_null($format) + && in_array($format, $this->formatArr) + ) { + $thumbStr .= 'format/' . $format . '/'; + } + + // 拼接渐进显示 + if (!is_null($interlace) + && in_array(intval($interlace), array(0, 1), true) + ) { + $thumbStr .= 'interlace/' . $interlace . '/'; + } + + // 拼接图片质量 + if (!is_null($quality) + && intval($quality) >= 0 + && intval($quality) <= 100 + ) { + $thumbStr .= 'q/' . $quality . '/'; + } + + $thumbStr .= 'ignore-error/' . $ignoreError . '/'; + + // 如果有query_string用|线分割实现多参数 + return $url . ($this->hasQuery($url) ? '|' : '?') . $thumbStr; + } + + /** + * 图片水印 + * + * @param string $url 图片链接 + * @param string $image 水印图片链接 + * @param int $dissolve 透明度 + * @param string $gravity 水印位置 + * @param int $dx 横轴边距 + * @param int $dy 纵轴边距 + * @param int $watermarkScale 自适应原图的短边比例 + * @return string + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html + * @author Sherlock Ren + */ + public function waterImg( + $url, + $image, + $dissolve = 100, + $gravity = 'SouthEast', + $dx = null, + $dy = null, + $watermarkScale = null + ) { + // url合法效验 + if (!$this->isUrl($url)) { + return $url; + } + + $waterStr = 'watermark/1/image/' . \Qiniu\base64_urlSafeEncode($image) . '/'; + + // 拼接水印透明度 + if (is_numeric($dissolve) + && $dissolve <= 100 + ) { + $waterStr .= 'dissolve/' . $dissolve . '/'; + } + + // 拼接水印位置 + if (in_array($gravity, $this->gravityArr, true)) { + $waterStr .= 'gravity/' . $gravity . '/'; + } + + // 拼接横轴边距 + if (!is_null($dx) + && is_numeric($dx) + ) { + $waterStr .= 'dx/' . $dx . '/'; + } + + // 拼接纵轴边距 + if (!is_null($dy) + && is_numeric($dy) + ) { + $waterStr .= 'dy/' . $dy . '/'; + } + + // 拼接自适应原图的短边比例 + if (!is_null($watermarkScale) + && is_numeric($watermarkScale) + && $watermarkScale > 0 + && $watermarkScale < 1 + ) { + $waterStr .= 'ws/' . $watermarkScale . '/'; + } + + // 如果有query_string用|线分割实现多参数 + return $url . ($this->hasQuery($url) ? '|' : '?') . $waterStr; + } + + /** + * 文字水印 + * + * @param string $url 图片链接 + * @param string $text 文字 + * @param string $font 文字字体 + * @param string $fontSize 文字字号 + * @param string $fontColor 文字颜色 + * @param int $dissolve 透明度 + * @param string $gravity 水印位置 + * @param int $dx 横轴边距 + * @param int $dy 纵轴边距 + * @return string + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html#text-watermark + * @author Sherlock Ren + */ + public function waterText( + $url, + $text, + $font = '黑体', + $fontSize = 0, + $fontColor = null, + $dissolve = 100, + $gravity = 'SouthEast', + $dx = null, + $dy = null + ) { + // url合法效验 + if (!$this->isUrl($url)) { + return $url; + } + + $waterStr = 'watermark/2/text/' + . \Qiniu\base64_urlSafeEncode($text) . '/font/' + . \Qiniu\base64_urlSafeEncode($font) . '/'; + + // 拼接文字大小 + if (is_int($fontSize)) { + $waterStr .= 'fontsize/' . $fontSize . '/'; + } + + // 拼接文字颜色 + if (!is_null($fontColor) + && $fontColor + ) { + $waterStr .= 'fill/' . \Qiniu\base64_urlSafeEncode($fontColor) . '/'; + } + + // 拼接水印透明度 + if (is_numeric($dissolve) + && $dissolve <= 100 + ) { + $waterStr .= 'dissolve/' . $dissolve . '/'; + } + + // 拼接水印位置 + if (in_array($gravity, $this->gravityArr, true)) { + $waterStr .= 'gravity/' . $gravity . '/'; + } + + // 拼接横轴边距 + if (!is_null($dx) + && is_numeric($dx) + ) { + $waterStr .= 'dx/' . $dx . '/'; + } + + // 拼接纵轴边距 + if (!is_null($dy) + && is_numeric($dy) + ) { + $waterStr .= 'dy/' . $dy . '/'; + } + + // 如果有query_string用|线分割实现多参数 + return $url . ($this->hasQuery($url) ? '|' : '?') . $waterStr; + } + + /** + * 效验url合法性 + * + * @param string $url url链接 + * @return string + * @author Sherlock Ren + */ + protected function isUrl($url) + { + $urlArr = parse_url($url); + + return $urlArr['scheme'] + && in_array($urlArr['scheme'], array('http', 'https')) + && $urlArr['host'] + && $urlArr['path']; + } + + /** + * 检测是否有query + * + * @param string $url url链接 + * @return string + * @author Sherlock Ren + */ + protected function hasQuery($url) + { + $urlArr = parse_url($url); + + return !empty($urlArr['query']); + } +} diff --git a/php-sdk/src/Qiniu/Processing/Operation.php b/php-sdk/src/Qiniu/Processing/Operation.php new file mode 100644 index 0000000..839703c --- /dev/null +++ b/php-sdk/src/Qiniu/Processing/Operation.php @@ -0,0 +1,69 @@ +auth = $auth; + $this->domain = $domain; + $this->token_expire = $token_expire; + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + + /** + * 对资源文件进行处理 + * + * @param string $key 待处理的资源文件名 + * @param string $fops string|array fop操作,多次fop操作以array的形式传入。 + * eg. imageView2/1/w/200/h/200, imageMogr2/thumbnail/!75px + * + * @return array 文件处理后的结果及错误。 + * + * @link http://developer.qiniu.com/docs/v6/api/reference/fop/ + */ + public function execute($key, $fops) + { + $url = $this->buildUrl($key, $fops); + $resp = Client::get($url, array(), $this->proxy->makeReqOpt()); + if (!$resp->ok()) { + return array(null, new Error($url, $resp)); + } + if ($resp->json() !== null) { + return array($resp->json(), null); + } + return array($resp->body, null); + } + + public function buildUrl($key, $fops, $protocol = 'http') + { + if (is_array($fops)) { + $fops = implode('|', $fops); + } + + $url = $protocol . "://$this->domain/$key?$fops"; + if ($this->auth !== null) { + $url = $this->auth->privateDownloadUrl($url, $this->token_expire); + } + + return $url; + } +} diff --git a/php-sdk/src/Qiniu/Processing/PersistentFop.php b/php-sdk/src/Qiniu/Processing/PersistentFop.php new file mode 100644 index 0000000..8dca4a9 --- /dev/null +++ b/php-sdk/src/Qiniu/Processing/PersistentFop.php @@ -0,0 +1,135 @@ +auth = $auth; + if ($config == null) { + $this->config = new Config(); + } else { + $this->config = $config; + } + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + /** + * 对资源文件进行异步持久化处理 + * @param string $bucket 资源所在空间 + * @param string $key 待处理的源文件 + * @param string|array $fops 待处理的pfop操作,多个pfop操作以array的形式传入。 + * eg. avthumb/mp3/ab/192k, vframe/jpg/offset/7/w/480/h/360 + * @param string $pipeline 资源处理队列 + * @param string $notify_url 处理结果通知地址 + * @param bool $force 是否强制执行一次新的指令 + * @param int $type 为 `1` 时开启闲时任务 + * + * + * @return array 返回持久化处理的 persistentId 与可能出现的错误。 + * + * @link http://developer.qiniu.com/docs/v6/api/reference/fop/ + */ + public function execute( + $bucket, + $key, + $fops = null, + $pipeline = null, + $notify_url = null, + $force = false, + $type = null, + $workflow_template_id = null + ) { + if (is_array($fops)) { + $fops = implode(';', $fops); + } + + if (!$fops && !$workflow_template_id) { + throw new \InvalidArgumentException('Must provide one of fops or template_id'); + } + + $params = array('bucket' => $bucket, 'key' => $key); + \Qiniu\setWithoutEmpty($params, 'fops', $fops); + \Qiniu\setWithoutEmpty($params, 'pipeline', $pipeline); + \Qiniu\setWithoutEmpty($params, 'notifyURL', $notify_url); + \Qiniu\setWithoutEmpty($params, 'type', $type); + \Qiniu\setWithoutEmpty($params, 'workflowTemplateID', $workflow_template_id); + if ($force) { + $params['force'] = 1; + } + $data = http_build_query($params); + $scheme = "http://"; + if ($this->config->useHTTPS === true) { + $scheme = "https://"; + } + $apiHost = $this->getApiHost(); + $url = $scheme . $apiHost . '/pfop/'; + $headers = $this->auth->authorization($url, $data, 'application/x-www-form-urlencoded'); + $headers['Content-Type'] = 'application/x-www-form-urlencoded'; + $response = Client::post($url, $data, $headers, $this->proxy->makeReqOpt()); + if (!$response->ok()) { + return array(null, new Error($url, $response)); + } + $r = $response->json(); + $id = $r['persistentId']; + return array($id, null); + } + + /** + * @param string $id + * @return array 返回任务状态与可能出现的错误 + */ + public function status($id) + { + $scheme = "http://"; + + if ($this->config->useHTTPS === true) { + $scheme = "https://"; + } + $apiHost = $this->getApiHost(); + $url = $scheme . $apiHost . "/status/get/prefop?id=$id"; + $response = Client::get($url, array(), $this->proxy->makeReqOpt()); + if (!$response->ok()) { + return array(null, new Error($url, $response)); + } + return array($response->json(), null); + } + + private function getApiHost() + { + if (!empty($this->config->zone) && !empty($this->config->zone->apiHost)) { + $apiHost = $this->config->zone->apiHost; + } else { + $apiHost = Config::API_HOST; + } + return $apiHost; + } +} diff --git a/php-sdk/src/Qiniu/Region.php b/php-sdk/src/Qiniu/Region.php new file mode 100644 index 0000000..220a5a3 --- /dev/null +++ b/php-sdk/src/Qiniu/Region.php @@ -0,0 +1,229 @@ +srcUpHosts = $srcUpHosts; + $this->cdnUpHosts = $cdnUpHosts; + $this->rsHost = $rsHost; + $this->rsfHost = $rsfHost; + $this->apiHost = $apiHost; + $this->iovipHost = $iovipHost; + $this->ttl = $ttl; + } + + //华东机房 + public static function regionHuadong() + { + $regionHuadong = new Region( + array("up.qiniup.com"), + array('upload.qiniup.com'), + 'rs-z0.qiniuapi.com', + 'rsf-z0.qiniuapi.com', + 'api.qiniuapi.com', + 'iovip.qbox.me' + ); + return $regionHuadong; + } + + //华东机房内网上传 + public static function qvmRegionHuadong() + { + $qvmRegionHuadong = new Region( + array("free-qvm-z0-xs.qiniup.com"), + 'rs-z0.qiniuapi.com', + 'rsf-z0.qiniuapi.com', + 'api.qiniuapi.com', + 'iovip.qbox.me' + ); + return $qvmRegionHuadong; + } + + //华北机房内网上传 + public static function qvmRegionHuabei() + { + $qvmRegionHuabei = new Region( + array("free-qvm-z1-zz.qiniup.com"), + "rs-z1.qiniuapi.com", + "rsf-z1.qiniuapi.com", + "api-z1.qiniuapi.com", + "iovip-z1.qbox.me" + ); + return $qvmRegionHuabei; + } + + //华北机房 + public static function regionHuabei() + { + $regionHuabei = new Region( + array('up-z1.qiniup.com'), + array('upload-z1.qiniup.com'), + "rs-z1.qiniuapi.com", + "rsf-z1.qiniuapi.com", + "api-z1.qiniuapi.com", + "iovip-z1.qbox.me" + ); + + return $regionHuabei; + } + + //华南机房 + public static function regionHuanan() + { + $regionHuanan = new Region( + array('up-z2.qiniup.com'), + array('upload-z2.qiniup.com'), + "rs-z2.qiniuapi.com", + "rsf-z2.qiniuapi.com", + "api-z2.qiniuapi.com", + "iovip-z2.qbox.me" + ); + return $regionHuanan; + } + + //华东2 机房 + public static function regionHuadong2() + { + return new Region( + array('up-cn-east-2.qiniup.com'), + array('upload-cn-east-2.qiniup.com'), + "rs-cn-east-2.qiniuapi.com", + "rsf-cn-east-2.qiniuapi.com", + "api-cn-east-2.qiniuapi.com", + "iovip-cn-east-2.qiniuio.com" + ); + } + + //北美机房 + public static function regionNorthAmerica() + { + //北美机房 + $regionNorthAmerica = new Region( + array('up-na0.qiniup.com'), + array('upload-na0.qiniup.com'), + "rs-na0.qiniuapi.com", + "rsf-na0.qiniuapi.com", + "api-na0.qiniuapi.com", + "iovip-na0.qbox.me" + ); + return $regionNorthAmerica; + } + + //新加坡机房 + public static function regionSingapore() + { + //新加坡机房 + $regionSingapore = new Region( + array('up-as0.qiniup.com'), + array('upload-as0.qiniup.com'), + "rs-as0.qiniuapi.com", + "rsf-as0.qiniuapi.com", + "api-as0.qiniuapi.com", + "iovip-as0.qbox.me" + ); + return $regionSingapore; + } + + /* + * GET /v4/query?ak=&bucket= + * @param string $ak + * @param string $bucket + * @param string $ucHost|null + * @param array $backupUcHosts + * @param int $retryTimes + * @param RequestOptions|null $reqOpt + * @return Response + **/ + public static function queryRegion( + $ak, + $bucket, + $ucHost = null, + $backupUcHosts = array(), + $retryTimes = 2, + $reqOpt = null + ) { + $region = new Region(); + if (!$ucHost) { + $ucHost = "https://" . Config::QUERY_REGION_HOST; + } + $url = $ucHost . '/v4/query' . "?ak=$ak&bucket=$bucket"; + if ($reqOpt == null) { + $reqOpt = new RequestOptions(); + } + $reqOpt->middlewares = array( + new RetryDomainsMiddleware( + $backupUcHosts, + $retryTimes + ) + ); + $ret = Client::get($url, array(), $reqOpt); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = ($ret->body === null) ? array() : $ret->json(); + if (!is_array($r["hosts"]) || count($r["hosts"]) == 0) { + return array(null, new Error($url, $ret)); + } + + // parse region; + $regionHost = $r["hosts"][0]; + $region->cdnUpHosts = array_merge($region->cdnUpHosts, $regionHost['up']['domains']); + $region->srcUpHosts = array_merge($region->srcUpHosts, $regionHost['up']['domains']); + + // set specific hosts + $region->iovipHost = $regionHost['io']['domains'][0]; + if (isset($regionHost['rs']['domains']) && count($regionHost['rs']['domains']) > 0) { + $region->rsHost = $regionHost['rs']['domains'][0]; + } else { + $region->rsHost = Config::RS_HOST; + } + if (isset($regionHost['rsf']['domains']) && count($regionHost['rsf']['domains']) > 0) { + $region->rsfHost = $regionHost['rsf']['domains'][0]; + } else { + $region->rsfHost = Config::RSF_HOST; + } + if (isset($regionHost['api']['domains']) && count($regionHost['api']['domains']) > 0) { + $region->apiHost = $regionHost['api']['domains'][0]; + } else { + $region->apiHost = Config::API_HOST; + } + + // set ttl + $region->ttl = $regionHost['ttl']; + + return $region; + } +} diff --git a/php-sdk/src/Qiniu/Rtc/AppClient.php b/php-sdk/src/Qiniu/Rtc/AppClient.php new file mode 100644 index 0000000..3f245db --- /dev/null +++ b/php-sdk/src/Qiniu/Rtc/AppClient.php @@ -0,0 +1,236 @@ +auth = $auth; + $this->baseURL = sprintf("%s/%s/apps", Config::RTCAPI_HOST, Config::RTCAPI_VERSION); + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + /** + * 创建应用 + * + * @param string $hub 绑定的直播 hub + * @param string $title app 的名称 注意,Title 不是唯一标识,重复 create 动作将生成多个 app + * @param int $maxUsers 连麦房间支持的最大在线人数 + * @param bool $noAutoKickUser 禁止自动踢人(抢流),默认为 false + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_1 + */ + public function createApp($hub, $title, $maxUsers = null, $noAutoKickUser = null) + { + $params = array(); + $params['hub'] = $hub; + $params['title'] = $title; + if (!empty($maxUsers)) { + $params['maxUsers'] = $maxUsers; + } + if ($noAutoKickUser !== null) { + $params['noAutoKickUser'] = $noAutoKickUser; + } + $body = json_encode($params); + return $this->post($this->baseURL, $body); + } + + /** + * 更新一个应用的配置信息 + * + * @param string $appId app 的唯一标识,创建的时候由系统生成 + * @param string $hub app 的名称,可选 + * @param string $title 绑定的直播 hub,可选,用于合流后 rtmp 推流 + * @param int $maxUsers 连麦房间支持的最大在线人数,可选 + * @param bool $noAutoKickUser 禁止自动踢人,可选 + * @param null $mergePublishRtmp 连麦合流转推 RTMP 的配置,可选择。其详细配置可以参考文档 + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_1 + */ + public function updateApp($appId, $hub, $title, $maxUsers = null, $noAutoKickUser = null, $mergePublishRtmp = null) + { + $url = $this->baseURL . '/' . $appId; + $params = array(); + $params['hub'] = $hub; + $params['title'] = $title; + if (!empty($maxUsers)) { + $params['maxUsers'] = $maxUsers; + } + if ($noAutoKickUser !== null) { + $params['noAutoKickUser'] = $noAutoKickUser; + } + if (!empty($mergePublishRtmp)) { + $params['mergePublishRtmp'] = $mergePublishRtmp; + } + $body = json_encode($params); + return $this->post($url, $body); + } + + /** + * 获取应用信息 + * + * @param string $appId + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_1 + */ + public function getApp($appId) + { + $url = $this->baseURL . '/' . $appId; + return $this->get($url); + } + + /** + * 删除应用 + * + * @param string $appId app 的唯一标识,创建的时候由系统生成 + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_1 + */ + public function deleteApp($appId) + { + $url = $this->baseURL . '/' . $appId; + return $this->delete($url); + } + + /** + * 获取房间内用户列表 + * + * @param string $appId app 的唯一标识,创建的时候由系统生成 + * @param string $roomName 操作所查询的连麦房间 + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_2 + */ + public function listUser($appId, $roomName) + { + $url = sprintf("%s/%s/rooms/%s/users", $this->baseURL, $appId, $roomName); + return $this->get($url); + } + + /** + * 指定一个用户踢出房间 + * + * @param string $appId app 的唯一标识,创建的时候由系统生成 + * @param string $roomName 连麦房间 + * @param string $userId 操作所剔除的用户 + * @return mixed + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_2 + */ + public function kickUser($appId, $roomName, $userId) + { + $url = sprintf("%s/%s/rooms/%s/users/%s", $this->baseURL, $appId, $roomName, $userId); + return $this->delete($url); + } + + /** + * 停止一个房间的合流转推 + * + * @param string $appId + * @param string $roomName + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_2 + */ + public function stopMerge($appId, $roomName) + { + $url = sprintf("%s/%s/rooms/%s/merge", $this->baseURL, $appId, $roomName); + return $this->delete($url); + } + + /** + * 获取应用中活跃房间 + * + * @param string $appId 连麦房间所属的 app + * @param null $prefix 所查询房间名的前缀索引,可以为空。 + * @param int $offset 分页查询的位移标记 + * @param int $limit 此次查询的最大长度 + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_2 + */ + public function listActiveRooms($appId, $prefix = null, $offset = null, $limit = null) + { + $query = array(); + if (isset($prefix)) { + $query['prefix'] = $prefix; + } + if (isset($offset)) { + $query['offset'] = $offset; + } + if (isset($limit)) { + $query['limit'] = $limit; + } + if (isset($query) && !empty($query)) { + $query = '?' . http_build_query($query); + $url = sprintf("%s/%s/rooms%s", $this->baseURL, $appId, $query); + } else { + $url = sprintf("%s/%s/rooms", $this->baseURL, $appId); + } + return $this->get($url); + } + + /** + * 生成加入房间的令牌 + * + * @param string $appId app 的唯一标识,创建的时候由系统生成 + * @param string $roomName 房间名称,需满足规格 ^[a-zA-Z0-9_-]{3,64}$ + * @param string $userId 请求加入房间的用户 ID,需满足规格 ^[a-zA-Z0-9_-]{3,50}$ + * @param int $expireAt 鉴权的有效时间,传入以秒为单位的64位 Unix 绝对时间 + * @param string $permission 该用户的房间管理权限,"admin" 或 "user",默认为 "user" + * @return string + * @link https://doc.qnsdk.com/rtn/docs/server_overview#1 + */ + public function appToken($appId, $roomName, $userId, $expireAt, $permission) + { + $params = array(); + $params['appId'] = $appId; + $params['userId'] = $userId; + $params['roomName'] = $roomName; + $params['permission'] = $permission; + $params['expireAt'] = $expireAt; + $appAccessString = json_encode($params); + return $this->auth->signWithData($appAccessString); + } + + private function get($url, $cType = null) + { + $rtcToken = $this->auth->authorizationV2($url, "GET", null, $cType); + $rtcToken['Content-Type'] = $cType; + $ret = Client::get($url, $rtcToken, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + return array($ret->json(), null); + } + + private function delete($url, $contentType = 'application/json') + { + $rtcToken = $this->auth->authorizationV2($url, "DELETE", null, $contentType); + $rtcToken['Content-Type'] = $contentType; + $ret = Client::delete($url, $rtcToken, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + return array($ret->json(), null); + } + + private function post($url, $body, $contentType = 'application/json') + { + $rtcToken = $this->auth->authorizationV2($url, "POST", $body, $contentType); + $rtcToken['Content-Type'] = $contentType; + $ret = Client::post($url, $body, $rtcToken, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = ($ret->body === null) ? array() : $ret->json(); + return array($r, null); + } +} diff --git a/php-sdk/src/Qiniu/Sms/Sms.php b/php-sdk/src/Qiniu/Sms/Sms.php new file mode 100644 index 0000000..c96409b --- /dev/null +++ b/php-sdk/src/Qiniu/Sms/Sms.php @@ -0,0 +1,382 @@ +auth = $auth; + $this->baseURL = sprintf("%s/%s/", Config::SMS_HOST, Config::SMS_VERSION); + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + /** + * 创建签名 + * + * @param string $signature 签名 + * @param string $source 签名来源,申请签名时必须指定签名来源 + * @param string $pics 签名对应的资质证明图片进行 base64 编码格式转换后的字符串,可选 + * @return array + * + * @link https://developer.qiniu.com/sms/api/5844/sms-api-create-signature + */ + public function createSignature($signature, $source, $pics = null) + { + $params = array(); + $params['signature'] = $signature; + $params['source'] = $source; + if (!empty($pics)) { + $params['pics'] = array($this->imgToBase64($pics)); + } + $body = json_encode($params); + $url = $this->baseURL . 'signature'; + return $this->post($url, $body); + } + + /** + * 编辑签名 + * + * @param string $id 签名 ID + * @param string $signature 签名 + * @param string $source 签名来源 + * @param string $pics 签名对应的资质证明图片进行 base64 编码格式转换后的字符串,可选 + * @return array + * @link https://developer.qiniu.com/sms/api/5890/sms-api-edit-signature + */ + public function updateSignature($id, $signature, $source, $pics = null) + { + $params = array(); + $params['signature'] = $signature; + $params['source'] = $source; + if (!empty($pics)) { + $params['pics'] = array($this->imgToBase64($pics)); + } + $body = json_encode($params); + $url = $this->baseURL . 'signature/' . $id; + return $this->PUT($url, $body); + } + + /** + * 列出签名 + * + * @param string $audit_status 审核状态:"passed"(通过), "rejected"(未通过), "reviewing"(审核中) + * @param int $page 页码。默认为 1 + * @param int $page_size 分页大小。默认为 20 + * @return array + * @link https://developer.qiniu.com/sms/api/5889/sms-api-query-signature + */ + public function querySignature($audit_status = null, $page = 1, $page_size = 20) + { + + $url = sprintf( + "%s?audit_status=%s&page=%s&page_size=%s", + $this->baseURL . 'signature', + $audit_status, + $page, + $page_size + ); + return $this->get($url); + } + + /** + * 查询单个签名 + * + * @param string $signature_id + * @return array + * @link https://developer.qiniu.com/sms/api/5970/query-a-single-signature + */ + public function checkSingleSignature($signature_id) + { + + $url = sprintf( + "%s/%s", + $this->baseURL . 'signature', + $signature_id + ); + return $this->get($url); + } + + /** + * 删除签名 + * + * @param string $signature_id 签名 ID + * @return array + * @link https://developer.qiniu.com/sms/api/5891/sms-api-delete-signature + */ + public function deleteSignature($signature_id) + { + $url = $this->baseURL . 'signature/' . $signature_id; + return $this->delete($url); + } + + /** + * 创建模板 + * + * @param string $name 模板名称 + * @param string $template 模板内容 可设置自定义变量,发送短信时候使用,参考:${code} + * @param string $type notification:通知类,verification:验证码,marketing:营销类,voice:语音类 + * @param string $description 申请理由简述 + * @param string $signature_id 已经审核通过的签名 + * @return array array + * @link https://developer.qiniu.com/sms/api/5893/sms-api-create-template + */ + public function createTemplate( + $name, + $template, + $type, + $description, + $signature_id + ) { + $params = array(); + $params['name'] = $name; + $params['template'] = $template; + $params['type'] = $type; + $params['description'] = $description; + $params['signature_id'] = $signature_id; + + $body = json_encode($params); + $url = $this->baseURL . 'template'; + return $this->post($url, $body); + } + + /** + * 列出模板 + * + * @param string $audit_status 审核状态:passed (通过), rejected (未通过), reviewing (审核中) + * @param int $page 页码。默认为 1 + * @param int $page_size 分页大小。默认为 20 + * @return array + * @link https://developer.qiniu.com/sms/api/5894/sms-api-query-template + */ + public function queryTemplate($audit_status = null, $page = 1, $page_size = 20) + { + + $url = sprintf( + "%s?audit_status=%s&page=%s&page_size=%s", + $this->baseURL . 'template', + $audit_status, + $page, + $page_size + ); + return $this->get($url); + } + + /** + * 查询单个模版 + * + * @param string $template_id 模版ID + * @return array + * @link https://developer.qiniu.com/sms/api/5969/query-a-single-template + */ + public function querySingleTemplate($template_id) + { + + $url = sprintf( + "%s/%s", + $this->baseURL . 'template', + $template_id + ); + return $this->get($url); + } + + /** + * 编辑模板 + * + * @param string $id 模板 ID + * @param string $name 模板名称 + * @param string $template 模板内容 + * @param string $description 申请理由简述 + * @param string $signature_id 已经审核通过的签名 ID + * @return array + * @link https://developer.qiniu.com/sms/api/5895/sms-api-edit-template + */ + public function updateTemplate( + $id, + $name, + $template, + $description, + $signature_id + ) { + $params = array(); + $params['name'] = $name; + $params['template'] = $template; + $params['description'] = $description; + $params['signature_id'] = $signature_id; + $body = json_encode($params); + $url = $this->baseURL . 'template/' . $id; + return $this->PUT($url, $body); + } + + /** + * 删除模板 + * + * @param string $template_id 模板 ID + * @return array + * @link https://developer.qiniu.com/sms/api/5896/sms-api-delete-template + */ + public function deleteTemplate($template_id) + { + $url = $this->baseURL . 'template/' . $template_id; + return $this->delete($url); + } + + /** + * 发送短信 + * + * @param string $template_id 模板 ID + * @param array $mobiles 手机号 + * @param array $parameters 自定义模板变量,变量设置在创建模板时,参数template指定 + * @return array + * @link https://developer.qiniu.com/sms/api/5897/sms-api-send-message + */ + public function sendMessage($template_id, $mobiles, $parameters = null) + { + $params = array(); + $params['template_id'] = $template_id; + $params['mobiles'] = $mobiles; + if (!empty($parameters)) { + $params['parameters'] = $parameters; + } + $body = json_encode($params); + $url = $this->baseURL . 'message'; + return $this->post($url, $body); + } + + /** + * 查询发送记录 + * + * @param string $job_id 发送任务返回的 id + * @param string $message_id 单条短信发送接口返回的 id + * @param string $mobile 接收短信的手机号码 + * @param string $status sending: 发送中,success: 发送成功,failed: 发送失败,waiting: 等待发送 + * @param string $template_id 模版 id + * @param string $type marketing:营销,notification:通知,verification:验证码,voice:语音 + * @param string $start 开始时间,timestamp,例如: 1563280448 + * @param int $end 结束时间,timestamp,例如: 1563280471 + * @param int $page 页码,默认为 1 + * @param int $page_size 每页返回的数据条数,默认20,最大200 + * @return array + * @link https://developer.qiniu.com/sms/api/5852/query-send-sms + */ + public function querySendSms( + $job_id = null, + $message_id = null, + $mobile = null, + $status = null, + $template_id = null, + $type = null, + $start = null, + $end = null, + $page = 1, + $page_size = 20 + ) { + $query = array(); + \Qiniu\setWithoutEmpty($query, 'job_id', $job_id); + \Qiniu\setWithoutEmpty($query, 'message_id', $message_id); + \Qiniu\setWithoutEmpty($query, 'mobile', $mobile); + \Qiniu\setWithoutEmpty($query, 'status', $status); + \Qiniu\setWithoutEmpty($query, 'template_id', $template_id); + \Qiniu\setWithoutEmpty($query, 'type', $type); + \Qiniu\setWithoutEmpty($query, 'start', $start); + \Qiniu\setWithoutEmpty($query, 'end', $end); + \Qiniu\setWithoutEmpty($query, 'page', $page); + \Qiniu\setWithoutEmpty($query, 'page_size', $page_size); + + $url = $this->baseURL . 'messages?' . http_build_query($query); + return $this->get($url); + } + + + public function imgToBase64($img_file) + { + $img_base64 = ''; + if (file_exists($img_file)) { + $app_img_file = $img_file; // 图片路径 + $img_info = getimagesize($app_img_file); // 取得图片的大小,类型等 + $fp = fopen($app_img_file, "r"); // 图片是否可读权限 + if ($fp) { + $filesize = filesize($app_img_file); + if ($filesize > 5 * 1024 * 1024) { + die("pic size < 5M !"); + } + $img_type = null; + $content = fread($fp, $filesize); + $file_content = chunk_split(base64_encode($content)); // base64编码 + switch ($img_info[2]) { //判读图片类型 + case 1: + $img_type = 'gif'; + break; + case 2: + $img_type = 'jpg'; + break; + case 3: + $img_type = 'png'; + break; + } + //合成图片的base64编码 + $img_base64 = 'data:image/' . $img_type . ';base64,' . $file_content; + } + fclose($fp); + } + + return $img_base64; + } + + private function get($url, $contentType = 'application/x-www-form-urlencoded') + { + $headers = $this->auth->authorizationV2($url, "GET", null, $contentType); + $headers['Content-Type'] = $contentType; + $ret = Client::get($url, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + return array($ret->json(), null); + } + + private function delete($url, $contentType = 'application/json') + { + $headers = $this->auth->authorizationV2($url, "DELETE", null, $contentType); + $headers['Content-Type'] = $contentType; + $ret = Client::delete($url, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + return array($ret->json(), null); + } + + private function post($url, $body, $contentType = 'application/json') + { + $headers = $this->auth->authorizationV2($url, "POST", $body, $contentType); + + $headers['Content-Type'] = $contentType; + $ret = Client::post($url, $body, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = ($ret->body === null) ? array() : $ret->json(); + return array($r, null); + } + + private function PUT($url, $body, $contentType = 'application/json') + { + $headers = $this->auth->authorizationV2($url, "PUT", $body, $contentType); + $headers['Content-Type'] = $contentType; + $ret = Client::put($url, $body, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = ($ret->body === null) ? array() : $ret->json(); + return array($r, null); + } +} diff --git a/php-sdk/src/Qiniu/Storage/ArgusManager.php b/php-sdk/src/Qiniu/Storage/ArgusManager.php new file mode 100644 index 0000000..51b4200 --- /dev/null +++ b/php-sdk/src/Qiniu/Storage/ArgusManager.php @@ -0,0 +1,129 @@ +auth = $auth; + if ($config == null) { + $this->config = new Config(); + } else { + $this->config = $config; + } + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + /** + * 视频审核 + * + * @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()) { + 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, $this->proxy->makeReqOpt()); + } + + 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, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + 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); + } +} diff --git a/php-sdk/src/Qiniu/Storage/BucketManager.php b/php-sdk/src/Qiniu/Storage/BucketManager.php new file mode 100644 index 0000000..bfca4fc --- /dev/null +++ b/php-sdk/src/Qiniu/Storage/BucketManager.php @@ -0,0 +1,1324 @@ +auth = $auth; + if ($config == null) { + $this->config = new Config(); + } else { + $this->config = $config; + } + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + /** + * 获取指定账号下所有的空间名 + * + * @param bool $shared 指定共享空间,rw:读写权限空间,rd:读权限空间 + * @return array 包含所有空间名 + */ + public function buckets($shared = true) + { + $includeShared = "false"; + if ($shared === true) { + $includeShared = "true"; + } + return $this->getV2($this->config->getUcHost() . '/buckets?shared=' . $includeShared); + } + + /** + * 列举空间,返回bucket列表 + * + * @param string $region 区域 + * @param string $line + * @param string $shared 指定共享空间,rw:读写权限空间,rd:读权限空间 + * @return array + */ + public function listbuckets( + $region = null, + $line = 'false', + $shared = 'false' + ) { + $path = '/v3/buckets?region=' . $region . '&line=' . $line . '&shared=' . $shared; + return $this->ucPost($path); + } + + /** + * 创建空间 + * + * @param string $name 创建的空间名 + * @param string $region 创建的区域,默认华东 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1382/mkbucketv3 + */ + public function createBucket($name, $region = 'z0') + { + $path = '/mkbucketv3/' . $name . '/region/' . $region; + return $this->postV2($this->config->getUcHost() . $path, null); + } + + /** + * 删除空间 + * + * @param string $name 需要删除的目标空间名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1601/drop-bucket + */ + public function deleteBucket($name) + { + $path = '/drop/' . $name; + return $this->postV2($this->config->getUcHost() . $path, null); + } + + /** + * 获取指定空间绑定的所有的域名 + * + * @param string $bucket 空间名称 + * @return array + */ + public function domains($bucket) + { + return $this->ucGet('/v2/domains?tbl=' . $bucket); + } + + /** + * 获取指定空间的相关信息 + * + * @param string $bucket 空间名称 + * @return array + */ + public function bucketInfo($bucket) + { + $path = '/v2/bucketInfo?bucket=' . $bucket; + return $this->ucPost($path); + } + + /** + * 获取指定zone的空间信息列表 + * + * @param string $region 区域 + * @param string $shared 指定共享空间,rw:读写权限空间,rd:读权限空间 + * @param string $fs 如果为 true,会返回每个空间当前的文件数和存储量(实时数据) + * @return array + */ + public function bucketInfos($region = null, $shared = 'false', $fs = 'false') + { + $path = '/v2/bucketInfos?region=' . $region . '&shared=' . $shared . '&fs=' . $fs; + return $this->ucPost($path); + } + + /** + * 列取空间的文件列表 + * + * @param string $bucket 空间名 + * @param string $prefix 列举前缀 + * @param string $marker 列举标识符 + * @param int $limit 单次列举个数限制 + * @param string $delimiter 指定目录分隔符 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1284/list + */ + public function listFiles( + $bucket, + $prefix = null, + $marker = null, + $limit = 1000, + $delimiter = null + ) { + $query = array('bucket' => $bucket); + \Qiniu\setWithoutEmpty($query, 'prefix', $prefix); + \Qiniu\setWithoutEmpty($query, 'marker', $marker); + \Qiniu\setWithoutEmpty($query, 'limit', $limit); + \Qiniu\setWithoutEmpty($query, 'delimiter', $delimiter); + return $this->rsfGet($bucket, '/list?' . http_build_query($query)); + } + + /** + * 列取空间的文件列表 + * + * @deprecated API 可能返回仅包含 marker,不包含 item 或 dir 的项,请使用 {@link listFiles} + * + * @param string $bucket 空间名 + * @param string $prefix 列举前缀 + * @param string $marker 列举标识符 + * @param int $limit 单次列举个数限制 + * @param string $delimiter 指定目录分隔符 + * @param bool $skipconfirm 是否跳过已删除条目的确认机制 + * + * @return array + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/list.html + */ + public function listFilesv2( + $bucket, + $prefix = null, + $marker = null, + $limit = 1000, + $delimiter = null, + $skipconfirm = true + ) { + $query = array('bucket' => $bucket); + \Qiniu\setWithoutEmpty($query, 'prefix', $prefix); + \Qiniu\setWithoutEmpty($query, 'marker', $marker); + \Qiniu\setWithoutEmpty($query, 'limit', $limit); + \Qiniu\setWithoutEmpty($query, 'delimiter', $delimiter); + \Qiniu\setWithoutEmpty($query, 'skipconfirm', $skipconfirm); + $path = '/v2/list?' . http_build_query($query); + + list($host, $err) = $this->config->getRsfHostV2( + $this->auth->getAccessKey(), + $bucket, + $this->proxy->makeReqOpt() + ); + + if ($err != null) { + return array(null, $err); + } + + $url = $host . $path; + $headers = $this->auth->authorizationV2($url, 'POST', null, 'application/x-www-form-urlencoded'); + $ret = Client::post($url, null, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = explode("\n", $ret->body); + array_pop($r); + return array($r, null); + } + + /** + * 增加bucket生命规则 + * + * @param string $bucket + * 空间名 + * @param string $name + * 规则名称 bucket 内唯一,长度小于50,不能为空,只能为字母、数字、下划线 + * @param string $prefix + * 同一个 bucket 里面前缀不能重复 + * @param int $delete_after_days + * 指定上传文件多少天后删除,指定为0表示不删除,大于0表示多少天后删除。 + * 需大于 to_line_after_days + * @param int $to_line_after_days + * 指定文件上传多少天后转低频存储。指定为0表示不转低频存储 + * @param int $to_archive_ir_after_days + * 指定文件上传多少天后转归档直读。指定为0表示不转归档直读 + * @param int $to_archive_after_days + * 指定文件上传多少天后转归档存储。指定为0表示不转归档存储 + * @param int $to_deep_archive_after_days + * 指定文件上传多少天后转深度归档存储。指定为0表示不转深度归档存储 + * @return array + */ + public function bucketLifecycleRule( + $bucket, + $name, + $prefix, + $delete_after_days = null, + $to_line_after_days = null, + $to_archive_after_days = null, + $to_deep_archive_after_days = null, + $to_archive_ir_after_days = null + ) { + $path = '/rules/add'; + $params = array(); + if ($bucket) { + $params['bucket'] = $bucket; + } + if ($name) { + $params['name'] = $name; + } + if ($prefix) { + $params['prefix'] = $prefix; + } + if ($delete_after_days) { + $params['delete_after_days'] = $delete_after_days; + } + if ($to_line_after_days) { + $params['to_line_after_days'] = $to_line_after_days; + } + if ($to_archive_ir_after_days) { + $params['to_archive_ir_after_days'] = $to_archive_ir_after_days; + } + if ($to_archive_after_days) { + $params['to_archive_after_days'] = $to_archive_after_days; + } + if ($to_deep_archive_after_days) { + $params['to_deep_archive_after_days'] = $to_deep_archive_after_days; + } + $data = http_build_query($params); + $info = $this->ucPost($path, $data); + return $info; + } + + /** + * 更新bucket生命规则 + * + * @param string $bucket + * 空间名 + * @param string $name + * 规则名称 bucket 内唯一,长度小于50,不能为空,只能为字母、数字、下划线 + * @param string $prefix + * 同一个 bucket 里面前缀不能重复 + * @param int $delete_after_days + * 指定上传文件多少天后删除,指定为0表示不删除,大于0表示多少天后删除 + * 需大于 to_line_after_days + * @param int $to_line_after_days + * 指定文件上传多少天后转低频存储。指定为0表示不转低频存储 + * @param int $to_archive_ir_after_days + * 指定文件上传多少天后转归档只读。指定为0表示不转归档只读 + * @param int $to_archive_after_days + * 指定文件上传多少天后转归档存储。指定为0表示不转归档存储 + * @param int $to_deep_archive_after_days + * 指定文件上传多少天后转深度归档存储。指定为0表示不转深度归档存储 + * @return array + */ + public function updateBucketLifecycleRule( + $bucket, + $name, + $prefix, + $delete_after_days = null, + $to_line_after_days = null, + $to_archive_after_days = null, + $to_deep_archive_after_days = null, + $to_archive_ir_after_days = null + ) { + $path = '/rules/update'; + $params = array(); + if ($bucket) { + $params['bucket'] = $bucket; + } + if ($name) { + $params['name'] = $name; + } + if ($prefix) { + $params['prefix'] = $prefix; + } + if ($delete_after_days) { + $params['delete_after_days'] = $delete_after_days; + } + if ($to_line_after_days) { + $params['to_line_after_days'] = $to_line_after_days; + } + if ($to_archive_ir_after_days) { + $params['to_archive_ir_after_days'] = $to_archive_ir_after_days; + } + if ($to_archive_after_days) { + $params['to_archive_after_days'] = $to_archive_after_days; + } + if ($to_deep_archive_after_days) { + $params['to_deep_archive_after_days'] = $to_deep_archive_after_days; + } + $data = http_build_query($params); + return $this->ucPost($path, $data); + } + + /** + * 获取bucket生命规则 + * + * @param string $bucket 空间名 + * @return array + */ + public function getBucketLifecycleRules($bucket) + { + $path = '/rules/get?bucket=' . $bucket; + $info = $this->ucGet($path); + return $info; + } + + /** + * 删除bucket生命规则 + * + * @param string $bucket 空间名 + * @param string $name 规则名称 bucket 内唯一,长度小于50,不能为空, + * 只能为字母、数字、下划线() + * @return array + */ + public function deleteBucketLifecycleRule($bucket, $name) + { + $path = '/rules/delete'; + $params = array(); + if ($bucket) { + $params['bucket'] = $bucket; + } + if ($name) { + $params['name'] = $name; + } + $data = http_build_query($params); + $info = $this->ucPost($path, $data); + return $info; + } + + /** + * 增加bucket事件通知规则 + * + * @param string $bucket 空间名 + * @param string $name 规则名称 bucket 内唯一,长度小于50,不能为空, + * 只能为字母、数字、下划线() + * @param string $prefix 同一个 bucket 里面前缀不能重复 + * @param string $suffix 可选,文件配置的后缀 + * @param array $event 事件类型,可以指定多个,包括 put,mkfile,delete,copy,move,append, + * disable,enable,deleteMarkerCreate + * @param string $callbackURL 通知URL,可以指定多个,失败依次重试 + * @param string $access_key 可选,设置的话会对通知请求用对应的ak、sk进行签名 + * @param string $host 可选,通知请求的host + * + * @return array + */ + public function putBucketEvent( + $bucket, + $name, + $prefix, + $suffix, + $event, + $callbackURL, + $access_key = null, + $host = null + ) { + $path = '/events/add'; + $params = array(); + if (!empty($bucket)) { + $params['bucket'] = $bucket; + } + if (!empty($name)) { + $params['name'] = $name; + } + if (!empty($prefix)) { + $params['prefix'] = $prefix; + } + if (!empty($suffix)) { + $params['suffix'] = $suffix; + } + if (!empty($callbackURL)) { + $params['callbackURL'] = $callbackURL; + } + if (!empty($access_key)) { + $params['access_key'] = $access_key; + } + if (!empty($host)) { + $params['host'] = $host; + } + $data = http_build_query($params); + if (!empty($event)) { + $eventpath = ""; + foreach ($event as $key => $value) { + $eventpath .= "&event=$value"; + } + $data .= $eventpath; + } + $info = $this->ucPost($path, $data); + return $info; + } + + /** + * 更新bucket事件通知规则 + * + * @param string $bucket 空间名 + * @param string $name 规则名称 bucket 内唯一,长度小于50,不能为空, + * 只能为字母、数字、下划线() + * @param string $prefix 同一个 bucket 里面前缀不能重复 + * @param string $suffix 可选,文件配置的后缀 + * @param array $event 事件类型,可以指定多个,包括 put,mkfile,delete,copy,move,append,disable, + * enable,deleteMarkerCreate + * @param string $callbackURL 通知URL,可以指定多个,失败依次重试 + * @param string $access_key 可选,设置的话会对通知请求用对应的ak、sk进行签名 + * @param string $host 可选,通知请求的host + * + * @return array + */ + public function updateBucketEvent( + $bucket, + $name, + $prefix, + $suffix, + $event, + $callbackURL, + $access_key = null, + $host = null + ) { + $path = '/events/update'; + $params = array(); + if (!empty($bucket)) { + $params['bucket'] = $bucket; + } + if (!empty($name)) { + $params['name'] = $name; + } + if (!empty($prefix)) { + $params['prefix'] = $prefix; + } + if ($suffix) { + $params['suffix'] = $suffix; + } + if (!empty($event)) { + $params['event'] = $event; + } + if (!empty($callbackURL)) { + $params['callbackURL'] = $callbackURL; + } + if (!empty($access_key)) { + $params['access_key'] = $access_key; + } + if (!empty($host)) { + $params['host'] = $host; + } + $data = http_build_query($params); + if (!empty($event)) { + $eventpath = ""; + foreach ($event as $key => $value) { + $eventpath .= "&event=$value"; + } + $data .= $eventpath; + } + return $this->ucPost($path, $data); + } + + /** + * 获取bucket事件通知规则 + * + * @param string $bucket 空间名 + * @return array + */ + public function getBucketEvents($bucket) + { + $path = '/events/get?bucket=' . $bucket; + return $this->ucGet($path); + } + + /** + * 删除bucket事件通知规则 + * + * @param string $bucket 空间名 + * @param string $name 规则名称bucket内唯一,长度小于50,不能为空,只能为字母、数字、下划线 + * @return array + */ + public function deleteBucketEvent($bucket, $name) + { + $path = '/events/delete'; + $params = array(); + if ($bucket) { + $params['bucket'] = $bucket; + } + if ($name) { + $params['name'] = $name; + } + $data = http_build_query($params); + return $this->ucPost($path, $data); + } + + /** + * 获取bucket的跨域信息 + * + * @param string $bucket 空间名 + * @return array + */ + public function getCorsRules($bucket) + { + $path = '/corsRules/get/' . $bucket; + return $this->ucGet($path); + } + + /** + * 开关原图保护 + * + * @param string $bucket 空间名称 + * @param int $mode mode 为1表示开启原图保护,0表示关闭 + * @return array + */ + public function putBucketAccessStyleMode($bucket, $mode) + { + $path = '/accessMode/' . $bucket . '/mode/' . $mode; + return $this->ucPost($path, null); + } + + /** + * 设置私有属性 + * + * @param string $bucket 空间名称 + * @param int $private private为0表示公开,为1表示私有 + * @return array + */ + public function putBucketAccessMode($bucket, $private) + { + $path = "/private?bucket=$bucket&private=$private"; + return $this->ucPost($path, null); + } + + /** + * 设置 referer 防盗链 + * + * @param string $bucket 空间名称 + * @param int $mode 0:关闭Referer(使用此选项将会忽略以下参数并将恢复默认值); + * 1:设置Referer白名单; 2:设置Referer黑名单 + * @param string $norefer 0:不允许空 Refer 访问; 1:表示允许空Refer访问 + * @param string $pattern 规则字符串 + * @param int $enabled 源站是否支持,默认为0只给CDN配置, 设置为1表示开启源站防盗链 + * @return array + * @link https://developer.qiniu.com/kodo/manual/6093/set-the-hotlinking-prevention + */ + public function putReferAntiLeech($bucket, $mode, $norefer, $pattern, $enabled = 1) + { + $path = "/referAntiLeech?bucket=$bucket&mode=$mode&norefer=$norefer&pattern=$pattern&source_enabled=$enabled"; + return $this->ucPost($path, null); + } + + /** + * 设置Bucket的maxAge + * + * @param string $bucket 空间名称 + * @param int $maxAge maxAge为0或者负数表示为默认值(31536000) + * @return array + */ + public function putBucketMaxAge($bucket, $maxAge) + { + $path = '/maxAge?bucket=' . $bucket . '&maxAge=' . $maxAge; + return $this->ucPost($path, null); + } + + /** + * 设置空间配额 + * + * @param string $bucket 空间名称,不支持授权空间 + * @param string $size 空间存储量配额,参数传入0或不传表示不更改当前配置,传入-1表示取消限额,新创建的空间默认没有限额 + * @param string $count 空间文件数配额,参数含义同 + * @return array + */ + public function putBucketQuota($bucket, $size, $count) + { + $path = '/setbucketquota/' . $bucket . '/size/' . $size . '/count/' . $count; + return $this->apiPost($bucket, $path); + } + + /** + * 获取空间配额 + * + * @param string $bucket 空间名称 + * @return array + */ + public function getBucketQuota($bucket) + { + $path = '/getbucketquota/' . $bucket; + return $this->apiPost($bucket, $path); + } + + /** + * 获取资源的元信息,但不返回文件内容 + * + * @param string $bucket 待获取信息资源所在的空间 + * @param string $key 待获取资源的文件名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1308/stat + */ + public function stat($bucket, $key) + { + $path = '/stat/' . \Qiniu\entry($bucket, $key); + return $this->rsGet($bucket, $path); + } + + /** + * 删除指定资源 + * + * @param string $bucket 待删除资源所在的空间 + * @param string $key 待删除资源的文件名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1257/delete + */ + public function delete($bucket, $key) + { + $path = '/delete/' . \Qiniu\entry($bucket, $key); + return $this->rsPost($bucket, $path); + } + + /** + * 给资源进行重命名,本质为move操作。 + * + * @param string $bucket 待操作资源所在空间 + * @param string $oldname 待操作资源文件名 + * @param string $newname 目标资源文件名 + * + * @return array + */ + public function rename($bucket, $oldname, $newname) + { + return $this->move($bucket, $oldname, $bucket, $newname); + } + + /** + * 对资源进行复制。 + * + * @param string $from_bucket 待操作资源所在空间 + * @param string $from_key 待操作资源文件名 + * @param string $to_bucket 目标资源空间名 + * @param string $to_key 目标资源文件名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1254/copy + */ + public function copy($from_bucket, $from_key, $to_bucket, $to_key, $force = false) + { + $from = \Qiniu\entry($from_bucket, $from_key); + $to = \Qiniu\entry($to_bucket, $to_key); + $path = '/copy/' . $from . '/' . $to; + if ($force === true) { + $path .= '/force/true'; + } + return $this->rsPost($from_bucket, $path); + } + + /** + * 将资源从一个空间到另一个空间 + * + * @param string $from_bucket 待操作资源所在空间 + * @param string $from_key 待操作资源文件名 + * @param string $to_bucket 目标资源空间名 + * @param string $to_key 目标资源文件名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1288/move + */ + public function move($from_bucket, $from_key, $to_bucket, $to_key, $force = false) + { + $from = \Qiniu\entry($from_bucket, $from_key); + $to = \Qiniu\entry($to_bucket, $to_key); + $path = '/move/' . $from . '/' . $to; + if ($force) { + $path .= '/force/true'; + } + return $this->rsPost($from_bucket, $path); + } + + /** + * 主动修改指定资源的文件元信息 + * + * @param string $bucket 待操作资源所在空间 + * @param string $key 待操作资源文件名 + * @param string $mime 待操作文件目标mimeType + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1252/chgm + */ + public function changeMime($bucket, $key, $mime) + { + $resource = \Qiniu\entry($bucket, $key); + $encode_mime = \Qiniu\base64_urlSafeEncode($mime); + $path = '/chgm/' . $resource . '/mime/' . $encode_mime; + return $this->rsPost($bucket, $path); + } + + + /** + * 修改指定资源的存储类型 + * + * @param string $bucket 待操作资源所在空间 + * @param string $key 待操作资源文件名 + * @param int $fileType 对象存储类型 + * 0 表示标准存储; + * 1 表示低频存储; + * 2 表示归档存储; + * 3 表示深度归档存储; + * 4 表示归档直读存储; + * + * @return array + * @link https://developer.qiniu.com/kodo/api/3710/chtype + */ + public function changeType($bucket, $key, $fileType) + { + $resource = \Qiniu\entry($bucket, $key); + $path = '/chtype/' . $resource . '/type/' . $fileType; + return $this->rsPost($bucket, $path); + } + + /** + * 解冻指定资源的存储类型 + * + * @param string $bucket 待操作资源所在空间 + * @param string $key 待操作资源文件名 + * @param int $freezeAfterDays 解冻有效时长,取值范围 1~7 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/6380/restore-archive + */ + public function restoreAr($bucket, $key, $freezeAfterDays) + { + $resource = \Qiniu\entry($bucket, $key); + $path = '/restoreAr/' . $resource . '/freezeAfterDays/' . $freezeAfterDays; + return $this->rsPost($bucket, $path); + } + + /** + * 修改文件的存储状态,即禁用状态和启用状态间的的互相转换 + * + * @param string $bucket 待操作资源所在空间 + * @param string $key 待操作资源文件名 + * @param int $status 0表示启用;1表示禁用 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/4173/modify-the-file-status + */ + public function changeStatus($bucket, $key, $status) + { + $resource = \Qiniu\entry($bucket, $key); + $path = '/chstatus/' . $resource . '/status/' . $status; + return $this->rsPost($bucket, $path); + } + + /** + * 从指定URL抓取资源,并将该资源存储到指定空间中 + * + * @param string $url 指定的URL + * @param string $bucket 目标资源空间 + * @param string $key 目标资源文件名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1263/fetch + */ + public function fetch($url, $bucket, $key = null) + { + + $resource = \Qiniu\base64_urlSafeEncode($url); + $to = \Qiniu\entry($bucket, $key); + $path = '/fetch/' . $resource . '/to/' . $to; + + $ak = $this->auth->getAccessKey(); + + + list($ioHost, $err) = $this->config->getIovipHostV2($ak, $bucket, $this->proxy->makeReqOpt()); + if ($err != null) { + return array(null, $err); + } + + $url = $ioHost . $path; + return $this->postV2($url, null); + } + + /** + * 从指定URL异步抓取资源,并将该资源存储到指定空间中 + * + * @param string $url 需要抓取的url + * @param string $bucket 所在区域的bucket + * @param string $host 从指定url下载数据时使用的Host + * @param string $key 文件存储的key + * @param string $md5 文件md5 + * @param string $etag 文件etag + * @param string $callbackurl 回调URL + * @param string $callbackbody 回调Body + * @param string $callbackbodytype 回调Body内容类型,默认为"application/x-www-form-urlencoded" + * @param string $callbackhost 回调时使用的Host + * @param int $file_type 存储文件类型 + * 0:标准存储(默认) + * 1:低频存储 + * 2:归档存储 + * 3:深度归档存储 + * 4:归档直读存储 + * @param bool $ignore_same_key 如果空间中已经存在同名文件则放弃本次抓取 + * @return array + * @link https://developer.qiniu.com/kodo/api/4097/asynch-fetch + */ + public function asynchFetch( + $url, + $bucket, + $host = null, + $key = null, + $md5 = null, + $etag = null, + $callbackurl = null, + $callbackbody = null, + $callbackbodytype = 'application/x-www-form-urlencoded', + $callbackhost = null, + $file_type = 0, + $ignore_same_key = false + ) { + $path = '/sisyphus/fetch'; + + $params = array('url' => $url, 'bucket' => $bucket); + \Qiniu\setWithoutEmpty($params, 'host', $host); + \Qiniu\setWithoutEmpty($params, 'key', $key); + \Qiniu\setWithoutEmpty($params, 'md5', $md5); + \Qiniu\setWithoutEmpty($params, 'etag', $etag); + \Qiniu\setWithoutEmpty($params, 'callbackurl', $callbackurl); + \Qiniu\setWithoutEmpty($params, 'callbackbody', $callbackbody); + \Qiniu\setWithoutEmpty($params, 'callbackbodytype', $callbackbodytype); + \Qiniu\setWithoutEmpty($params, 'callbackhost', $callbackhost); + \Qiniu\setWithoutEmpty($params, 'file_type', $file_type); + \Qiniu\setWithoutEmpty($params, 'ignore_same_key', $ignore_same_key); + $data = json_encode($params); + + return $this->apiPost($bucket, $path, $data); + } + + + /** + * 查询异步第三方资源抓取任务状态 + * + * @param string $zone + * @param string $id + * @return array + * @link https://developer.qiniu.com/kodo/api/4097/asynch-fetch + */ + public function asynchFetchStatus($zone, $id) + { + $scheme = "http://"; + + if ($this->config->useHTTPS === true) { + $scheme = "https://"; + } + + $url = $scheme . "api-" . $zone . ".qiniuapi.com/sisyphus/fetch?id=" . $id; + + list($ret, $err) = $this->getV2($url); + + if ($err != null) { + return array(null, $err); + } + return array($ret, null); + } + + + /** + * 从镜像源站抓取资源到空间中,如果空间中已经存在,则覆盖该资源 + * + * @param string $bucket 待获取资源所在的空间 + * @param string $key 代获取资源文件名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1293/prefetch + */ + public function prefetch($bucket, $key) + { + $resource = \Qiniu\entry($bucket, $key); + $path = '/prefetch/' . $resource; + + $ak = $this->auth->getAccessKey(); + list($ioHost, $err) = $this->config->getIovipHostV2($ak, $bucket, $this->proxy->makeReqOpt()); + + if ($err != null) { + return array(null, $err); + } + + $url = $ioHost . $path; + return $this->postV2($url, null); + } + + /** + * 在单次请求中进行多个资源管理操作 + * + * @param array $operations 资源管理操作数组 + * + * @return array 每个资源的处理情况,结果类似: + * [ + * { "code" => , "data" => }, + * { "code" => }, + * { "code" => }, + * { "code" => }, + * { "code" => , "data" => { "error": "" } }, + * ... + * ] + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/batch.html + */ + public function batch($operations) + { + $scheme = "http://"; + if ($this->config->useHTTPS === true) { + $scheme = "https://"; + } + $params = 'op=' . implode('&op=', $operations); + $errResp = new Response(0, 0); + if (count($operations) <= 0) { + $errResp->error = 'empty operations'; + return array(null, new Error($scheme . '/batch', $errResp)); + } + $bucket = ''; + foreach ($operations as $op) { + $segments = explode('/', $op); + if (count($segments) < 3) { + continue; + } + list($bucket,) = \Qiniu\decodeEntry($segments[2]); + } + return $this->rsPost($bucket, '/batch', $params); + } + + /** + * 设置文件的生命周期 + * + * @param string $bucket 设置文件生命周期文件所在的空间 + * @param string $key 设置文件生命周期文件的文件名 + * @param int $days 设置该文件多少天后删除,当$days设置为0时表示取消该文件的生命周期 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/update-file-lifecycle + */ + public function deleteAfterDays($bucket, $key, $days) + { + $entry = \Qiniu\entry($bucket, $key); + $path = "/deleteAfterDays/$entry/$days"; + return $this->rsPost($bucket, $path); + } + + /** + * 更新 object 生命周期 + * + * @param string $bucket 空间名 + * @param string $key 目标资源 + * @param int $to_line_after_days 多少天后将文件转为低频存储。 + * -1 表示取消已设置的转低频存储的生命周期规则; + * 0 表示不修改转低频生命周期规则。 + * @param int $to_archive_ir_after_days 多少天后转为归档直读存储。 + * -1 表示取消已设置的转归档直读存储的生命周期规则; + * 0 表示不修改转归档直读生命周期规则。 + * @param int $to_archive_after_days 多少天后将文件转为归档存储。 + * -1 表示取消已设置的转归档存储的生命周期规则; + * 0 表示不修改转归档生命周期规则。 + * @param int $to_deep_archive_after_days 多少天后将文件转为深度归档存储。 + * -1 表示取消已设置的转深度归档存储的生命周期规则; + * 0 表示不修改转深度归档生命周期规则。 + * @param int $delete_after_days 多少天后将文件删除。 + * -1 表示取消已设置的删除存储的生命周期规则; + * 0 表示不修改删除存储的生命周期规则。 + * @return array + */ + public function setObjectLifecycle( + $bucket, + $key, + $to_line_after_days = 0, + $to_archive_after_days = 0, + $to_deep_archive_after_days = 0, + $delete_after_days = 0, + $to_archive_ir_after_days = 0 + ) { + return $this->setObjectLifecycleWithCond( + $bucket, + $key, + null, + $to_line_after_days, + $to_archive_after_days, + $to_deep_archive_after_days, + $delete_after_days, + $to_archive_ir_after_days + ); + } + + /** + * 更新 object 生命周期 + * + * @param string $bucket 空间名 + * @param string $key 目标资源 + * @param int $to_line_after_days 多少天后将文件转为低频存储。 + * 设置为 -1 表示取消已设置的转低频存储的生命周期规则; + * 0 表示不修改转低频生命周期规则。 + * @param int $to_archive_ir_after_days 多少天后将文件转为归档直读存储。 + * 设置为 -1 表示取消已设置的转归档直读存储的生命周期规则; + * 0 表示不修改转归档直读生命周期规则。 + * @param int $to_archive_after_days 多少天后将文件转为归档存储。 + * -1 表示取消已设置的转归档存储的生命周期规则; + * 0 表示不修改转归档生命周期规则。 + * @param int $to_deep_archive_after_days 多少天后将文件转为深度归档存储。 + * -1 表示取消已设置的转深度归档存储的生命周期规则; + * 0 表示不修改转深度归档生命周期规则。 + * @param int $delete_after_days 多少天后将文件删除。 + * -1 表示取消已设置的删除存储的生命周期规则; + * 0 表示不修改删除存储的生命周期规则。 + * @param array $cond 匹配条件,只有条件匹配才会设置成功。 + * 目前支持:hash、mime、fsize、putTime + * @return array + */ + public function setObjectLifecycleWithCond( + $bucket, + $key, + $cond = null, + $to_line_after_days = 0, + $to_archive_after_days = 0, + $to_deep_archive_after_days = 0, + $delete_after_days = 0, + $to_archive_ir_after_days = 0 + ) { + $encodedEntry = \Qiniu\entry($bucket, $key); + $path = '/lifecycle/' . $encodedEntry . + '/toIAAfterDays/' . $to_line_after_days . + '/toArchiveIRAfterDays/' . $to_archive_ir_after_days . + '/toArchiveAfterDays/' . $to_archive_after_days . + '/toDeepArchiveAfterDays/' . $to_deep_archive_after_days . + '/deleteAfterDays/' . $delete_after_days; + if ($cond != null) { + $condStrArr = array(); + foreach ($cond as $key => $value) { + array_push($condStrArr, $key . '=' . $value); + } + $condStr = implode('&', $condStrArr); + $path .= '/cond' . \Qiniu\base64_urlSafeEncode($condStr); + } + return $this->rsPost($bucket, $path); + } + + private function rsfGet($bucket, $path) + { + list($host, $err) = $this->config->getRsfHostV2( + $this->auth->getAccessKey(), + $bucket, + $this->proxy->makeReqOpt() + ); + + if ($err != null) { + return array(null, $err); + } + + return $this->getV2($host . $path); + } + + private function rsGet($bucket, $path) + { + list($host, $err) = $this->config->getRsHostV2( + $this->auth->getAccessKey(), + $bucket, + $this->proxy->makeReqOpt() + ); + + if ($err != null) { + return array(null, $err); + } + + return $this->getV2($host . $path); + } + + private function rsPost($bucket, $path, $body = null) + { + list($host, $err) = $this->config->getRsHostV2( + $this->auth->getAccessKey(), + $bucket, + $this->proxy->makeReqOpt() + ); + + if ($err != null) { + return array(null, $err); + } + + return $this->postV2($host . $path, $body); + } + + private function apiGet($bucket, $path) + { + list($host, $err) = $this->config->getApiHostV2( + $this->auth->getAccessKey(), + $bucket, + $this->proxy->makeReqOpt() + ); + + if ($err != null) { + return array(null, $err); + } + + return $this->getV2($host . $path); + } + + private function apiPost($bucket, $path, $body = null) + { + + list($host, $err) = $this->config->getApiHostV2( + $this->auth->getAccessKey(), + $bucket, + $this->proxy->makeReqOpt() + ); + + if ($err != null) { + return array(null, $err); + } + + return $this->postV2($host . $path, $body); + } + + private function ucGet($path) + { + $url = $this->config->getUcHost() . $path; + return $this->getV2($url); + } + + private function ucPost($path, $body = null) + { + $url = $this->config->getUcHost() . $path; + return $this->postV2($url, $body); + } + + private function getV2($url) + { + $headers = $this->auth->authorizationV2($url, 'GET', null, 'application/x-www-form-urlencoded'); + $ret = Client::get($url, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + return array($ret->json(), null); + } + + private function postV2($url, $body) + { + $headers = $this->auth->authorizationV2($url, 'POST', $body, 'application/x-www-form-urlencoded'); + $ret = Client::post($url, $body, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = ($ret->body === null) ? array() : $ret->json(); + return array($r, null); + } + + public static function buildBatchCopy($source_bucket, $key_pairs, $target_bucket, $force) + { + return self::twoKeyBatch('/copy', $source_bucket, $key_pairs, $target_bucket, $force); + } + + + public static function buildBatchRename($bucket, $key_pairs, $force) + { + return self::buildBatchMove($bucket, $key_pairs, $bucket, $force); + } + + + public static function buildBatchMove($source_bucket, $key_pairs, $target_bucket, $force) + { + return self::twoKeyBatch('/move', $source_bucket, $key_pairs, $target_bucket, $force); + } + + + public static function buildBatchDelete($bucket, $keys) + { + return self::oneKeyBatch('/delete', $bucket, $keys); + } + + + public static function buildBatchStat($bucket, $keys) + { + return self::oneKeyBatch('/stat', $bucket, $keys); + } + + public static function buildBatchDeleteAfterDays($bucket, $key_day_pairs) + { + $data = array(); + foreach ($key_day_pairs as $key => $day) { + array_push($data, '/deleteAfterDays/' . \Qiniu\entry($bucket, $key) . '/' . $day); + } + return $data; + } + + /** + * @param string $bucket 空间名 + * @param array $keys 目标资源 + * @param int $to_line_after_days 多少天后将文件转为低频存储。 + * -1 表示取消已设置的转低频存储的生命周期规则; + * 0 表示不修改转低频生命周期规则。 + * @param int $to_archive_ir_after_days 多少天后将文件转为归档直读。 + * -1 表示取消已设置的转归档只读的生命周期规则; + * 0 表示不修改转归档只读周期规则。 + * @param int $to_archive_after_days 多少天后将文件转为归档存储。 + * -1 表示取消已设置的转归档存储的生命周期规则; + * 0 表示不修改转归档生命周期规则。 + * @param int $to_deep_archive_after_days 多少天后将文件转为深度归档存储。 + * -1 表示取消已设置的转深度归档存储的生命周期规则; + * 0 表示不修改转深度归档生命周期规则。 + * @param int $delete_after_days 多少天后将文件删除。 + * -1 表示取消已设置的删除存储的生命周期规则; + * 0 表示不修改删除存储的生命周期规则。 + * + * @retrun array + */ + public static function buildBatchSetObjectLifecycle( + $bucket, + $keys, + $to_line_after_days, + $to_archive_after_days, + $to_deep_archive_after_days, + $delete_after_days, + $to_archive_ir_after_days = 0 + ) { + $result = array(); + foreach ($keys as $key) { + $encodedEntry = \Qiniu\entry($bucket, $key); + $op = '/lifecycle/' . $encodedEntry . + '/toIAAfterDays/' . $to_line_after_days . + '/toArchiveIRAfterDays/' . $to_archive_ir_after_days . + '/toArchiveAfterDays/' . $to_archive_after_days . + '/toDeepArchiveAfterDays/' . $to_deep_archive_after_days . + '/deleteAfterDays/' . $delete_after_days; + array_push($result, $op); + } + return $result; + } + + public static function buildBatchChangeMime($bucket, $key_mime_pairs) + { + $data = array(); + foreach ($key_mime_pairs as $key => $mime) { + array_push($data, '/chgm/' . \Qiniu\entry($bucket, $key) . '/mime/' . base64_encode($mime)); + } + return $data; + } + + public static function buildBatchChangeType($bucket, $key_type_pairs) + { + $data = array(); + foreach ($key_type_pairs as $key => $type) { + array_push($data, '/chtype/' . \Qiniu\entry($bucket, $key) . '/type/' . $type); + } + return $data; + } + + public static function buildBatchRestoreAr($bucket, $key_restore_days_pairs) + { + $data = array(); + foreach ($key_restore_days_pairs as $key => $restore_days) { + array_push($data, '/restoreAr/' . \Qiniu\entry($bucket, $key) . '/freezeAfterDays/' . $restore_days); + } + return $data; + } + + private static function oneKeyBatch($operation, $bucket, $keys) + { + $data = array(); + foreach ($keys as $key) { + array_push($data, $operation . '/' . \Qiniu\entry($bucket, $key)); + } + return $data; + } + + private static function twoKeyBatch($operation, $source_bucket, $key_pairs, $target_bucket, $force) + { + if ($target_bucket === null) { + $target_bucket = $source_bucket; + } + $data = array(); + $forceOp = "false"; + if ($force) { + $forceOp = "true"; + } + foreach ($key_pairs as $from_key => $to_key) { + $from = \Qiniu\entry($source_bucket, $from_key); + $to = \Qiniu\entry($target_bucket, $to_key); + array_push($data, $operation . '/' . $from . '/' . $to . "/force/" . $forceOp); + } + return $data; + } +} diff --git a/php-sdk/src/Qiniu/Storage/FormUploader.php b/php-sdk/src/Qiniu/Storage/FormUploader.php new file mode 100644 index 0000000..d68654d --- /dev/null +++ b/php-sdk/src/Qiniu/Storage/FormUploader.php @@ -0,0 +1,165 @@ + "", + * "key" => "" + * ] + */ + public static function put( + $upToken, + $key, + $data, + $config, + $params, + $mime, + $fname, + $reqOpt = null + ) { + if ($reqOpt == null) { + $reqOpt = new RequestOptions(); + } + $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); + } + + list($upHost, $err) = $config->getUpHostV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + + $response = Client::multipartPost( + $upHost, + $fields, + 'file', + $fname, + $data, + $mime, + array(), + $reqOpt + ); + 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 Config $config 上传配置 + * @param string $params 自定义变量,规格参考 + * https://developer.qiniu.com/kodo/manual/1235/vars#xvar + * @param string $mime 上传数据的mimeType + * + * @return array 包含已上传文件的信息,类似: + * [ + * "hash" => "", + * "key" => "" + * ] + */ + public static function putFile( + $upToken, + $key, + $filePath, + $config, + $params, + $mime, + $reqOpt = null + ) { + if ($reqOpt == null) { + $reqOpt = new RequestOptions(); + } + + $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); + } + + list($upHost, $err) = $config->getUpHostV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + $response = Client::post($upHost, $fields, $headers, $reqOpt); + 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; + } +} diff --git a/php-sdk/src/Qiniu/Storage/ResumeUploader.php b/php-sdk/src/Qiniu/Storage/ResumeUploader.php new file mode 100644 index 0000000..00e88ef --- /dev/null +++ b/php-sdk/src/Qiniu/Storage/ResumeUploader.php @@ -0,0 +1,580 @@ + $params 自定义变量 + * @param string $mime 上传数据的mimeType + * @param Config $config + * @param string $resumeRecordFile 断点续传的已上传的部分信息记录文件 + * @param string $version 分片上传版本 目前支持v1/v2版本 默认v1 + * @param int $partSize 分片上传v2字段 默认大小为4MB 分片大小范围为1 MB - 1 GB + * @param RequestOptions $reqOpt 分片上传v2字段 默认大小为4MB 分片大小范围为1 MB - 1 GB + * @throws \Exception + * + * @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, + $reqOpt = null + ) { + + $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->partSize = $partSize ? $partSize : config::BLOCK_SIZE; + + if ($reqOpt === null) { + $reqOpt = new RequestOptions(); + } + $this->reqOpt = $reqOpt; + + try { + $this->version = SplitUploadVersion::from($version ? $version : 'v1'); + } catch (\Exception $e) { + throw new \Exception("only support v1/v2 now!", 0, $e); + } + + list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken); + $this->bucket = $bucket; + if ($err != null) { + return array(null, $err); + } + + list($upHost, $err) = $config->getUpHostV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + throw new \Exception($err->message(), 1); + } + $this->host = $upHost; + } + + /** + * 上传操作 + * @param $fname string 文件名 + * + * @throws \Exception + */ + public function upload($fname) + { + $blkputRets = null; + // get upload record from resumeRecordFile + if ($this->resumeRecordFile != 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 ($this->version == SplitUploadVersion::V1) { + return $this->uploadV1($fname, $blkputRets); + } elseif ($this->version == SplitUploadVersion::V2) { + return $this->uploadV2($fname, $blkputRets); + } else { + throw new \Exception("only support v1/v2 now!"); + } + } + + /** + * @param string $fname 文件名 + * @param null|array $blkputRets + * + * @throws \Exception + */ + private function uploadV1($fname, $blkputRets = null) + { + // 尝试恢复恢复已上传的数据 + $isResumeUpload = $blkputRets !== null; + $this->contexts = array(); + + if ($blkputRets) { + if (isset($blkputRets['contexts']) && isset($blkputRets['uploaded']) && + is_array($blkputRets['contexts']) && is_int($blkputRets['uploaded']) + ) { + $this->contexts = array_map(function ($ctx) { + if (is_array($ctx)) { + return $ctx; + } else { + // 兼容旧版本(旧版本没有存储 expireAt) + return array( + "ctx" => $ctx, + "expiredAt" => 0, + ); + } + }, $blkputRets['contexts']); + } + } + + // 上传分片 + $uploaded = 0; + while ($uploaded < $this->size) { + $blockSize = $this->blockSize($uploaded); + $blockIndex = $uploaded / $this->partSize; + if (!is_int($blockIndex)) { + throw new \Exception("v1 part size changed"); + } + // 如果已上传该分片且没有过期 + if (isset($this->contexts[$blockIndex]) && $this->contexts[$blockIndex]["expiredAt"] >= time()) { + $uploaded += $blockSize; + fseek($this->inputStream, $blockSize, SEEK_CUR); + continue; + } + $data = fread($this->inputStream, $blockSize); + if ($data === false) { + throw new \Exception("file read failed", 1); + } + $crc = \Qiniu\crc32_data($data); + $response = $this->makeBlock($data, $blockSize); + + + $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); + } + list($upHostBackup, $err) = $this->config->getUpBackupHostV2($accessKey, $bucket, $this->reqOpt); + if ($err != null) { + return array(null, $err); + } + $this->host = $upHostBackup; + } + + 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)); + } + + // 如果可以在已上传取到说明是过期分片直接修改已上传信息,否则是新的片添加到已上传分片尾部 + if (isset($this->contexts[$blockIndex])) { + $this->contexts[$blockIndex] = array( + 'ctx' => $ret['ctx'], + 'expiredAt' => $ret['expired_at'], + ); + } else { + array_push($this->contexts, array( + 'ctx' => $ret['ctx'], + 'expiredAt' => $ret['expired_at'], + )); + } + $uploaded += $blockSize; + + // 记录断点 + if ($this->resumeRecordFile !== null) { + $recordData = array( + 'contexts' => $this->contexts, + 'uploaded' => $uploaded + ); + $recordData = json_encode($recordData); + + if ($recordData) { + $isWritten = file_put_contents($this->resumeRecordFile, $recordData); + if ($isWritten === false) { + error_log("write resumeRecordFile failed"); + } + } else { + error_log('resumeRecordData encode failed'); + } + } + } + + // 完成上传 + list($ret, $err) = $this->makeFile($fname); + if ($err !== null) { + $response = $err->getResponse(); + if ($isResumeUpload && $response->statusCode === 701) { + fseek($this->inputStream, 0); + return $this->uploadV1($fname); + } + } + return array($ret, $err); + } + + /** + * @param string $fname 文件名 + * @param null|array $blkputRets + * + * @throws \Exception + */ + private function uploadV2($fname, $blkputRets = null) + { + $uploaded = 0; + $partNumber = 1; + $encodedObjectName = $this->key ? \Qiniu\base64_urlSafeEncode($this->key) : '~'; + $isResumeUpload = $blkputRets !== null; + + // 初始化 upload id + $err = null; + if ($blkputRets) { + 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 { + $err = $this->makeInitReq($encodedObjectName); + } + } else { + $err = $this->makeInitReq($encodedObjectName); + } + if ($err != null) { + return array(null, $err); + } + + // 上传分片 + fseek($this->inputStream, $uploaded); + while ($uploaded < $this->size) { + $blockSize = $this->blockSize($uploaded); + $data = fread($this->inputStream, $blockSize); + if ($data === false) { + throw new \Exception("file read failed", 1); + } + $md5 = md5($data); + $response = $this->uploadPart( + $data, + $partNumber, + $this->finishedEtags["uploadId"], + $encodedObjectName, + $md5 + ); + + $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); + } + list($upHostBackup, $err) = $this->config->getUpBackupHostV2($accessKey, $bucket, $this->reqOpt); + if ($err != null) { + return array(null, $err); + } + $this->host = $upHostBackup; + } + + if ($response->needRetry() || !isset($ret['md5']) || $md5 != $ret['md5']) { + $response = $this->uploadPart( + $data, + $partNumber, + $this->finishedEtags["uploadId"], + $encodedObjectName, + $md5 + ); + $ret = $response->json(); + } + if ($isResumeUpload && $response->statusCode === 612) { + return $this->uploadV2($fname); + } + 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; + $this->finishedEtags['uploaded'] = $uploaded; + + if ($this->resumeRecordFile !== null) { + $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'); + } + } + } + + list($ret, $err) = $this->completeParts($fname, $this->finishedEtags['uploadId'], $encodedObjectName); + if ($err !== null) { + $response = $err->getResponse(); + if ($isResumeUpload && $response->statusCode === 612) { + return $this->uploadV2($fname); + } + } + return array($ret, $err); + } + + /** + * 创建块 + */ + 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; + } + + /** + * 创建文件 + * + * @param string $fname 文件名 + * @return array{array | null, Error | null} + */ + private function makeFile($fname) + { + $url = $this->fileUrl($fname); + $body = implode(',', array_map(function ($ctx) { + return $ctx['ctx']; + }, $this->contexts)); + $response = $this->post($url, $body); + if ($response->needRetry()) { + $response = $this->post($url, $body); + } + if ($response->statusCode === 200 || $response->statusCode === 701) { + if ($this->resumeRecordFile !== null) { + @unlink($this->resumeRecordFile); + } + } + 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, $this->reqOpt); + } + + private function blockSize($uploaded) + { + if ($this->size < $uploaded + $this->partSize) { + return $this->size - $uploaded; + } + return $this->partSize; + } + + private function makeInitReq($encodedObjectName) + { + list($ret, $err) = $this->initReq($encodedObjectName); + + if ($ret == null) { + return $err; + } + + $this->finishedEtags["uploadId"] = $ret['uploadId']; + $this->finishedEtags["expiredAt"] = $ret['expireAt']; + return $err; + } + + /** + * 初始化上传任务 + */ + 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); + $ret = $response->json(); + if ($response->ok() && $ret != null) { + return array($ret, null); + } + + return array(null, new Error($url, $response)); + } + + /** + * 分块上传v2 + */ + private function uploadPart($block, $partNumber, $uploadId, $encodedObjectName, $md5) + { + $headers = array( + 'Authorization' => 'UpToken ' . $this->upToken, + 'Content-Type' => 'application/octet-stream', + 'Content-MD5' => $md5 + ); + $url = $this->host . '/buckets/' . $this->bucket . '/objects/' . $encodedObjectName . + '/uploads/' . $uploadId . '/' . $partNumber; + $response = $this->put($url, $block, $headers); + if ($response->statusCode === 612) { + if ($this->resumeRecordFile !== null) { + @unlink($this->resumeRecordFile); + } + } + return $response; + } + + /** + * 完成分片上传V2 + * + * @param string $fname 文件名 + * @param int $uploadId 由 {@see initReq} 获取 + * @param string $encodedObjectName 经过编码的存储路径 + * @return array{array | null, Error | null} + */ + 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'); + $metadata = array(); + $customVars = array(); + if ($this->params) { + foreach ($this->params as $k => $v) { + if (strpos($k, 'x:') === 0) { + $customVars[$k] = $v; + } elseif (strpos($k, 'x-qn-meta-') === 0) { + $metadata[$k] = $v; + } + } + } + if (empty($metadata)) { + $metadata = null; + } + if (empty($customVars)) { + $customVars = null; + } + $body = array( + 'fname' => $fname, + 'mimeType' => $this->mime, + 'metadata' => $metadata, + 'customVars' => $customVars, + '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->statusCode === 200 || $response->statusCode === 612) { + if ($this->resumeRecordFile !== null) { + @unlink($this->resumeRecordFile); + } + } + 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, $this->reqOpt); + } + + private function postWithHeaders($url, $data, $headers) + { + $this->currentUrl = $url; + return Client::post($url, $data, $headers, $this->reqOpt); + } +} diff --git a/php-sdk/src/Qiniu/Storage/UploadManager.php b/php-sdk/src/Qiniu/Storage/UploadManager.php new file mode 100644 index 0000000..fcd11fa --- /dev/null +++ b/php-sdk/src/Qiniu/Storage/UploadManager.php @@ -0,0 +1,176 @@ +config = $config; + + if ($reqOpt === null) { + $reqOpt = new RequestOptions(); + } + + $this->reqOpt = $reqOpt; + } + + /** + * 上传二进制流到七牛 + * + * @param string $upToken 上传凭证 + * @param string $key 上传文件名 + * @param string $data 上传二进制流 + * @param array $params 自定义变量,规格参考 + * http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar + * @param string $mime 上传数据的mimeType + * @param string $fname + * @param RequestOptions $reqOpt + * @return array 包含已上传文件的信息,类似: + * [ + * "hash" => "", + * "key" => "" + * ] + */ + public function put( + $upToken, + $key, + $data, + $params = null, + $mime = 'application/octet-stream', + $fname = "default_filename", + $reqOpt = null + ) { + $reqOpt = $reqOpt === null ? $this->reqOpt : $reqOpt; + + $params = self::trimParams($params); + return FormUploader::put( + $upToken, + $key, + $data, + $this->config, + $params, + $mime, + $fname, + $reqOpt + ); + } + + + /** + * 上传文件到七牛 + * + * @param string $upToken 上传凭证 + * @param string $key 上传文件名 + * @param string $filePath 上传文件的路径 + * @param array $params 定义变量,规格参考 + * http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar + * @param boolean $mime 上传数据的mimeType + * @param string $checkCrc 是否校验crc32 + * @param string $resumeRecordFile 断点续传文件路径 默认为null + * @param string $version 分片上传版本 目前支持v1/v2版本 默认v1 + * @param int $partSize 分片上传v2字段 默认大小为4MB 分片大小范围为1 MB - 1 GB + * + * @return array 包含已上传文件的信息,类似: + * [ + * "hash" => "", + * "key" => "" + * ] + * @throws \Exception + */ + public function putFile( + $upToken, + $key, + $filePath, + $params = null, + $mime = 'application/octet-stream', + $checkCrc = false, + $resumeRecordFile = null, + $version = 'v1', + $partSize = config::BLOCK_SIZE, + $reqOpt = null + ) { + $reqOpt = $reqOpt === null ? $this->reqOpt : $reqOpt; + + $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), + $reqOpt + ); + } + + $up = new ResumeUploader( + $upToken, + $key, + $file, + $size, + $params, + $mime, + $this->config, + $resumeRecordFile, + $version, + $partSize, + $reqOpt + ); + $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; + } +} diff --git a/php-sdk/src/Qiniu/Zone.php b/php-sdk/src/Qiniu/Zone.php new file mode 100644 index 0000000..50d60c6 --- /dev/null +++ b/php-sdk/src/Qiniu/Zone.php @@ -0,0 +1,58 @@ + $v) { + $keysValue[$k] = $v[$key]; + } + array_multisort($keysValue, $sort, $array); + return $array; + } + + /** + * Wrapper for JSON decode that implements error detection with helpful + * error messages. + * + * @param string $json JSON data to parse + * @param bool $assoc When true, returned objects will be converted + * into associative arrays. + * @param int $depth User specified recursion depth. + * + * @return mixed + * @throws \InvalidArgumentException if the JSON cannot be parsed. + * @link http://www.php.net/manual/en/function.json-decode.php + */ + function json_decode($json, $assoc = false, $depth = 512) + { + static $jsonErrors = array( + JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded', + JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch', + JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found', + JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON', + JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded' + ); + + if (empty($json)) { + return null; + } + $data = \json_decode($json, $assoc, $depth); + + if (JSON_ERROR_NONE !== json_last_error()) { + $last = json_last_error(); + throw new \InvalidArgumentException( + 'Unable to parse JSON data: ' + . (isset($jsonErrors[$last]) + ? $jsonErrors[$last] + : 'Unknown error') + ); + } + + return $data; + } + + /** + * 计算七牛API中的数据格式 + * + * @param string $bucket 待操作的空间名 + * @param string $key 待操作的文件名 + * + * @return string 符合七牛API规格的数据格式 + * @link https://developer.qiniu.com/kodo/api/data-format + */ + function entry($bucket, $key = null) + { + $en = $bucket; + if ($key !== null) { + $en = $bucket . ':' . $key; + } + return base64_urlSafeEncode($en); + } + + function decodeEntry($entry) + { + $en = base64_urlSafeDecode($entry); + $en = explode(':', $en); + if (count($en) == 1) { + return array($en[0], null); + } + return array($en[0], $en[1]); + } + + /** + * array 辅助方法,无值时不set + * + * @param array $array 待操作array + * @param string $key key + * @param string $value value 为null时 不设置 + * + * @return array 原来的array,便于连续操作 + */ + function setWithoutEmpty(&$array, $key, $value) + { + if (!empty($value)) { + $array[$key] = $value; + } + return $array; + } + + /** + * 缩略图链接拼接 + * + * @param string $url 图片链接 + * @param int $mode 缩略模式 + * @param int $width 宽度 + * @param int $height 长度 + * @param string $format 输出类型 + * @param int $quality 图片质量 + * @param int $interlace 是否支持渐进显示 + * @param int $ignoreError 忽略结果 + * @return string + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/imageview2.html + * @author Sherlock Ren + */ + function thumbnail( + $url, + $mode, + $width, + $height, + $format = null, + $quality = null, + $interlace = null, + $ignoreError = 1 + ) { + + static $imageUrlBuilder = null; + if (is_null($imageUrlBuilder)) { + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder; + } + + return call_user_func_array(array($imageUrlBuilder, 'thumbnail'), func_get_args()); + } + + /** + * 图片水印 + * + * @param string $url 图片链接 + * @param string $image 水印图片链接 + * @param numeric $dissolve 透明度 + * @param string $gravity 水印位置 + * @param numeric $dx 横轴边距 + * @param numeric $dy 纵轴边距 + * @param numeric $watermarkScale 自适应原图的短边比例 + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html + * @return string + * @author Sherlock Ren + */ + function waterImg( + $url, + $image, + $dissolve = 100, + $gravity = 'SouthEast', + $dx = null, + $dy = null, + $watermarkScale = null + ) { + + static $imageUrlBuilder = null; + if (is_null($imageUrlBuilder)) { + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder; + } + + return call_user_func_array(array($imageUrlBuilder, 'waterImg'), func_get_args()); + } + + /** + * 文字水印 + * + * @param string $url 图片链接 + * @param string $text 文字 + * @param string $font 文字字体 + * @param string $fontSize 文字字号 + * @param string $fontColor 文字颜色 + * @param numeric $dissolve 透明度 + * @param string $gravity 水印位置 + * @param numeric $dx 横轴边距 + * @param numeric $dy 纵轴边距 + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html#text-watermark + * @return string + * @author Sherlock Ren + */ + function waterText( + $url, + $text, + $font = '黑体', + $fontSize = 0, + $fontColor = null, + $dissolve = 100, + $gravity = 'SouthEast', + $dx = null, + $dy = null + ) { + + static $imageUrlBuilder = null; + if (is_null($imageUrlBuilder)) { + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder; + } + + return call_user_func_array(array($imageUrlBuilder, 'waterText'), func_get_args()); + } + + /** + * 从uptoken解析accessKey和bucket + * + * @param $upToken + * @return array(ak,bucket,err=null) + */ + function explodeUpToken($upToken) + { + $items = explode(':', $upToken); + if (count($items) != 3) { + return array(null, null, "invalid uptoken"); + } + $accessKey = $items[0]; + $putPolicy = json_decode(base64_urlSafeDecode($items[2])); + $scope = $putPolicy->scope; + $scopeItems = explode(':', $scope); + $bucket = $scopeItems[0]; + return array($accessKey, $bucket, null); + } + + // polyfill ucwords for `php version < 5.4.32` or `5.5.0 <= php version < 5.5.16` + if (version_compare(phpversion(), "5.4.32") < 0 || + ( + version_compare(phpversion(), "5.5.0") >= 0 && + version_compare(phpversion(), "5.5.16") < 0 + ) + ) { + function ucwords($str, $delimiters = " \t\r\n\f\v") + { + $delims = preg_split('//u', $delimiters, -1, PREG_SPLIT_NO_EMPTY); + + foreach ($delims as $delim) { + $str = implode($delim, array_map('ucfirst', explode($delim, $str))); + } + + return $str; + } + } else { + function ucwords($str, $delimiters) + { + return \ucwords($str, $delimiters); + } + } + + /** + * 将 parse_url 的结果转换回字符串 + * TODO: add unit test + * + * @param $parsed_url - parse_url 的结果 + * @return string + */ + function unparse_url($parsed_url) + { + + $scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : ''; + + $host = isset($parsed_url['host']) ? $parsed_url['host'] : ''; + + $port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : ''; + + $user = isset($parsed_url['user']) ? $parsed_url['user'] : ''; + + $pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : ''; + + $pass = ($user || $pass) ? "$pass@" : ''; + + $path = isset($parsed_url['path']) ? $parsed_url['path'] : ''; + + $query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : ''; + + $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : ''; + + return "$scheme$user$pass$host$port$path$query$fragment"; + } +} diff --git a/php-sdk/test-env.sh b/php-sdk/test-env.sh new file mode 100644 index 0000000..eedf6b5 --- /dev/null +++ b/php-sdk/test-env.sh @@ -0,0 +1,4 @@ +export QINIU_ACCESS_KEY=xxx +export QINIU_SECRET_KEY=xxx +export QINIU_TEST_BUCKET=phpsdk +export QINIU_TEST_DOMAIN=phpsdk.qiniudn.com \ No newline at end of file diff --git a/php-sdk/tests/Qiniu/Tests/AuthTest.php b/php-sdk/tests/Qiniu/Tests/AuthTest.php new file mode 100644 index 0000000..99aec85 --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/AuthTest.php @@ -0,0 +1,296 @@ +sign('test'); + $this->assertEquals('abcdefghklmnopq:mSNBTR7uS2crJsyFr2Amwv1LaYg=', $token); + } + + public function testSignWithData() + { + global $dummyAuth; + $token = $dummyAuth->signWithData('test'); + $this->assertEquals('abcdefghklmnopq:-jP8eEV9v48MkYiBGs81aDxl60E=:dGVzdA==', $token); + } + + public function testSignRequest() + { + global $dummyAuth; + $token = $dummyAuth->signRequest('http://www.qiniu.com?go=1', 'test', ''); + $this->assertEquals('abcdefghklmnopq:cFyRVoWrE3IugPIMP5YJFTO-O-Y=', $token); + $ctype = 'application/x-www-form-urlencoded'; + $token = $dummyAuth->signRequest('http://www.qiniu.com?go=1', 'test', $ctype); + $this->assertEquals($token, 'abcdefghklmnopq:svWRNcacOE-YMsc70nuIYdaa1e4='); + } + + public function testPrivateDownloadUrl() + { + global $dummyAuth; + $_SERVER['override_qiniu_auth_time'] = true; + $url = $dummyAuth->privateDownloadUrl('http://www.qiniu.com?go=1'); + $expect = 'http://www.qiniu.com?go=1&e=1234571490&token=abcdefghklmnopq:8vzBeLZ9W3E4kbBLFLW0Xe0u7v4='; + $this->assertEquals($expect, $url); + unset($_SERVER['override_qiniu_auth_time']); + } + + public function testUploadToken() + { + global $dummyAuth; + $_SERVER['override_qiniu_auth_time'] = true; + $token = $dummyAuth->uploadToken('1', '2', 3600, array('endUser' => 'y')); + // @codingStandardsIgnoreStart + $exp = 'abcdefghklmnopq:yyeexeUkPOROoTGvwBjJ0F0VLEo=:eyJlbmRVc2VyIjoieSIsInNjb3BlIjoiMToyIiwiZGVhZGxpbmUiOjEyMzQ1NzE0OTB9'; + // @codingStandardsIgnoreEnd + $this->assertEquals($exp, $token); + unset($_SERVER['override_qiniu_auth_time']); + } + + public function testSignQiniuAuthorization() + { + $auth = new Auth("ak", "sk"); + + $testCases = array( + array( + "url" => "", + "method" => "", + "headers" => array( + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + "Content-Type" => array("application/x-www-form-urlencoded") + ), + "body" => "{\"name\": \"test\"}", + "expectedToken" => "ak:0i1vKClRDWFyNkcTFzwcE7PzX74=" + ), + array( + "url" => "", + "method" => "", + "headers" => array( + "Content-Type" => array("application/json") + ), + "body" => "{\"name\": \"test\"}", + "expectedToken" => "ak:K1DI0goT05yhGizDFE5FiPJxAj4=" + ), + array( + "url" => "", + "method" => "GET", + "headers" => array( + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + "Content-Type" => array("application/x-www-form-urlencoded"), + ), + "body" => "{\"name\": \"test\"}", + "expectedToken" => "ak:0i1vKClRDWFyNkcTFzwcE7PzX74=" + ), + array( + "url" => "", + "method" => "POST", + "headers" => array( + "Content-Type" => array("application/json"), + "X-Qiniu" => array("b"), + ), + "body" => "{\"name\": \"test\"}", + "expectedToken" => "ak:0ujEjW_vLRZxebsveBgqa3JyQ-w=" + ), + array( + "url" => "http://upload.qiniup.com", + "method" => "", + "headers" => array( + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + "Content-Type" => array("application/x-www-form-urlencoded"), + ), + "body" => "{\"name\": \"test\"}", + "expectedToken" => "ak:GShw5NitGmd5TLoo38nDkGUofRw=" + ), + array( + "url" => "http://upload.qiniup.com", + "method" => "", + "headers" => array( + "Content-Type" => array("application/json"), + "X-Qiniu-Bbb" => array("BBB", "AAA"), + "X-Qiniu-Aaa" => array("DDD", "CCC"), + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + ), + "body" => "{\"name\": \"test\"}", + "expectedToken" => "ak:DhNA1UCaBqSHCsQjMOLRfVn63GQ=" + ), + array( + "url" => "http://upload.qiniup.com", + "method" => "", + "headers" => array( + "Content-Type" => array("application/x-www-form-urlencoded"), + "X-Qiniu-Bbb" => array("BBB", "AAA"), + "X-Qiniu-Aaa" => array("DDD", "CCC"), + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + ), + "body" => "name=test&language=go", + "expectedToken" => "ak:KUAhrYh32P9bv0COD8ugZjDCmII=" + ), + array( + "url" => "http://upload.qiniup.com", + "method" => "", + "headers" => array( + "Content-Type" => array("application/x-www"), + "Content-Type" => array("application/x-www-form-urlencoded"), + "X-Qiniu-Bbb" => array("BBB", "AAA"), + "X-Qiniu-Aaa" => array("DDD", "CCC"), + ), + "body" => "name=test&language=go", + "expectedToken" => "ak:KUAhrYh32P9bv0COD8ugZjDCmII=" + ), + array( + "url" => "http://upload.qiniup.com/mkfile/sdf.jpg", + "method" => "", + "headers" => array( + "Content-Type" => array("application/x-www-form-urlencoded"), + "X-Qiniu-Bbb" => array("BBB", "AAA"), + "X-Qiniu-Aaa" => array("DDD", "CCC"), + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + ), + "body" => "name=test&language=go", + "expectedToken" => "ak:fkRck5_LeyfwdkyyLk-hyNwGKac=" + ), + array( + "url" => "http://upload.qiniup.com/mkfile/sdf.jpg?s=er3&df", + "method" => "", + "headers" => array( + "Content-Type" => array("application/x-www-form-urlencoded"), + "X-Qiniu-Bbb" => array("BBB", "AAA"), + "X-Qiniu-Aaa" => array("DDD", "CCC"), + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + ), + "body" => "name=test&language=go", + "expectedToken" => "ak:PUFPWsEUIpk_dzUvvxTTmwhp3p4=" + ) + ); + + foreach ($testCases as $testCase) { + list($sign, $err) = $auth->signQiniuAuthorization( + $testCase["url"], + $testCase["method"], + $testCase["body"], + new Header($testCase["headers"]) + ); + + $this->assertNull($err); + $this->assertEquals($testCase["expectedToken"], $sign); + } + } + + public function testDisableQiniuTimestampSignatureDefault() + { + $auth = new Auth("ak", "sk"); + $authedHeaders = $auth->authorizationV2("https://example.com", "GET"); + $this->assertArrayHasKey("X-Qiniu-Date", $authedHeaders); + } + + public function testDisableQiniuTimestampSignature() + { + $auth = new Auth("ak", "sk", array( + "disableQiniuTimestampSignature" => true + )); + $authedHeaders = $auth->authorizationV2("https://example.com", "GET"); + $this->assertArrayNotHasKey("X-Qiniu-Date", $authedHeaders); + } + public function testDisableQiniuTimestampSignatureEnv() + { + putenv("DISABLE_QINIU_TIMESTAMP_SIGNATURE=true"); + $auth = new Auth("ak", "sk"); + $authedHeaders = $auth->authorizationV2("https://example.com", "GET"); + $this->assertArrayNotHasKey("X-Qiniu-Date", $authedHeaders); + putenv('DISABLE_QINIU_TIMESTAMP_SIGNATURE'); + } + public function testDisableQiniuTimestampSignatureEnvBeIgnored() + { + putenv("DISABLE_QINIU_TIMESTAMP_SIGNATURE=true"); + $auth = new Auth("ak", "sk", array( + "disableQiniuTimestampSignature" => false + )); + $authedHeaders = $auth->authorizationV2("https://example.com", "GET"); + $this->assertArrayHasKey("X-Qiniu-Date", $authedHeaders); + putenv('DISABLE_QINIU_TIMESTAMP_SIGNATURE'); + } + public function testQboxVerifyCallbackShouldOkWithRequiredOptions() + { + $auth = new Auth('abcdefghklmnopq', '1234567890'); + $ok = $auth->verifyCallback( + 'application/x-www-form-urlencoded', + 'QBox abcdefghklmnopq:T7F-SjxX7X2zI4Fc1vANiNt1AUE=', + 'https://test.qiniu.com/callback', + 'name=sunflower.jpg&hash=Fn6qeQi4VDLQ347NiRm-RlQx_4O2&location=Shanghai&price=1500.00&uid=123' + ); + $this->assertTrue($ok); + } + public function testQboxVerifyCallbackShouldOkWithOmitOptions() + { + $auth = new Auth('abcdefghklmnopq', '1234567890'); + $ok = $auth->verifyCallback( + 'application/x-www-form-urlencoded', + 'QBox abcdefghklmnopq:T7F-SjxX7X2zI4Fc1vANiNt1AUE=', + 'https://test.qiniu.com/callback', + 'name=sunflower.jpg&hash=Fn6qeQi4VDLQ347NiRm-RlQx_4O2&location=Shanghai&price=1500.00&uid=123', + 'POST', // this should be omit + array( + 'X-Qiniu-Bbb' => 'BBB' + ) // this should be omit + ); + $this->assertTrue($ok); + } + public function testQiniuVerifyCallbackShouldOk() + { + $auth = new Auth('abcdefghklmnopq', '1234567890'); + $ok = $auth->verifyCallback( + 'application/x-www-form-urlencoded', + 'Qiniu abcdefghklmnopq:ZqS7EZuAKrhZaEIxqNGxDJi41IQ=', + 'https://test.qiniu.com/callback', + 'name=sunflower.jpg&hash=Fn6qeQi4VDLQ347NiRm-RlQx_4O2&location=Shanghai&price=1500.00&uid=123', + 'GET', + array( + 'X-Qiniu-Bbb' => 'BBB' + ) + ); + $this->assertTrue($ok); + } + public function testQiniuVerifyCallbackShouldFailed() + { + $auth = new Auth('abcdefghklmnopq', '1234567890'); + $ok = $auth->verifyCallback( + 'application/x-www-form-urlencoded', + 'Qiniu abcdefghklmnopq:ZqS7EZuAKrhZaEIxqNGxDJi41IQ=', + 'https://test.qiniu.com/callback', + 'name=sunflower.jpg&hash=Fn6qeQi4VDLQ347NiRm-RlQx_4O2&location=Shanghai&price=1500.00&uid=123', + 'POST', + array( + 'X-Qiniu-Bbb' => 'BBB' + ) + ); + $this->assertFalse($ok); + } + } +} diff --git a/php-sdk/tests/Qiniu/Tests/Base64Test.php b/php-sdk/tests/Qiniu/Tests/Base64Test.php new file mode 100644 index 0000000..fed3da0 --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/Base64Test.php @@ -0,0 +1,16 @@ +assertEquals($a, \Qiniu\base64_urlSafeDecode($b)); + } +} diff --git a/php-sdk/tests/Qiniu/Tests/BucketTest.php b/php-sdk/tests/Qiniu/Tests/BucketTest.php new file mode 100644 index 0000000..0467698 --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/BucketTest.php @@ -0,0 +1,733 @@ +batch($ops); + } + + private static function getObjectKey($key) + { + $result = $key . rand(); + + self::$bucketManager->copy( + self::$bucketName, + $key, + self::$bucketName, + $result + ); + + self::$keysToCleanup[] = $result; + + return $result; + } + + public function testBuckets() + { + + list($list, $error) = self::$bucketManager->buckets(); + $this->assertNull($error); + $this->assertTrue(in_array(self::$bucketName, $list)); + + list($list2, $error) = self::$dummyBucketManager->buckets(); + $this->assertEquals(401, $error->code()); + $this->assertNotNull($error->message()); + $this->assertNotNull($error->getResponse()); + $this->assertNull($list2); + } + + public function testListBuckets() + { + list($ret, $error) = self::$bucketManager->listbuckets('z0'); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testCreateBucket() + { + list($ret, $error) = self::$bucketManager->createBucket(self::$bucketToCreate); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testDeleteBucket() + { + list($ret, $error) = self::$bucketManager->deleteBucket(self::$bucketToCreate); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testDomains() + { + list($ret, $error) = self::$bucketManager->domains(self::$bucketName); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testBucketInfo() + { + list($ret, $error) = self::$bucketManager->bucketInfo(self::$bucketName); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testBucketInfos() + { + list($ret, $error) = self::$bucketManager->bucketInfos('z0'); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testList() + { + list($ret, $error) = self::$bucketManager->listFiles(self::$bucketName, null, null, 10); + $this->assertNull($error); + $this->assertNotNull($ret['items'][0]); + $this->assertNotNull($ret['marker']); + } + + public function testListFilesv2() + { + list($ret, $error) = self::$bucketManager->listFilesv2(self::$bucketName, null, null, 10); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testBucketLifecycleRule() + { + // delete + self::$bucketManager->deleteBucketLifecycleRule(self::$bucketName, self::$bucketLifeRuleName); + + // add + list($ret, $error) = self::$bucketManager->bucketLifecycleRule( + self::$bucketName, + self::$bucketLifeRuleName, + self::$bucketLifeRulePrefix, + 80, + 70, + 72, + 74, + 71 + ); + $this->assertNull($error); + $this->assertNotNull($ret); + + // get + list($ret, $error) = self::$bucketManager->getBucketLifecycleRules(self::$bucketName); + $this->assertNull($error); + $this->assertNotNull($ret); + $rule = null; + foreach ($ret as $r) { + if ($r["name"] === self::$bucketLifeRuleName) { + $rule = $r; + break; + } + } + $this->assertNotNull($rule); + $this->assertEquals(self::$bucketLifeRulePrefix, $rule["prefix"]); + $this->assertEquals(80, $rule["delete_after_days"]); + $this->assertEquals(70, $rule["to_line_after_days"]); + $this->assertEquals(71, $rule["to_archive_ir_after_days"]); + $this->assertEquals(72, $rule["to_archive_after_days"]); + $this->assertEquals(74, $rule["to_deep_archive_after_days"]); + + // update + list($ret, $error) = self::$bucketManager->updateBucketLifecycleRule( + self::$bucketName, + self::$bucketLifeRuleName, + 'update-' . self::$bucketLifeRulePrefix, + 90, + 75, + 80, + 85, + 78 + ); + $this->assertNull($error); + $this->assertNotNull($ret); + + // get + list($ret, $error) = self::$bucketManager->getBucketLifecycleRules(self::$bucketName); + $this->assertNull($error); + $this->assertNotNull($ret); + $rule = null; + foreach ($ret as $r) { + if ($r["name"] === self::$bucketLifeRuleName) { + $rule = $r; + break; + } + } + $this->assertNotNull($rule); + $this->assertEquals('update-' . self::$bucketLifeRulePrefix, $rule["prefix"]); + $this->assertEquals(90, $rule["delete_after_days"]); + $this->assertEquals(75, $rule["to_line_after_days"]); + $this->assertEquals(78, $rule["to_archive_ir_after_days"]); + $this->assertEquals(80, $rule["to_archive_after_days"]); + $this->assertEquals(85, $rule["to_deep_archive_after_days"]); + + // delete + list($ret, $error) = self::$bucketManager->deleteBucketLifecycleRule( + self::$bucketName, + self::$bucketLifeRuleName + ); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testPutBucketEvent() + { + list($ret, $error) = self::$bucketManager->putBucketEvent( + self::$bucketName, + self::$bucketEventName, + self::$bucketEventPrefix, + 'img', + array('copy'), + self::$customCallbackURL + ); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testUpdateBucketEvent() + { + list($ret, $error) = self::$bucketManager->updateBucketEvent( + self::$bucketName, + self::$bucketEventName, + self::$bucketEventPrefix, + 'video', + array('copy'), + self::$customCallbackURL + ); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testGetBucketEvents() + { + list($ret, $error) = self::$bucketManager->getBucketEvents(self::$bucketName); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testDeleteBucketEvent() + { + list($ret, $error) = self::$bucketManager->deleteBucketEvent(self::$bucketName, self::$bucketEventName); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testStat() + { + list($stat, $error) = self::$bucketManager->stat(self::$bucketName, self::$key); + $this->assertNull($error); + $this->assertNotNull($stat); + $this->assertNotNull($stat['hash']); + + list($stat, $error) = self::$bucketManager->stat(self::$bucketName, 'nofile'); + $this->assertEquals(612, $error->code()); + $this->assertNotNull($error->message()); + $this->assertNull($stat); + + list($stat, $error) = self::$bucketManager->stat('nobucket', 'nofile'); + $this->assertEquals(631, $error->code()); + $this->assertNotNull($error->message()); + $this->assertNull($stat); + } + + public function testDelete() + { + $fileToDel = self::getObjectKey(self::$key); + list(, $error) = self::$bucketManager->delete(self::$bucketName, $fileToDel); + $this->assertNull($error); + } + + + public function testRename() + { + $fileToRename = self::getObjectKey(self::$key); + $fileRenamed = $fileToRename . 'new'; + list(, $error) = self::$bucketManager->rename(self::$bucketName, $fileToRename, $fileRenamed); + $this->assertNull($error); + self::$keysToCleanup[] = $fileRenamed; + } + + + public function testCopy() + { + $fileToCopy = self::getObjectKey(self::$key2); + $fileCopied = $fileToCopy . 'copied'; + + //test force copy + list(, $error) = self::$bucketManager->copy( + self::$bucketName, + $fileToCopy, + self::$bucketName, + $fileCopied, + true + ); + $this->assertNull($error); + + list($fileToCopyStat,) = self::$bucketManager->stat(self::$bucketName, $fileToCopy); + list($fileCopiedStat,) = self::$bucketManager->stat(self::$bucketName, $fileCopied); + + $this->assertEquals($fileToCopyStat['hash'], $fileCopiedStat['hash']); + + self::$keysToCleanup[] = $fileCopied; + } + + + public function testChangeMime() + { + $fileToChange = self::getObjectKey('php-sdk.html'); + list(, $error) = self::$bucketManager->changeMime( + self::$bucketName, + $fileToChange, + 'text/plain' + ); + $this->assertNull($error); + + list($ret, $error) = self::$bucketManager->stat( + self::$bucketName, + $fileToChange + ); + $this->assertNull($error); + $this->assertEquals('text/plain', $ret['mimeType']); + } + + public function testPrefetch() + { + list($ret, $error) = self::$bucketManager->prefetch( + self::$bucketName, + 'php-sdk.html' + ); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testPrefetchFailed() + { + list($ret, $error) = self::$bucketManager->prefetch( + 'fakebucket', + 'php-sdk.html' + ); + $this->assertNotNull($error); + $this->assertNull($ret); + } + + public function testFetch() + { + list($ret, $error) = self::$bucketManager->fetch( + 'http://developer.qiniu.com/docs/v6/sdk/php-sdk.html', + self::$bucketName, + 'fetch.html' + ); + $this->assertNull($error); + $this->assertArrayHasKey('hash', $ret); + + list($ret, $error) = self::$bucketManager->fetch( + 'http://developer.qiniu.com/docs/v6/sdk/php-sdk.html', + self::$bucketName, + '' + ); + $this->assertNull($error); + $this->assertArrayHasKey('key', $ret); + + list($ret, $error) = self::$bucketManager->fetch( + 'http://developer.qiniu.com/docs/v6/sdk/php-sdk.html', + self::$bucketName + ); + $this->assertNull($error); + $this->assertArrayHasKey('key', $ret); + } + + public function testFetchFailed() + { + list($ret, $error) = self::$bucketManager->fetch( + 'http://developer.qiniu.com/docs/v6/sdk/php-sdk.html', + 'fakebucket' + ); + $this->assertNotNull($error); + $this->assertNull($ret); + } + + public function testAsynchFetch() + { + list($ret, $error) = self::$bucketManager->asynchFetch( + 'http://devtools.qiniu.com/qiniu.png', + self::$bucketName, + null, + 'qiniu.png' + ); + $this->assertNull($error); + $this->assertArrayHasKey('id', $ret); + + list($ret, $error) = self::$bucketManager->asynchFetch( + 'http://devtools.qiniu.com/qiniu.png', + self::$bucketName, + null, + '' + ); + $this->assertNull($error); + $this->assertArrayHasKey('id', $ret); + + list($ret, $error) = self::$bucketManager->asynchFetch( + 'http://devtools.qiniu.com/qiniu.png', + self::$bucketName + ); + $this->assertNull($error); + $this->assertArrayHasKey('id', $ret); + } + + public function testAsynchFetchFailed() + { + list($ret, $error) = self::$bucketManager->asynchFetch( + 'http://devtools.qiniu.com/qiniu.png', + 'fakebucket' + ); + $this->assertNotNull($error); + $this->assertNull($ret); + } + + + public function testBatchCopy() + { + $key = 'copyto' . rand(); + $ops = BucketManager::buildBatchCopy( + self::$bucketName, + array(self::$key => $key), + self::$bucketName, + true + ); + list($ret, $error) = self::$bucketManager->batch($ops); + $this->assertNull($error); + $this->assertEquals(200, $ret[0]['code']); + + self::$keysToCleanup[] = $key; + } + + public function testBatchMove() + { + $fileToMove = self::getObjectKey(self::$key); + $fileMoved = $fileToMove . 'to'; + $ops = BucketManager::buildBatchMove( + self::$bucketName, + array($fileToMove => $fileMoved), + self::$bucketName, + true + ); + list($ret, $error) = self::$bucketManager->batch($ops); + $this->assertNull($error); + $this->assertEquals(200, $ret[0]['code']); + self::$keysToCleanup[] = $fileMoved; + } + + public function testBatchRename() + { + $fileToRename = self::getObjectKey(self::$key); + $fileRenamed = $fileToRename . 'to'; + + $ops = BucketManager::buildBatchRename( + self::$bucketName, + array($fileToRename => $fileRenamed), + true + ); + list($ret, $error) = self::$bucketManager->batch($ops); + $this->assertNull($error); + $this->assertEquals(200, $ret[0]['code']); + + self::$keysToCleanup[] = $fileRenamed; + } + + public function testBatchStat() + { + $ops = BucketManager::buildBatchStat(self::$bucketName, array('php-sdk.html')); + list($ret, $error) = self::$bucketManager->batch($ops); + $this->assertNull($error); + $this->assertEquals(200, $ret[0]['code']); + } + + public function testBatchChangeTypeAndBatchRestoreAr() + { + $key = self::getObjectKey(self::$key); + + $ops = BucketManager::buildBatchChangeType(self::$bucketName, array($key => 2)); // 2 Archive + list($ret, $error) = self::$bucketManager->batch($ops); + $this->assertNull($error); + $this->assertEquals(200, $ret[0]['code']); + + $ops = BucketManager::buildBatchRestoreAr(self::$bucketName, array($key => 1)); // 1 day + list($ret, $error) = self::$bucketManager->batch($ops); + $this->assertNull($error); + $this->assertEquals(200, $ret[0]['code']); + } + + public function testDeleteAfterDays() + { + $key = "noexist" . rand(); + list($ret, $error) = self::$bucketManager->deleteAfterDays(self::$bucketName, $key, 1); + $this->assertNotNull($error); + $this->assertNull($ret); + + $key = self::getObjectKey(self::$key); + list(, $error) = self::$bucketManager->deleteAfterDays(self::$bucketName, $key, 1); + $this->assertNull($error); + + list($ret, $error) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($error); + $this->assertGreaterThan(23 * 3600, $ret['expiration'] - time()); + $this->assertLessThan(48 * 3600, $ret['expiration'] - time()); + } + + public function testSetObjectLifecycle() + { + $key = self::getObjectKey(self::$key); + + list(, $err) = self::$bucketManager->setObjectLifecycle( + self::$bucketName, + $key, + 10, + 20, + 30, + 40, + 15 + ); + $this->assertNull($err); + + list($ret, $error) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($error); + $this->assertNotNull($ret['transitionToIA']); + $this->assertNotNull($ret['transitionToArchiveIR']); + $this->assertNotNull($ret['transitionToARCHIVE']); + $this->assertNotNull($ret['transitionToDeepArchive']); + $this->assertNotNull($ret['expiration']); + } + + public function testSetObjectLifecycleWithCond() + { + $key = self::getObjectKey(self::$key); + + list($ret, $err) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($err); + $key_hash = $ret['hash']; + $key_fsize = $ret['fsize']; + + list(, $err) = self::$bucketManager->setObjectLifecycleWithCond( + self::$bucketName, + $key, + array( + 'hash' => $key_hash, + 'fsize' => $key_fsize + ), + 10, + 20, + 30, + 40, + 15 + ); + $this->assertNull($err); + + list($ret, $error) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($error); + $this->assertNotNull($ret['transitionToIA']); + $this->assertNotNull($ret['transitionToArchiveIR']); + $this->assertNotNull($ret['transitionToARCHIVE']); + $this->assertNotNull($ret['transitionToDeepArchive']); + $this->assertNotNull($ret['expiration']); + } + + public function testBatchSetObjectLifecycle() + { + $key = self::getObjectKey(self::$key); + + $ops = BucketManager::buildBatchSetObjectLifecycle( + self::$bucketName, + array($key), + 10, + 20, + 30, + 40, + 15 + ); + list($ret, $err) = self::$bucketManager->batch($ops); + $this->assertNull($err); + $this->assertEquals(200, $ret[0]['code']); + } + + public function testGetCorsRules() + { + list(, $err) = self::$bucketManager->getCorsRules(self::$bucketName); + $this->assertNull($err); + } + + public function testPutBucketAccessStyleMode() + { + list(, $err) = self::$bucketManager->putBucketAccessStyleMode(self::$bucketName, 0); + $this->assertNull($err); + } + + public function testPutBucketAccessMode() + { + list(, $err) = self::$bucketManager->putBucketAccessMode(self::$bucketName, 0); + $this->assertNull($err); + } + + public function testPutReferAntiLeech() + { + list(, $err) = self::$bucketManager->putReferAntiLeech(self::$bucketName, 0, "1", "*"); + $this->assertNull($err); + } + + public function testPutBucketMaxAge() + { + list(, $err) = self::$bucketManager->putBucketMaxAge(self::$bucketName, 31536000); + $this->assertNull($err); + } + + public function testPutBucketQuota() + { + list(, $err) = self::$bucketManager->putBucketQuota(self::$bucketName, -1, -1); + $this->assertNull($err); + } + + public function testGetBucketQuota() + { + list(, $err) = self::$bucketManager->getBucketQuota(self::$bucketName); + $this->assertNull($err); + } + + public function testChangeType() + { + $fileToChange = self::getObjectKey(self::$key); + + list(, $err) = self::$bucketManager->changeType(self::$bucketName, $fileToChange, 0); + $this->assertNull($err); + + list(, $err) = self::$bucketManager->changeType(self::$bucketName, $fileToChange, 1); + $this->assertNull($err); + } + + public function testArchiveRestoreAr() + { + $key = self::getObjectKey(self::$key); + + self::$bucketManager->changeType(self::$bucketName, $key, 2); + + list(, $err) = self::$bucketManager->restoreAr(self::$bucketName, $key, 2); + $this->assertNull($err); + + list($ret, $err) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($err); + + $this->assertEquals(2, $ret["type"]); + + // restoreStatus + // null means frozen; + // 1 means be unfreezing; + // 2 means be unfrozen; + $this->assertNotNull($ret["restoreStatus"]); + $this->assertContains($ret["restoreStatus"], array(1, 2)); + } + + public function testDeepArchiveRestoreAr() + { + $key = self::getObjectKey(self::$key); + + self::$bucketManager->changeType(self::$bucketName, $key, 3); + + list(, $err) = self::$bucketManager->restoreAr(self::$bucketName, $key, 1); + $this->assertNull($err); + list($ret, $err) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($err); + + $this->assertEquals(3, $ret["type"]); + + // restoreStatus + // null means frozen; + // 1 means be unfreezing; + // 2 means be unfrozen; + $this->assertNotNull($ret["restoreStatus"]); + $this->assertContains($ret["restoreStatus"], array(1, 2)); + } + + public function testChangeStatus() + { + $key = self::getObjectKey(self::$key); + + list(, $err) = self::$bucketManager->changeStatus(self::$bucketName, $key, 1); + $this->assertNull($err); + list($ret, $err) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($err); + $this->assertEquals(1, $ret['status']); + + list(, $err) = self::$bucketManager->changeStatus(self::$bucketName, $key, 0); + $this->assertNull($err); + list($ret, $err) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($err); + $this->assertArrayNotHasKey('status', $ret); + } +} diff --git a/php-sdk/tests/Qiniu/Tests/CdnManagerTest.php b/php-sdk/tests/Qiniu/Tests/CdnManagerTest.php new file mode 100644 index 0000000..baa9486 --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/CdnManagerTest.php @@ -0,0 +1,151 @@ +cdnManager = new CdnManager($testAuth); + + global $timestampAntiLeechEncryptKey; + $this->encryptKey = $timestampAntiLeechEncryptKey; + + global $testStartDate; + $this->testStartDate = $testStartDate; + + global $testEndDate; + $this->testEndDate = $testEndDate; + + global $testGranularity; + $this->testGranularity = $testGranularity; + + global $testLogDate; + $this->testLogDate = $testLogDate; + + global $customDomain; + $this->refreshUrl = $customDomain . '/sdktest.png'; + $this->refreshDirs = $customDomain; + $this->customDomain = $customDomain; + + global $customDomain2; + $this->customDomain2 = $customDomain2; + } + + public function testRefreshUrls() + { + list($ret, $err) = $this->cdnManager->refreshUrls(array($this->refreshUrl)); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testRefreshDirs() + { + list($ret, $err) = $this->cdnManager->refreshDirs(array($this->refreshDirs)); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testRefreshUrlsAndDirs() + { + list($ret, $err) = $this->cdnManager->refreshUrlsAndDirs(array($this->refreshUrl), array($this->refreshDirs)); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testGetCdnRefreshList() + { + list($ret, $err) = $this->cdnManager->getCdnRefreshList(null, null, null, 'success'); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testPrefetchUrls() + { + list($ret, $err) = $this->cdnManager->prefetchUrls(array($this->refreshUrl)); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testGetCdnPrefetchList() + { + list($ret, $err) = $this->cdnManager->getCdnPrefetchList(null, null, 'success'); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testGetBandwidthData() + { + list($ret, $err) = $this->cdnManager->getBandwidthData( + array($this->customDomain2), + $this->testStartDate, + $this->testEndDate, + $this->testGranularity + ); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testGetFluxData() + { + list($ret, $err) = $this->cdnManager->getFluxData( + array($this->customDomain2), + $this->testStartDate, + $this->testEndDate, + $this->testGranularity + ); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testGetCdnLogList() + { + $domain = getenv('QINIU_TEST_DOMAIN'); + list($ret, $err) = $this->cdnManager->getCdnLogList(array($domain), $this->testLogDate); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testCreateTimestampAntiLeechUrl() + { + $signUrl = $this->cdnManager->createTimestampAntiLeechUrl($this->refreshUrl, $this->encryptKey, 3600); + $response = Client::get($signUrl); + $this->assertNull($response->error); + $this->assertEquals($response->statusCode, 200); + + $signUrl = $this->cdnManager->createTimestampAntiLeechUrl( + $this->refreshUrl . '?qiniu', + $this->encryptKey, + 3600 + ); + $response = Client::get($signUrl); + $this->assertNull($response->error); + $this->assertEquals($response->statusCode, 200); + } +} diff --git a/php-sdk/tests/Qiniu/Tests/ConfigTest.php b/php-sdk/tests/Qiniu/Tests/ConfigTest.php new file mode 100644 index 0000000..3c39a5c --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/ConfigTest.php @@ -0,0 +1,118 @@ +accessKey = $accessKey; + global $bucketName; + $this->bucketName = $bucketName; + } + + public function testGetApiHost() + { + $conf = new Config(); + $hasException = false; + $apiHost = ''; + try { + $apiHost = $conf->getApiHost($this->accessKey, $this->bucketName); + } catch (\Exception $e) { + $hasException = true; + } + $this->assertFalse($hasException); + } + + public function testGetApiHostErrored() + { + $conf = new Config(); + $hasException = false; + try { + $conf->getApiHost($this->accessKey, "fakebucket"); + } catch (\Exception $e) { + $hasException = true; + } + $this->assertTrue($hasException); + } + + public function testGetApiHostV2() + { + $conf = new Config(); + list($apiHost, $err) = $conf->getApiHostV2($this->accessKey, $this->bucketName); + $this->assertNull($err); + } + + public function testGetApiHostV2Errored() + { + $conf = new Config(); + list($apiHost, $err) = $conf->getApiHostV2($this->accessKey, "fakebucket"); + $this->assertNotNull($err->code()); + $this->assertEquals(631, $err->code()); + $this->assertNull($apiHost); + } + + public function testSetUcHost() + { + $conf = new Config(); + $this->assertEquals('http://' . Config::UC_HOST, $conf->getUcHost()); + $conf->setUcHost("uc.example.com"); + $this->assertEquals("http://uc.example.com", $conf->getUcHost()); + + $conf = new Config(); + $conf->useHTTPS = true; + $this->assertEquals('https://' . Config::UC_HOST, $conf->getUcHost()); + $conf->setUcHost("uc.example.com"); + $this->assertEquals("https://uc.example.com", $conf->getUcHost()); + } + + public function testGetRegionWithCustomDomain() + { + $conf = new Config(); + $conf->setQueryRegionHost( + "uc.qbox.me" + ); + list(, $err) = $conf->getRsHostV2($this->accessKey, $this->bucketName); + $this->assertNull($err); + } + + public function testGetRegionWithBackupDomains() + { + $conf = new Config(); + $conf->setQueryRegionHost( + "fake-uc.phpsdk.qiniu.com", + array( + "unavailable-uc.phpsdk.qiniu.com", + Config::UC_HOST // real uc + ) + ); + list(, $err) = $conf->getRsHostV2($this->accessKey, $this->bucketName); + $this->assertNull($err); + } + + public function testGetRegionWithUcAndBackupDomains() + { + $conf = new Config(); + $conf->setUcHost("fake-uc.phpsdk.qiniu.com"); + $conf->setBackupQueryRegionHosts( + array( + "unavailable-uc.phpsdk.qiniu.com", + Config::UC_HOST // real uc + ) + ); + list(, $err) = $conf->getRsHostV2($this->accessKey, $this->bucketName); + $this->assertNull($err); + } + } +} diff --git a/php-sdk/tests/Qiniu/Tests/Crc32Test.php b/php-sdk/tests/Qiniu/Tests/Crc32Test.php new file mode 100644 index 0000000..63e24fd --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/Crc32Test.php @@ -0,0 +1,23 @@ +assertEquals('1352841281', $b); + } + + public function testFile() + { + $b = \Qiniu\crc32_file(__file__); + $c = \Qiniu\crc32_file(__file__); + $this->assertEquals($c, $b); + } +} diff --git a/php-sdk/tests/Qiniu/Tests/DownloadTest.php b/php-sdk/tests/Qiniu/Tests/DownloadTest.php new file mode 100644 index 0000000..9b4b034 --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/DownloadTest.php @@ -0,0 +1,27 @@ +privateDownloadUrl($base_url); + $response = Client::get($private_url); + $this->assertEquals(200, $response->statusCode); + } + + public function testFop() + { + global $testAuth; + $base_url = 'http://sdk.peterpy.cn/gogopher.jpg?exif'; + $private_url = $testAuth->privateDownloadUrl($base_url); + $response = Client::get($private_url); + $this->assertEquals(200, $response->statusCode); + } +} diff --git a/php-sdk/tests/Qiniu/Tests/EntryTest.php b/php-sdk/tests/Qiniu/Tests/EntryTest.php new file mode 100644 index 0000000..73bfac4 --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/EntryTest.php @@ -0,0 +1,88 @@ +assertEquals('cWluaXVwaG90b3M6Z29nb3BoZXIuanBn', $encodeEntryURI); + } + + public function testKeyEmpty() + { + $bucket = 'qiniuphotos'; + $key = ''; + $encodeEntryURI = Qiniu\entry($bucket, $key); + $this->assertEquals('cWluaXVwaG90b3M6', $encodeEntryURI); + } + + public function testKeyNull() + { + $bucket = 'qiniuphotos'; + $key = null; + $encodeEntryURI = Qiniu\entry($bucket, $key); + $this->assertEquals('cWluaXVwaG90b3M=', $encodeEntryURI); + } + + public function testKeyNeedReplacePlusSymbol() + { + $bucket = 'qiniuphotos'; + $key = '012ts>a'; + $encodeEntryURI = Qiniu\entry($bucket, $key); + $this->assertEquals('cWluaXVwaG90b3M6MDEydHM-YQ==', $encodeEntryURI); + } + + public function testKeyNeedReplaceSlashSymbol() + { + $bucket = 'qiniuphotos'; + $key = '012ts?a'; + $encodeEntryURI = Qiniu\entry($bucket, $key); + $this->assertEquals('cWluaXVwaG90b3M6MDEydHM_YQ==', $encodeEntryURI); + } + public function testDecodeEntry() + { + $entry = 'cWluaXVwaG90b3M6Z29nb3BoZXIuanBn'; + list($bucket, $key) = Qiniu\decodeEntry($entry); + $this->assertEquals('qiniuphotos', $bucket); + $this->assertEquals('gogopher.jpg', $key); + } + + public function testDecodeEntryWithEmptyKey() + { + $entry = 'cWluaXVwaG90b3M6'; + list($bucket, $key) = Qiniu\decodeEntry($entry); + $this->assertEquals('qiniuphotos', $bucket); + $this->assertEquals('', $key); + } + + public function testDecodeEntryWithNullKey() + { + $entry = 'cWluaXVwaG90b3M='; + list($bucket, $key) = Qiniu\decodeEntry($entry); + $this->assertEquals('qiniuphotos', $bucket); + $this->assertNull($key); + } + + public function testDecodeEntryWithPlusSymbol() + { + $entry = 'cWluaXVwaG90b3M6MDEydHM-YQ=='; + list($bucket, $key) = Qiniu\decodeEntry($entry); + $this->assertEquals('qiniuphotos', $bucket); + $this->assertEquals('012ts>a', $key); + } + + public function testDecodeEntryWithSlashSymbol() + { + $entry = 'cWluaXVwaG90b3M6MDEydHM_YQ=='; + list($bucket, $key) = Qiniu\decodeEntry($entry); + $this->assertEquals('qiniuphotos', $bucket); + $this->assertEquals('012ts?a', $key); + } +} diff --git a/php-sdk/tests/Qiniu/Tests/EtagTest.php b/php-sdk/tests/Qiniu/Tests/EtagTest.php new file mode 100644 index 0000000..4e09a78 --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/EtagTest.php @@ -0,0 +1,54 @@ +assertEquals('Fto5o-5ea0sNMlW_75VgGJCv2AcJ', $r); + $this->assertNull($error); + } + + public function testLess4M() + { + $file = qiniuTempFile(3 * 1024 * 1024, false); + list($r, $error) = Etag::sum($file); + unlink($file); + $this->assertEquals('Fs5BpnAjRykYTg6o5E09cjuXrDkG', $r); + $this->assertNull($error); + } + + public function test4M() + { + $file = qiniuTempFile(4 * 1024 * 1024, false); + list($r, $error) = Etag::sum($file); + unlink($file); + $this->assertEquals('FiuKULnybewpEnrfTmxjsxc-3dWp', $r); + $this->assertNull($error); + } + + public function testMore4M() + { + $file = qiniuTempFile(5 * 1024 * 1024, false); + list($r, $error) = Etag::sum($file); + unlink($file); + $this->assertEquals('lhvyfIWMYFTq4s4alzlhXoAkqfVL', $r); + $this->assertNull($error); + } + + public function test8M() + { + $file = qiniuTempFile(8 * 1024 * 1024, false); + list($r, $error) = Etag::sum($file); + unlink($file); + $this->assertEquals('lmRm9ZfGZ86bnMys4wRTWtJj9ClG', $r); + $this->assertNull($error); + } +} diff --git a/php-sdk/tests/Qiniu/Tests/FopTest.php b/php-sdk/tests/Qiniu/Tests/FopTest.php new file mode 100644 index 0000000..42b7997 --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/FopTest.php @@ -0,0 +1,39 @@ +execute('gogopher.jpg', 'exif'); + $this->assertNull($error); + $this->assertNotNull($exif); + } + + public function testExifPrivate() + { + global $testAuth; + $fop = new Operation('private-res.qiniudn.com', $testAuth); + list($exif, $error) = $fop->execute('noexif.jpg', 'exif'); + $this->assertNotNull($error); + $this->assertNull($exif); + } + + public function testbuildUrl() + { + $fops = 'imageView2/2/h/200'; + $fop = new Operation('testres.qiniudn.com'); + $url = $fop->buildUrl('gogopher.jpg', $fops); + $this->assertEquals($url, 'http://testres.qiniudn.com/gogopher.jpg?imageView2/2/h/200'); + + $fops = array('imageView2/2/h/200', 'imageInfo'); + $url = $fop->buildUrl('gogopher.jpg', $fops); + $this->assertEquals($url, 'http://testres.qiniudn.com/gogopher.jpg?imageView2/2/h/200|imageInfo'); + } +} diff --git a/php-sdk/tests/Qiniu/Tests/FormUpTest.php b/php-sdk/tests/Qiniu/Tests/FormUpTest.php new file mode 100644 index 0000000..f75794e --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/FormUpTest.php @@ -0,0 +1,205 @@ +batch($ops); + } + + private static function getObjectKey($key) + { + $result = $key . rand(); + self::$keysToCleanup[] = $result; + return $result; + } + + public function testData() + { + $key = self::getObjectKey('formput'); + $token = self::$auth->uploadToken(self::$bucketName); + list($ret, $error) = FormUploader::put($token, $key, 'hello world', self::$cfg, null, 'text/plain', null); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testDataWithProxy() + { + $key = self::getObjectKey('formput'); + $token = self::$auth->uploadToken(self::$bucketName); + list($ret, $error) = FormUploader::put( + $token, + $key, + 'hello world', + self::$cfg, + null, + 'text/plain', + null, + $this->makeReqOpt() + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testData2() + { + $key = self::getObjectKey('formput'); + $upManager = new UploadManager(); + $token = self::$auth->uploadToken(self::$bucketName); + list($ret, $error) = $upManager->put($token, $key, 'hello world', null, 'text/plain', null); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testData2WithProxy() + { + $key = self::getObjectKey('formput'); + $upManager = new UploadManager(); + $token = self::$auth->uploadToken(self::$bucketName); + list($ret, $error) = $upManager->put( + $token, + $key, + 'hello world', + null, + 'text/plain', + null, + $this->makeReqOpt() + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testDataFailed() + { + $key = self::getObjectKey('formput'); + $token = self::$auth->uploadToken('fakebucket'); + list($ret, $error) = FormUploader::put( + $token, + $key, + 'hello world', + self::$cfg, + null, + 'text/plain', + null + ); + $this->assertNull($ret); + $this->assertNotNull($error); + } + + public function testFile() + { + $key = self::getObjectKey('formPutFile'); + $token = self::$auth->uploadToken(self::$bucketName, $key); + list($ret, $error) = FormUploader::putFile( + $token, + $key, + __file__, + self::$cfg, + null, + 'text/plain', + null + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testFileWithProxy() + { + $key = self::getObjectKey('formPutFile'); + $token = self::$auth->uploadToken(self::$bucketName, $key); + list($ret, $error) = FormUploader::putFile( + $token, + $key, + __file__, + self::$cfg, + null, + 'text/plain', + $this->makeReqOpt() + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testFile2() + { + $key = self::getObjectKey('formPutFile'); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $upManager = new UploadManager(); + list($ret, $error) = $upManager->putFile($token, $key, __file__, null, 'text/plain', null); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testFile2WithProxy() + { + $key = self::getObjectKey('formPutFile'); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $upManager = new UploadManager(); + list($ret, $error) = $upManager->putFile( + $token, + $key, + __file__, + null, + 'text/plain', + false, + null, + 'v1', + Config::BLOCK_SIZE, + $this->makeReqOpt() + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testFileFailed() + { + $key = self::getObjectKey('fakekey'); + $token = self::$auth->uploadToken('fakebucket', $key); + list($ret, $error) = FormUploader::putFile($token, $key, __file__, self::$cfg, null, 'text/plain', null); + $this->assertNull($ret); + $this->assertNotNull($error); + } + + private function makeReqOpt() + { + $reqOpt = new RequestOptions(); + $reqOpt->proxy = 'socks5://127.0.0.1:8080'; + $reqOpt->proxy_user_password = 'user:pass'; + return $reqOpt; + } +} diff --git a/php-sdk/tests/Qiniu/Tests/HeaderTest.php b/php-sdk/tests/Qiniu/Tests/HeaderTest.php new file mode 100644 index 0000000..28af5f3 --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/HeaderTest.php @@ -0,0 +1,184 @@ + array('200'), + ':x-test-1' => array('hello1'), + ':x-Test-2' => array('hello2'), + 'content-type' => array('application/json'), + 'CONTENT-LENGTH' => array(1234), + 'oRiGin' => array('https://www.qiniu.com'), + 'ReFer' => array('www.qiniu.com'), + 'Last-Modified' => array('Mon, 06 Sep 2021 06:44:52 GMT'), + 'acCePt-ChArsEt' => array('utf-8'), + 'x-test-3' => array('hello3'), + 'cache-control' => array('no-cache', 'no-store'), + ); + + public function testNormalizeKey() + { + $except = array( + ':status', + ':x-test-1', + ':x-Test-2', + 'Content-Type', + 'Content-Length', + 'Origin', + 'Refer', + 'Last-Modified', + 'Accept-Charset', + 'X-Test-3', + 'Cache-Control' + ); + $actual = array_map(function ($str) { + return Header::normalizeKey($str); + }, array_keys($this->heads)); + $this->assertEquals($actual, $except); + } + + + public function testInvalidKeyName() + { + $except = array( + 'a:x-test-1', + ); + + $actual = array_map(function ($str) { + return Header::normalizeKey($str); + }, $except); + + $this->assertEquals($except, $actual); + } + + public function testGetRawData() + { + $header = new Header($this->heads); + foreach ($this->heads as $k => $v) { + $rawHeader = $header->getRawData(); + $this->assertEquals($v, $rawHeader[Header::normalizeKey($k)]); + } + } + + public function testOffsetExists() + { + $header = new Header($this->heads); + foreach (array_keys($this->heads) as $k) { + $this->assertNotNull($header[$k]); + } + + $except = array( + ':status', + ':x-test-1', + ':x-Test-2', + 'Content-Type', + 'Content-Length', + 'Origin', + 'Refer', + 'Last-Modified', + 'Accept-Charset', + 'X-Test-3', + 'Cache-Control' + ); + foreach ($except as $k) { + $this->assertNotNull($header[$k], $k." is null"); + } + } + + public function testOffsetGet() + { + $header = new Header($this->heads); + foreach ($this->heads as $k => $v) { + $this->assertEquals($v[0], $header[$k]); + } + + $this->assertNull($header['no-exist']); + } + + public function testOffsetSet() + { + $header = new Header($this->heads); + $header["X-Test-3"] = "hello"; + $this->assertEquals("hello", $header["X-Test-3"]); + $header["x-test-3"] = "hello test3"; + $this->assertEquals("hello test3", $header["x-test-3"]); + $header[":x-Test-2"] = "hello"; + $this->assertEquals("hello", $header[":x-Test-2"]); + $header[":x-test-2"] = "hello test2"; + $this->assertEquals("hello", $header[":x-Test-2"]); + } + + public function testOffsetUnset() + { + $header = new Header($this->heads); + unset($header["X-Test-3"]); + $this->assertFalse(isset($header["X-Test-3"])); + + $header = new Header($this->heads); + unset($header["x-test-3"]); + $this->assertFalse(isset($header["x-test-3"])); + + $header = new Header($this->heads); + unset($header[":x-test-2"]); + $this->assertTrue(isset($header[":x-Test-2"])); + + $header = new Header($this->heads); + unset($header[":x-Test-2"]); + $this->assertFalse(isset($header[":x-Test-2"])); + } + + public function testGetIterator() + { + $header = new Header($this->heads); + + $hasException = false; + try { + foreach ($header as $k => $v) { + $hasException = !isset($header[$k]); + } + } catch (\Exception $e) { + $hasException = true; + } + $this->assertFalse($hasException); + } + + public function testEmptyHeaderIterator() + { + $emptyHeader = new Header(); + + $hasException = false; + try { + foreach ($emptyHeader as $k => $v) { + $hasException = !isset($header[$k]); + } + } catch (\Exception $e) { + $hasException = true; + } + $this->assertFalse($hasException); + } + + public function testCount() + { + $header = new Header($this->heads); + + $this->assertEquals(count($this->heads), count($header)); + } + + public function testFromRaw() + { + $lines = array(); + foreach ($this->heads as $k => $vs) { + foreach ($vs as $v) { + array_push($lines, $k . ": " . $v); + } + } + $raw = implode("\r\n", $lines); + $headerFromRaw = Header::fromRawText($raw); + $this->assertEquals(new Header($this->heads), $headerFromRaw); + } +} diff --git a/php-sdk/tests/Qiniu/Tests/HttpTest.php b/php-sdk/tests/Qiniu/Tests/HttpTest.php new file mode 100644 index 0000000..c122f8e --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/HttpTest.php @@ -0,0 +1,163 @@ +assertEquals(200, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNull($response->error); + } + + public function testGetQiniu() + { + $response = Client::get('upload.qiniu.com'); + $this->assertEquals(405, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNotNull($response->xReqId()); + $this->assertNotNull($response->xLog()); + $this->assertNotNull($response->error); + } + + public function testGetTimeout() + { + $reqOpt = new RequestOptions(); + $reqOpt->timeout = 1; + $response = Client::get('localhost:9000/timeout.php', array(), $reqOpt); + $this->assertEquals(-1, $response->statusCode); + } + + public function testGetRedirect() + { + $response = Client::get('localhost:9000/redirect.php'); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals('application/json;charset=UTF-8', $response->normalizedHeaders['Content-Type']); + $respData = $response->json(); + $this->assertEquals('ok', $respData['msg']); + } + + public function testDelete() + { + $response = Client::delete('uc.qbox.me/bucketTagging', array()); + $this->assertEquals(401, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNotNull($response->error); + } + + public function testDeleteQiniu() + { + $response = Client::delete('uc.qbox.me/bucketTagging', array()); + $this->assertEquals(401, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNotNull($response->xReqId()); + $this->assertNotNull($response->xLog()); + $this->assertNotNull($response->error); + } + + public function testDeleteTimeout() + { + $reqOpt = new RequestOptions(); + $reqOpt->timeout = 1; + $response = Client::delete('localhost:9000/timeout.php', array(), $reqOpt); + $this->assertEquals(-1, $response->statusCode); + } + + + public function testPost() + { + $response = Client::post('qiniu.com', null); + $this->assertEquals(200, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNull($response->error); + } + + public function testPostQiniu() + { + $response = Client::post('upload.qiniu.com', null); + $this->assertEquals(400, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNotNull($response->xReqId()); + $this->assertNotNull($response->xLog()); + $this->assertNotNull($response->error); + } + + public function testPostTimeout() + { + $reqOpt = new RequestOptions(); + $reqOpt->timeout = 1; + $response = Client::post('localhost:9000/timeout.php', null, array(), $reqOpt); + $this->assertEquals(-1, $response->statusCode); + } + + public function testSocks5Proxy() + { + $reqOpt = new RequestOptions(); + $reqOpt->proxy = 'socks5://localhost:8080'; + $response = Client::post('qiniu.com', null, array(), $reqOpt); + $this->assertEquals(-1, $response->statusCode); + + $reqOpt->proxy_user_password = 'user:pass'; + $response = Client::post('qiniu.com', null, array(), $reqOpt); + $this->assertEquals(200, $response->statusCode); + } + + public function testPut() + { + $response = Client::PUT('uc.qbox.me/bucketTagging', null); + $this->assertEquals(401, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNotNull($response->error); + } + + public function testPutQiniu() + { + $response = Client::put('uc.qbox.me/bucketTagging', null); + $this->assertEquals(401, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNotNull($response->xReqId()); + $this->assertNotNull($response->xLog()); + $this->assertNotNull($response->error); + } + + + public function testPutTimeout() + { + $reqOpt = new RequestOptions(); + $reqOpt->timeout = 1; + $response = Client::put('localhost:9000/timeout.php', null, array(), $reqOpt); + $this->assertEquals(-1, $response->statusCode); + } + + public function testNeedRetry() + { + $testCases = array_merge( + array(array(-1, true)), + array_map(function ($i) { + return array($i, false); + }, range(100, 499)), + array_map(function ($i) { + if (in_array($i, array( + 501, 509, 573, 579, 608, 612, 614, 616, 618, 630, 631, 632, 640, 701 + ))) { + return array($i, false); + } + return array($i, true); + }, range(500, 799)) + ); + $resp = new Response(-1, 222, array(), '{"msg": "mock"}', null); + foreach ($testCases as $testCase) { + list($code, $expectNeedRetry) = $testCase; + $resp->statusCode = $code; + $msg = $resp->statusCode . ' need' . ($expectNeedRetry ? '' : ' NOT') . ' retry'; + $this->assertEquals($expectNeedRetry, $resp->needRetry(), $msg); + } + } +} diff --git a/php-sdk/tests/Qiniu/Tests/ImageUrlBuilderTest.php b/php-sdk/tests/Qiniu/Tests/ImageUrlBuilderTest.php new file mode 100644 index 0000000..486323c --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/ImageUrlBuilderTest.php @@ -0,0 +1,263 @@ + + */ +class ImageUrlBuilderTest extends TestCase +{ + /** + * 缩略图测试 + * + * @test + * @return void + * @author Sherlock Ren + */ + public function testThumbutl() + { + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder(); + $url = 'http://78re52.com1.z0.glb.clouddn.com/resource/gogopher.jpg'; + $url2 = $url . '?watermark/1/gravity/SouthEast/dx/0/dy/0/image/' + . 'aHR0cDovL2Fkcy1jZG4uY2h1Y2h1amllLmNvbS9Ga1R6bnpIY2RLdmRBUFc5cHZZZ3pTc21UY0tB'; + // 异常测试 + $this->assertEquals($url, $imageUrlBuilder->thumbnail($url, 1, 0, 0)); + $this->assertEquals($url, \Qiniu\thumbnail($url, 1, 0, 0)); + + // 简单缩略测试 + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/ignore-error/1/', + $imageUrlBuilder->thumbnail($url, 1, 200, 200) + ); + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/ignore-error/1/', + \Qiniu\thumbnail($url, 1, 200, 200) + ); + + // 输出格式测试 + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/', + $imageUrlBuilder->thumbnail($url, 1, 200, 200, 'png') + ); + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/', + \Qiniu\thumbnail($url, 1, 200, 200, 'png') + ); + + // 渐进显示测试 + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/format/png/interlace/1/ignore-error/1/', + $imageUrlBuilder->thumbnail($url, 1, 200, 200, 'png', 1) + ); + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/', + \Qiniu\thumbnail($url, 1, 200, 200, 'png', 2) + ); + + // 图片质量测试 + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/format/png/interlace/1/q/80/ignore-error/1/', + $imageUrlBuilder->thumbnail($url, 1, 200, 200, 'png', 1, 80) + ); + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/format/png/interlace/1/ignore-error/1/', + \Qiniu\thumbnail($url, 1, 200, 200, 'png', 1, 101) + ); + + // 多参数测试 + $this->assertEquals( + $url2 . '|imageView2/1/w/200/h/200/ignore-error/1/', + $imageUrlBuilder->thumbnail($url2, 1, 200, 200) + ); + $this->assertEquals( + $url2 . '|imageView2/1/w/200/h/200/ignore-error/1/', + \Qiniu\thumbnail($url2, 1, 200, 200) + ); + } + + /** + * 图片水印测试 + * + * @test + * @param void + * @return void + * @author Sherlock Ren + */ + public function waterImgTest() + { + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder(); + $url = 'http://78re52.com1.z0.glb.clouddn.com/resource/gogopher.jpg'; + $url2 = $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/'; + $image = 'http://developer.qiniu.com/resource/logo-2.jpg'; + + // 水印简单测试 + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + $imageUrlBuilder->waterImg($url, $image) + ); + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/gravity/SouthEast/', + $imageUrlBuilder->waterImg($url, $image, 101) + ); + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==/', + $imageUrlBuilder->waterImg($url, $image, 101, 'sdfsd') + ); + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + \Qiniu\waterImg($url, $image) + ); + + // 横轴边距测试 + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/dx/10/', + $imageUrlBuilder->waterImg($url, $image, 100, 'SouthEast', 10) + ); + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + \Qiniu\waterImg($url, $image, 100, 'SouthEast', 'sad') + ); + + // 纵轴边距测试 + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/dx/10/dy/10/', + $imageUrlBuilder->waterImg($url, $image, 100, 'SouthEast', 10, 10) + ); + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + \Qiniu\waterImg($url, $image, 100, 'SouthEast', 'sad', 'asdf') + ); + + // 自适应原图的短边比例测试 + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/dx/10/dy/10/ws/0.5/', + $imageUrlBuilder->waterImg($url, $image, 100, 'SouthEast', 10, 10, 0.5) + ); + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + \Qiniu\waterImg($url, $image, 100, 'SouthEast', 'sad', 'asdf', 2) + ); + + // 多参数测试 + $this->assertEquals( + $url2 . '|watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + $imageUrlBuilder->waterImg($url2, $image) + ); + $this->assertEquals( + $url2 . '|watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + \Qiniu\waterImg($url2, $image) + ); + } + + /** + * 文字水印测试 + * + * @test + * @param void + * @return void + * @author Sherlock Ren + */ + public function waterTextTest() + { + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder(); + $url = 'http://78re52.com1.z0.glb.clouddn.com/resource/gogopher.jpg'; + $url2 = $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/'; + $text = '测试一下'; + $font = '微软雅黑'; + $fontColor = '#FF0000'; + + // 水印简单测试 + $this->assertEquals($url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/' + . 'fontsize/500/dissolve/100/gravity/SouthEast/', $imageUrlBuilder->waterText($url, $text, $font, 500)); + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/' + . 'dissolve/100/gravity/SouthEast/', + \Qiniu\waterText($url, $text, $font, 'sdf') + ); + + // 字体颜色测试 + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/' + . 'I0ZGMDAwMA==/dissolve/100/gravity/SouthEast/', + $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor) + ); + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA==' + . '/dissolve/100/gravity/SouthEast/', + \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor) + ); + + // 透明度测试 + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/I0ZGMDAwMA==' + . '/dissolve/80/gravity/SouthEast/', + $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor, 80) + ); + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA==' + . '/gravity/SouthEast/', + \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor, 101) + ); + + // 水印位置测试 + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/I0ZGMDAwMA==' + . '/dissolve/80/gravity/East/', + $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor, 80, 'East') + ); + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA==/', + \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor, 101, 'sdfsdf') + ); + + // 横轴距离测试 + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/I0ZGMDAwMA==' + . '/dissolve/80/gravity/East/dx/10/', + $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor, 80, 'East', 10) + ); + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA==/', + \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor, 101, 'sdfsdf', 'sdfs') + ); + + // 纵轴距离测试 + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/I0ZGMDAwMA==' + . '/dissolve/80/gravity/East/dx/10/dy/10/', + $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor, 80, 'East', 10, 10) + ); + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA==/', + \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor, 101, 'sdfsdf', 'sdfs', 'ssdf') + ); + // 多参数测试 + $this->assertEquals( + $url2 . '|watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/' + . 'fontsize/500/dissolve/100/gravity/SouthEast/', + $imageUrlBuilder->waterText($url2, $text, $font, 500) + ); + $this->assertEquals( + $url2 . '|watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/' + . 'fontsize/500/dissolve/100/gravity/SouthEast/', + \Qiniu\waterText($url2, $text, $font, 500) + ); + } +} diff --git a/php-sdk/tests/Qiniu/Tests/MiddlewareTest.php b/php-sdk/tests/Qiniu/Tests/MiddlewareTest.php new file mode 100644 index 0000000..969cad4 --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/MiddlewareTest.php @@ -0,0 +1,160 @@ + + */ + private $orderRecorder; + + /** + * @var string + */ + private $label; + + public function __construct(&$orderRecorder, $label) + { + $this->orderRecorder =& $orderRecorder; + $this->label = $label; + } + + public function send($request, $next) + { + $this->orderRecorder[] = "bef_" . $this->label . count($this->orderRecorder); + $response = $next($request); + $this->orderRecorder[] = "aft_" . $this->label . count($this->orderRecorder); + return $response; + } +} + +class MiddlewareTest extends TestCase +{ + public function testSendWithMiddleware() + { + $orderRecorder = array(); + + $reqOpt = new RequestOptions(); + $reqOpt->middlewares = array( + new RecorderMiddleware($orderRecorder, "A"), + new RecorderMiddleware($orderRecorder, "B") + ); + + $request = new Request( + "GET", + "http://localhost:9000/ok.php", + array(), + null, + $reqOpt + ); + $response = Client::sendRequestWithMiddleware($request); + + $expectRecords = array( + "bef_A0", + "bef_B1", + "aft_B2", + "aft_A3" + ); + + $this->assertEquals($expectRecords, $orderRecorder); + $this->assertEquals(200, $response->statusCode); + } + + public function testSendWithRetryDomains() + { + $orderRecorder = array(); + + $reqOpt = new RequestOptions(); + $reqOpt->middlewares = array( + new Middleware\RetryDomainsMiddleware( + array( + "unavailable.phpsdk.qiniu.com", + "localhost:9000", + ), + 3 + ), + new RecorderMiddleware($orderRecorder, "rec") + ); + + $request = new Request( + "GET", + "http://fake.phpsdk.qiniu.com/ok.php", + array(), + null, + $reqOpt + ); + $response = Client::sendRequestWithMiddleware($request); + + $expectRecords = array( + // 'fake.phpsdk.qiniu.com' with retried 3 times + 'bef_rec0', + 'aft_rec1', + 'bef_rec2', + 'aft_rec3', + 'bef_rec4', + 'aft_rec5', + + // 'unavailable.pysdk.qiniu.com' with retried 3 times + 'bef_rec6', + 'aft_rec7', + 'bef_rec8', + 'aft_rec9', + 'bef_rec10', + 'aft_rec11', + + // 'qiniu.com' and it's success + 'bef_rec12', + 'aft_rec13' + ); + + $this->assertEquals($expectRecords, $orderRecorder); + $this->assertEquals(200, $response->statusCode); + } + + public function testSendFailFastWithRetryDomains() + { + $orderRecorder = array(); + + $reqOpt = new RequestOptions(); + $reqOpt->middlewares = array( + new Middleware\RetryDomainsMiddleware( + array( + "unavailable.phpsdk.qiniu.com", + "localhost:9000", + ), + 3, + function () { + return false; + } + ), + new RecorderMiddleware($orderRecorder, "rec") + ); + + $request = new Request( + "GET", + "http://fake.phpsdk.qiniu.com/ok.php", + array(), + null, + $reqOpt + ); + $response = Client::sendRequestWithMiddleware($request); + + $expectRecords = array( + // 'fake.phpsdk.qiniu.com' will fail fast + 'bef_rec0', + 'aft_rec1' + ); + $this->assertEquals($expectRecords, $orderRecorder); + $this->assertEquals(-1, $response->statusCode); + } +} diff --git a/php-sdk/tests/Qiniu/Tests/PfopTest.php b/php-sdk/tests/Qiniu/Tests/PfopTest.php new file mode 100644 index 0000000..77d06ec --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/PfopTest.php @@ -0,0 +1,304 @@ +execute($bucket, $key, $fops); + $this->assertNull($error); + list($status, $error) = $pfop->status($id); + $this->assertNotNull($status); + $this->assertNull($error); + } + + + public function testPfopExecuteAndStatusWithMultipleFops() + { + global $testAuth; + $bucket = 'testres'; + $key = 'sintel_trailer.mp4'; + $fops = array( + 'avthumb/m3u8/segtime/10/vcodec/libx264/s/320x240', + 'vframe/jpg/offset/7/w/480/h/360', + ); + $pfop = new PersistentFop($testAuth, self::getConfig()); + + list($id, $error) = $pfop->execute($bucket, $key, $fops); + $this->assertNull($error); + + list($status, $error) = $pfop->status($id); + $this->assertNotNull($status); + $this->assertNull($error); + } + + private function pfopOptionsTestData() + { + return array( + array( + 'type' => null + ), + array( + 'type' => -1 + ), + array( + 'type' => 0 + ), + array( + 'type' => 1 + ), + array( + 'type' => 2 + ), + array( + 'workflowTemplateID' => 'test-workflow' + ) + ); + } + + public function testPfopExecuteWithOptions() + { + $bucket = self::$bucketName; + $key = 'qiniu.png'; + $pfop = new PersistentFop(self::$testAuth, self::getConfig()); + + $testCases = $this->pfopOptionsTestData(); + + foreach ($testCases as $testCase) { + $workflowTemplateID = null; + $type = null; + + if (array_key_exists('workflowTemplateID', $testCase)) { + $workflowTemplateID = $testCase['workflowTemplateID']; + } + if (array_key_exists('type', $testCase)) { + $type = $testCase['type']; + } + + if ($workflowTemplateID) { + $fops = null; + } else { + $persistentEntry = \Qiniu\entry( + $bucket, + implode( + '_', + array( + 'test-pfop/test-pfop-by-api', + 'type', + $type + ) + ) + ); + $fops = 'avinfo|saveas/' . $persistentEntry; + } + list($id, $error) = $pfop->execute( + $bucket, + $key, + $fops, + null, + null, + false, + $type, + $workflowTemplateID + ); + + if (in_array($type, array(null, 0, 1))) { + $this->assertNull($error); + list($status, $error) = $pfop->status($id); + $this->assertNotNull($status); + $this->assertNull($error); + if ($type == 1) { + $this->assertEquals(1, $status['type']); + } + if ($workflowTemplateID) { + // assertStringContainsString when PHPUnit >= 8.0 + $this->assertTrue( + strpos( + $status['taskFrom'], + $workflowTemplateID + ) !== false + ); + } + $this->assertNotEmpty($status['creationDate']); + } else { + $this->assertNotNull($error); + } + } + } + + public function testPfopWithInvalidArgument() + { + $bucket = self::$bucketName; + $key = 'qiniu.png'; + $pfop = new PersistentFop(self::$testAuth, self::getConfig()); + $err = null; + try { + $pfop->execute( + $bucket, + $key + ); + } catch (\Exception $e) { + $err = $e; + } + + $this->assertNotEmpty($err); + $this->assertTrue( + strpos( + $err->getMessage(), + 'Must provide one of fops or template_id' + ) !== false + ); + } + + public function testPfopWithUploadPolicy() + { + $bucket = self::$bucketName; + $testAuth = self::$testAuth; + $key = 'test-pfop/upload-file'; + + $testCases = $this->pfopOptionsTestData(); + + foreach ($testCases as $testCase) { + $workflowTemplateID = null; + $type = null; + + if (array_key_exists('workflowTemplateID', $testCase)) { + $workflowTemplateID = $testCase['workflowTemplateID']; + } + if (array_key_exists('type', $testCase)) { + $type = $testCase['type']; + } + + $putPolicy = array( + 'persistentType' => $type + ); + if ($workflowTemplateID) { + $putPolicy['persistentWorkflowTemplateID'] = $workflowTemplateID; + } else { + $persistentEntry = \Qiniu\entry( + $bucket, + implode( + '_', + array( + 'test-pfop/test-pfop-by-upload', + 'type', + $type + ) + ) + ); + $putPolicy['persistentOps'] = 'avinfo|saveas/' . $persistentEntry; + } + + if ($type == null) { + unset($putPolicy['persistentType']); + } + + $token = $testAuth->uploadToken( + $bucket, + $key, + 3600, + $putPolicy + ); + $upManager = new UploadManager(self::getConfig()); + list($ret, $error) = $upManager->putFile( + $token, + $key, + __file__, + null, + 'text/plain', + true + ); + + if (in_array($type, array(null, 0, 1))) { + $this->assertNull($error); + $this->assertNotEmpty($ret['persistentId']); + $id = $ret['persistentId']; + } else { + $this->assertNotNull($error); + return; + } + + $pfop = new PersistentFop($testAuth, self::getConfig()); + list($status, $error) = $pfop->status($id); + + $this->assertNotNull($status); + $this->assertNull($error); + if ($type == 1) { + $this->assertEquals(1, $status['type']); + } + if ($workflowTemplateID) { + // assertStringContainsString when PHPUnit >= 8.0 + $this->assertTrue( + strpos( + $status['taskFrom'], + $workflowTemplateID + ) !== false + ); + } + $this->assertNotEmpty($status['creationDate']); + } + } + + public function testMkzip() + { + $bucket = self::$bucketName; + $key = 'php-logo.png'; + $pfop = new PersistentFop(self::$testAuth, null); + + $url1 = 'http://phpsdk.qiniudn.com/php-logo.png'; + $url2 = 'http://phpsdk.qiniudn.com/php-sdk.html'; + $zipKey = 'test.zip'; + + $fops = 'mkzip/2/url/' . \Qiniu\base64_urlSafeEncode($url1); + $fops .= '/url/' . \Qiniu\base64_urlSafeEncode($url2); + $fops .= '|saveas/' . \Qiniu\base64_urlSafeEncode("$bucket:$zipKey"); + + list($id, $error) = $pfop->execute($bucket, $key, $fops); + $this->assertNull($error); + + list($status, $error) = $pfop->status($id); + $this->assertNotNull($status); + $this->assertNull($error); + } +} diff --git a/php-sdk/tests/Qiniu/Tests/ResumeUpTest.php b/php-sdk/tests/Qiniu/Tests/ResumeUpTest.php new file mode 100644 index 0000000..6feee55 --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/ResumeUpTest.php @@ -0,0 +1,354 @@ +batch($ops); + } + + private static function getObjectKey($key) + { + $result = $key . rand(); + self::$keysToCleanup[] = $result; + return $result; + } + + public function test4ML() + { + $key = self::getObjectKey('resumePutFile4ML_'); + $upManager = new UploadManager(); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $tempFile = qiniuTempFile(4 * 1024 * 1024 + 10); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + list($ret, $error) = $upManager->putFile( + $token, + $key, + $tempFile, + null, + 'application/octet-stream', + false, + $resumeFile + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + + $domain = getenv('QINIU_TEST_DOMAIN'); + $response = Client::get("http://$domain/$key"); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals(md5_file($tempFile, true), md5($response->body(), true)); + unlink($tempFile); + } + + public function test4ML2() + { + $key = self::getObjectKey('resumePutFile4ML_'); + $cfg = new Config(); + $upManager = new UploadManager($cfg); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $tempFile = qiniuTempFile(4 * 1024 * 1024 + 10); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + list($ret, $error) = $upManager->putFile( + $token, + $key, + $tempFile, + null, + 'application/octet-stream', + false, + $resumeFile + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + + $domain = getenv('QINIU_TEST_DOMAIN'); + $response = Client::get("http://$domain/$key"); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals(md5_file($tempFile, true), md5($response->body(), true)); + unlink($tempFile); + } + + public function test4ML2WithProxy() + { + $key = self::getObjectKey('resumePutFile4ML_'); + $cfg = new Config(); + $upManager = new UploadManager($cfg); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $tempFile = qiniuTempFile(4 * 1024 * 1024 + 10); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + list($ret, $error) = $upManager->putFile( + $token, + $key, + $tempFile, + null, + 'application/octet-stream', + false, + $resumeFile, + 'v2', + Config::BLOCK_SIZE, + $this->makeReqOpt() + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + + $domain = getenv('QINIU_TEST_DOMAIN'); + $response = Client::get("http://$domain/$key"); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals(md5_file($tempFile, true), md5($response->body(), true)); + unlink($tempFile); + } + + // public function test8M() + // { + // $key = 'resumePutFile8M'; + // $upManager = new UploadManager(); + // $token = self::$auth->uploadToken(self::$bucketName, $key); + // $tempFile = qiniuTempFile(8*1024*1024+10); + // list($ret, $error) = $upManager->putFile($token, $key, $tempFile); + // $this->assertNull($error); + // $this->assertNotNull($ret['hash']); + // unlink($tempFile); + // } + + public function testFileWithFileType() + { + $config = new Config(); + $bucketManager = new BucketManager(self::$auth, $config); + + $testCases = array( + array( + "fileType" => 1, + "name" => "IA" + ), + array( + "fileType" => 2, + "name" => "Archive" + ), + array( + "fileType" => 3, + "name" => "DeepArchive" + ) + ); + + foreach ($testCases as $testCase) { + $key = self::getObjectKey('FileType' . $testCase["name"]); + $police = array( + "fileType" => $testCase["fileType"], + ); + $token = self::$auth->uploadToken(self::$bucketName, $key, 3600, $police); + $upManager = new UploadManager(); + list($ret, $error) = $upManager->putFile($token, $key, __file__, null, 'text/plain'); + $this->assertNull($error); + $this->assertNotNull($ret); + list($ret, $err) = $bucketManager->stat(self::$bucketName, $key); + $this->assertNull($err); + $this->assertEquals($testCase["fileType"], $ret["type"]); + } + } + + public function testResumeUploadWithParams() + { + $key = self::getObjectKey('resumePutFile4ML_'); + $upManager = new UploadManager(); + $policy = array('returnBody' => '{"hash":$(etag),"fname":$(fname),"var_1":$(x:var_1),"var_2":$(x:var_2)}'); + $token = self::$auth->uploadToken(self::$bucketName, $key, 3600, $policy); + $tempFile = qiniuTempFile(4 * 1024 * 1024 + 10); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + list($ret, $error) = $upManager->putFile( + $token, + $key, + $tempFile, + array("x:var_1" => "val_1", "x:var_2" => "val_2", "x-qn-meta-m1" => "val_1", "x-qn-meta-m2" => "val_2"), + 'application/octet-stream', + false, + $resumeFile + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + $this->assertEquals("val_1", $ret['var_1']); + $this->assertEquals("val_2", $ret['var_2']); + $this->assertEquals(basename($tempFile), $ret['fname']); + + $domain = getenv('QINIU_TEST_DOMAIN'); + $response = Client::get("http://$domain/$key"); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals(md5_file($tempFile, true), md5($response->body(), true)); + $headers = $response->headers(); + $this->assertEquals("val_1", $headers["X-Qn-Meta-M1"]); + $this->assertEquals("val_2", $headers["X-Qn-Meta-M2"]); + unlink($tempFile); + } + + public function testResumeUploadV2() + { + $cfg = new Config(); + $upManager = new UploadManager($cfg); + $testFileSize = array( + config::BLOCK_SIZE / 2, + config::BLOCK_SIZE, + config::BLOCK_SIZE + 10, + config::BLOCK_SIZE * 2, + config::BLOCK_SIZE * 2.5 + ); + $partSize = 5 * 1024 * 1024; + foreach ($testFileSize as $item) { + $key = self::getObjectKey('resumePutFile4ML_'); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $tempFile = qiniuTempFile($item); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + list($ret, $error) = $upManager->putFile( + $token, + $key, + $tempFile, + null, + 'application/octet-stream', + false, + $resumeFile, + 'v2', + $partSize + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + + $domain = getenv('QINIU_TEST_DOMAIN'); + $response = Client::get("http://$domain/$key"); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals(md5_file($tempFile, true), md5($response->body(), true)); + unlink($tempFile); + } + } + + public function testResumeUploadV2WithParams() + { + $key = self::getObjectKey('resumePutFile4ML_'); + $upManager = new UploadManager(); + $policy = array('returnBody' => '{"hash":$(etag),"fname":$(fname),"var_1":$(x:var_1),"var_2":$(x:var_2)}'); + $token = self::$auth->uploadToken(self::$bucketName, $key, 3600, $policy); + $tempFile = qiniuTempFile(4 * 1024 * 1024 + 10); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + list($ret, $error) = $upManager->putFile( + $token, + $key, + $tempFile, + array("x:var_1" => "val_1", "x:var_2" => "val_2", "x-qn-meta-m1" => "val_1", "x-qn-meta-m2" => "val_2"), + 'application/octet-stream', + false, + $resumeFile, + 'v2' + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + $this->assertEquals("val_1", $ret['var_1']); + $this->assertEquals("val_2", $ret['var_2']); + $this->assertEquals(basename($tempFile), $ret['fname']); + + $domain = getenv('QINIU_TEST_DOMAIN'); + $response = Client::get("http://$domain/$key"); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals(md5_file($tempFile, true), md5($response->body(), true)); + $headers = $response->headers(); + $this->assertEquals("val_1", $headers["X-Qn-Meta-M1"]); + $this->assertEquals("val_2", $headers["X-Qn-Meta-M2"]); + unlink($tempFile); + } + + // valid versions are tested above + // Use PHPUnit's Data Provider to test multiple Exception is better, + // but not match the test style of this project + public function testResumeUploadWithInvalidVersion() + { + $cfg = new Config(); + $upManager = new UploadManager($cfg); + $testFileSize = config::BLOCK_SIZE * 2; + $partSize = 5 * 1024 * 1024; + $testInvalidVersions = array( + // High probability invalid versions + 'v', + '1', + '2' + ); + + $expectExceptionCount = 0; + foreach ($testInvalidVersions as $invalidVersion) { + $key = self::getObjectKey('resumePutFile4ML_'); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $tempFile = qiniuTempFile($testFileSize); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + try { + $upManager->putFile( + $token, + $key, + $tempFile, + null, + 'application/octet-stream', + false, + $resumeFile, + $invalidVersion, + $partSize + ); + } catch (\Exception $e) { + $isRightException = false; + $expectExceptionCount++; + while ($e) { + $isRightException = $e instanceof \UnexpectedValueException; + if ($isRightException) { + break; + } + $e = $e->getPrevious(); + } + $this->assertTrue($isRightException); + } + + unlink($tempFile); + } + $this->assertEquals(count($testInvalidVersions), $expectExceptionCount); + } + + private function makeReqOpt() + { + $reqOpt = new RequestOptions(); + $reqOpt->proxy = 'socks5://127.0.0.1:8080'; + $reqOpt->proxy_user_password = 'user:pass'; + return $reqOpt; + } +} diff --git a/php-sdk/tests/Qiniu/Tests/ZoneTest.php b/php-sdk/tests/Qiniu/Tests/ZoneTest.php new file mode 100644 index 0000000..fbab528 --- /dev/null +++ b/php-sdk/tests/Qiniu/Tests/ZoneTest.php @@ -0,0 +1,136 @@ +bucketName = $bucketName; + + global $bucketNameBC; + $this->bucketNameBC = $bucketNameBC; + + global $bucketNameNA; + $this->bucketNameNA = $bucketNameNA; + + global $bucketNameFS; + $this->bucketNameFS = $bucketNameFS; + + global $bucketNameAS; + $this->bucketNameAS = $bucketNameAS; + + global $accessKey; + $this->ak = $accessKey; + + $this->zone = new Zone(); + $this->zoneHttps = new Zone('https'); + } + + public function testUpHosts() + { + list($ret, $err) = Zone::queryZone($this->ak, 'fakebucket'); + $this->assertNull($ret); + $this->assertNotNull($err); + + $zone = Zone::queryZone($this->ak, $this->bucketName); + $this->assertContains('upload.qiniup.com', $zone->cdnUpHosts); + + $zone = Zone::queryZone($this->ak, $this->bucketNameBC); + $this->assertContains('upload-z1.qiniup.com', $zone->cdnUpHosts); + + $zone = Zone::queryZone($this->ak, $this->bucketNameFS); + $this->assertContains('upload-z2.qiniup.com', $zone->cdnUpHosts); + + $zone = Zone::queryZone($this->ak, $this->bucketNameNA); + $this->assertContains('upload-na0.qiniup.com', $zone->cdnUpHosts); + + $zone = Zone::queryZone($this->ak, $this->bucketNameAS); + $this->assertContains('upload-as0.qiniup.com', $zone->cdnUpHosts); + } + + public function testIoHosts() + { + $zone = Zone::queryZone($this->ak, $this->bucketName); + $this->assertEquals($zone->iovipHost, 'iovip.qbox.me'); + + $zone = Zone::queryZone($this->ak, $this->bucketNameBC); + $this->assertEquals($zone->iovipHost, 'iovip-z1.qbox.me'); + + $zone = Zone::queryZone($this->ak, $this->bucketNameFS); + $this->assertEquals($zone->iovipHost, 'iovip-z2.qbox.me'); + + $zone = Zone::queryZone($this->ak, $this->bucketNameNA); + $this->assertEquals($zone->iovipHost, 'iovip-na0.qbox.me'); + + $zone = Zone::queryZone($this->ak, $this->bucketNameAS); + $this->assertEquals($zone->iovipHost, 'iovip-as0.qbox.me'); + } + + public function testZonez0() + { + $zone = Zone::zonez0(); + $this->assertContains('upload.qiniup.com', $zone->cdnUpHosts); + } + + public function testZonez1() + { + $zone = Zone::zonez1(); + $this->assertContains('upload-z1.qiniup.com', $zone->cdnUpHosts); + } + + public function testZonez2() + { + $zone = Zone::zonez2(); + $this->assertContains('upload-z2.qiniup.com', $zone->cdnUpHosts); + } + + public function testZoneCnEast2() + { + $zone = Zone::zoneCnEast2(); + $this->assertContains('upload-cn-east-2.qiniup.com', $zone->cdnUpHosts); + } + + public function testZoneNa0() + { + $zone = Zone::zoneNa0(); + $this->assertContains('upload-na0.qiniup.com', $zone->cdnUpHosts); + } + + public function testZoneAs0() + { + $zone = Zone::zoneAs0(); + $this->assertContains('upload-as0.qiniup.com', $zone->cdnUpHosts); + } + + public function testQvmZonez0() + { + $zone = Zone::qvmZonez0(); + $this->assertContains('free-qvm-z0-xs.qiniup.com', $zone->srcUpHosts); + } + + public function testQvmZonez1() + { + $zone = Zone::qvmZonez1(); + $this->assertContains('free-qvm-z1-zz.qiniup.com', $zone->srcUpHosts); + } +} diff --git a/php-sdk/tests/bootstrap.php b/php-sdk/tests/bootstrap.php new file mode 100644 index 0000000..9859a81 --- /dev/null +++ b/php-sdk/tests/bootstrap.php @@ -0,0 +1,61 @@ + 0) { + $length = min($rest_size, 4 * 1024); + if (fwrite($file, random_bytes($length)) == false) { + return false; + } + $rest_size -= $length; + } + } else if ($size > 0) { + fseek($file, $size - 1); + fwrite($file, ' '); + } + fclose($file); + return $fileName; +} diff --git a/php-sdk/tests/mock-server/ok.php b/php-sdk/tests/mock-server/ok.php new file mode 100644 index 0000000..5b0a65d --- /dev/null +++ b/php-sdk/tests/mock-server/ok.php @@ -0,0 +1,3 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + private $vendorDir; + + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + private static $registeredLoaders = array(); + + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000..2dcfa10 --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,317 @@ + + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + 'name' => '__root__', + ), + 'versions' => + array ( + '__root__' => + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + ), + 'myclabs/php-enum' => + array ( + 'pretty_version' => '1.8.5', + 'version' => '1.8.5.0', + 'aliases' => + array ( + ), + 'reference' => 'e7be26966b7398204a234f8673fdad5ac6277802', + ), + 'qiniu/php-sdk' => + array ( + 'pretty_version' => 'v7.14.0', + 'version' => '7.14.0.0', + 'aliases' => + array ( + ), + 'reference' => 'ee752ffa7263ce99fca0bd7340cf13c486a3516c', + ), + ), +); +private static $canGetVendors; +private static $installedByVendor = array(); + + + + + + + +public static function getInstalledPackages() +{ +$packages = array(); +foreach (self::getInstalled() as $installed) { +$packages[] = array_keys($installed['versions']); +} + +if (1 === \count($packages)) { +return $packages[0]; +} + +return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); +} + + + + + + + + + +public static function isInstalled($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (isset($installed['versions'][$packageName])) { +return true; +} +} + +return false; +} + + + + + + + + + + + + + + +public static function satisfies(VersionParser $parser, $packageName, $constraint) +{ +$constraint = $parser->parseConstraints($constraint); +$provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + +return $provided->matches($constraint); +} + + + + + + + + + + +public static function getVersionRanges($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +$ranges = array(); +if (isset($installed['versions'][$packageName]['pretty_version'])) { +$ranges[] = $installed['versions'][$packageName]['pretty_version']; +} +if (array_key_exists('aliases', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); +} +if (array_key_exists('replaced', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); +} +if (array_key_exists('provided', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); +} + +return implode(' || ', $ranges); +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getVersion($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +if (!isset($installed['versions'][$packageName]['version'])) { +return null; +} + +return $installed['versions'][$packageName]['version']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getPrettyVersion($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +if (!isset($installed['versions'][$packageName]['pretty_version'])) { +return null; +} + +return $installed['versions'][$packageName]['pretty_version']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getReference($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +if (!isset($installed['versions'][$packageName]['reference'])) { +return null; +} + +return $installed['versions'][$packageName]['reference']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getRootPackage() +{ +$installed = self::getInstalled(); + +return $installed[0]['root']; +} + + + + + + + + +public static function getRawData() +{ +@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + +return self::$installed; +} + + + + + + + +public static function getAllRawData() +{ +return self::getInstalled(); +} + + + + + + + + + + + + + + + + + + + +public static function reload($data) +{ +self::$installed = $data; +self::$installedByVendor = array(); +} + + + + + +private static function getInstalled() +{ +if (null === self::$canGetVendors) { +self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); +} + +$installed = array(); + +if (self::$canGetVendors) { +foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { +if (isset(self::$installedByVendor[$vendorDir])) { +$installed[] = self::$installedByVendor[$vendorDir]; +} elseif (is_file($vendorDir.'/composer/installed.php')) { +$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; +} +} +} + +$installed[] = self::$installed; + +return $installed; +} +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100644 index 0000000..f27399a --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..bb58823 --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,11 @@ + $vendorDir . '/composer/InstalledVersions.php', + 'Stringable' => $vendorDir . '/myclabs/php-enum/stubs/Stringable.php', +); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php new file mode 100644 index 0000000..8402a80 --- /dev/null +++ b/vendor/composer/autoload_files.php @@ -0,0 +1,11 @@ + $vendorDir . '/qiniu/php-sdk/src/Qiniu/functions.php', + '5dd19d8a547b7318af0c3a93c8bd6565' => $vendorDir . '/qiniu/php-sdk/src/Qiniu/Http/Middleware/Middleware.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..b7fc012 --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/qiniu/php-sdk/src/Qiniu'), + 'MyCLabs\\Enum\\' => array($vendorDir . '/myclabs/php-enum/src'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 0000000..70531e2 --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,75 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInit33806c1377e553ceececb4a264f74f6f::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + if ($useStaticLoader) { + $includeFiles = Composer\Autoload\ComposerStaticInit33806c1377e553ceececb4a264f74f6f::$files; + } else { + $includeFiles = require __DIR__ . '/autoload_files.php'; + } + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequire33806c1377e553ceececb4a264f74f6f($fileIdentifier, $file); + } + + return $loader; + } +} + +function composerRequire33806c1377e553ceececb4a264f74f6f($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + require $file; + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 0000000..75011ef --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,50 @@ + __DIR__ . '/..' . '/qiniu/php-sdk/src/Qiniu/functions.php', + '5dd19d8a547b7318af0c3a93c8bd6565' => __DIR__ . '/..' . '/qiniu/php-sdk/src/Qiniu/Http/Middleware/Middleware.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'Q' => + array ( + 'Qiniu\\' => 6, + ), + 'M' => + array ( + 'MyCLabs\\Enum\\' => 13, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Qiniu\\' => + array ( + 0 => __DIR__ . '/..' . '/qiniu/php-sdk/src/Qiniu', + ), + 'MyCLabs\\Enum\\' => + array ( + 0 => __DIR__ . '/..' . '/myclabs/php-enum/src', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'Stringable' => __DIR__ . '/..' . '/myclabs/php-enum/stubs/Stringable.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit33806c1377e553ceececb4a264f74f6f::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit33806c1377e553ceececb4a264f74f6f::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit33806c1377e553ceececb4a264f74f6f::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 0000000..0e6edfc --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,135 @@ +{ + "packages": [ + { + "name": "myclabs/php-enum", + "version": "1.8.5", + "version_normalized": "1.8.5.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/php-enum.git", + "reference": "e7be26966b7398204a234f8673fdad5ac6277802" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/e7be26966b7398204a234f8673fdad5ac6277802", + "reference": "e7be26966b7398204a234f8673fdad5ac6277802", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "1.*", + "vimeo/psalm": "^4.6.2 || ^5.2" + }, + "time": "2025-01-14T11:49:03+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "MyCLabs\\Enum\\": "src/" + }, + "classmap": [ + "stubs/Stringable.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP Enum contributors", + "homepage": "https://github.com/myclabs/php-enum/graphs/contributors" + } + ], + "description": "PHP Enum implementation", + "homepage": "https://github.com/myclabs/php-enum", + "keywords": [ + "enum" + ], + "support": { + "issues": "https://github.com/myclabs/php-enum/issues", + "source": "https://github.com/myclabs/php-enum/tree/1.8.5" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum", + "type": "tidelift" + } + ], + "install-path": "../myclabs/php-enum" + }, + { + "name": "qiniu/php-sdk", + "version": "v7.14.0", + "version_normalized": "7.14.0.0", + "source": { + "type": "git", + "url": "https://github.com/qiniu/php-sdk.git", + "reference": "ee752ffa7263ce99fca0bd7340cf13c486a3516c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/qiniu/php-sdk/zipball/ee752ffa7263ce99fca0bd7340cf13c486a3516c", + "reference": "ee752ffa7263ce99fca0bd7340cf13c486a3516c", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-xml": "*", + "myclabs/php-enum": "~1.5.2 || ~1.6.6 || ~1.7.7 || ~1.8.4", + "php": ">=5.3.3" + }, + "require-dev": { + "paragonie/random_compat": ">=2", + "phpunit/phpunit": "^4.8 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4", + "squizlabs/php_codesniffer": "^2.3 || ~3.6" + }, + "time": "2024-10-25T08:39:01+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/Qiniu/functions.php", + "src/Qiniu/Http/Middleware/Middleware.php" + ], + "psr-4": { + "Qiniu\\": "src/Qiniu" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Qiniu", + "email": "sdk@qiniu.com", + "homepage": "http://www.qiniu.com" + } + ], + "description": "Qiniu Resource (Cloud) Storage SDK for PHP", + "homepage": "http://developer.qiniu.com/", + "keywords": [ + "cloud", + "qiniu", + "sdk", + "storage" + ], + "support": { + "issues": "https://github.com/qiniu/php-sdk/issues", + "source": "https://github.com/qiniu/php-sdk/tree/v7.14.0" + }, + "install-path": "../qiniu/php-sdk" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 0000000..fed962a --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,42 @@ + + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + 'name' => '__root__', + ), + 'versions' => + array ( + '__root__' => + array ( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'aliases' => + array ( + ), + 'reference' => NULL, + ), + 'myclabs/php-enum' => + array ( + 'pretty_version' => '1.8.5', + 'version' => '1.8.5.0', + 'aliases' => + array ( + ), + 'reference' => 'e7be26966b7398204a234f8673fdad5ac6277802', + ), + 'qiniu/php-sdk' => + array ( + 'pretty_version' => 'v7.14.0', + 'version' => '7.14.0.0', + 'aliases' => + array ( + ), + 'reference' => 'ee752ffa7263ce99fca0bd7340cf13c486a3516c', + ), + ), +); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100644 index 0000000..92370c5 --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 70300)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.3.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/vendor/myclabs/php-enum/LICENSE b/vendor/myclabs/php-enum/LICENSE new file mode 100644 index 0000000..2a8cf22 --- /dev/null +++ b/vendor/myclabs/php-enum/LICENSE @@ -0,0 +1,18 @@ +The MIT License (MIT) + +Copyright (c) 2015 My C-Labs + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/myclabs/php-enum/README.md b/vendor/myclabs/php-enum/README.md new file mode 100644 index 0000000..948f374 --- /dev/null +++ b/vendor/myclabs/php-enum/README.md @@ -0,0 +1,196 @@ +# PHP Enum implementation inspired from SplEnum + +[![GitHub Actions][GA Image]][GA Link] +[![Latest Stable Version](https://poser.pugx.org/myclabs/php-enum/version.png)](https://packagist.org/packages/myclabs/php-enum) +[![Total Downloads](https://poser.pugx.org/myclabs/php-enum/downloads.png)](https://packagist.org/packages/myclabs/php-enum) +[![Psalm Shepherd][Shepherd Image]][Shepherd Link] + +Maintenance for this project is [supported via Tidelift](https://tidelift.com/subscription/pkg/packagist-myclabs-php-enum?utm_source=packagist-myclabs-php-enum&utm_medium=referral&utm_campaign=readme). + +## Why? + +First, and mainly, `SplEnum` is not integrated to PHP, you have to install the extension separately. + +Using an enum instead of class constants provides the following advantages: + +- You can use an enum as a parameter type: `function setAction(Action $action) {` +- You can use an enum as a return type: `function getAction() : Action {` +- You can enrich the enum with methods (e.g. `format`, `parse`, …) +- You can extend the enum to add new values (make your enum `final` to prevent it) +- You can get a list of all the possible values (see below) + +This Enum class is not intended to replace class constants, but only to be used when it makes sense. + +## Installation + +``` +composer require myclabs/php-enum +``` + +## Declaration + +```php +use MyCLabs\Enum\Enum; + +/** + * Action enum + * + * @extends Enum + */ +final class Action extends Enum +{ + private const VIEW = 'view'; + private const EDIT = 'edit'; +} +``` + +## Usage + +```php +$action = Action::VIEW(); + +// or with a dynamic key: +$action = Action::$key(); +// or with a dynamic value: +$action = Action::from($value); +// or +$action = new Action($value); +``` + +As you can see, static methods are automatically implemented to provide quick access to an enum value. + +One advantage over using class constants is to be able to use an enum as a parameter type: + +```php +function setAction(Action $action) { + // ... +} +``` + +## Documentation + +- `__construct()` The constructor checks that the value exist in the enum +- `__toString()` You can `echo $myValue`, it will display the enum value (value of the constant) +- `getValue()` Returns the current value of the enum +- `getKey()` Returns the key of the current value on Enum +- `equals()` Tests whether enum instances are equal (returns `true` if enum values are equal, `false` otherwise) + +Static methods: + +- `from()` Creates an Enum instance, checking that the value exist in the enum +- `toArray()` method Returns all possible values as an array (constant name in key, constant value in value) +- `keys()` Returns the names (keys) of all constants in the Enum class +- `values()` Returns instances of the Enum class of all Enum constants (constant name in key, Enum instance in value) +- `isValid()` Check if tested value is valid on enum set +- `isValidKey()` Check if tested key is valid on enum set +- `assertValidValue()` Assert the value is valid on enum set, throwing exception otherwise +- `search()` Return key for searched value + +### Static methods + +```php +final class Action extends Enum +{ + private const VIEW = 'view'; + private const EDIT = 'edit'; +} + +// Static method: +$action = Action::VIEW(); +$action = Action::EDIT(); +``` + +Static method helpers are implemented using [`__callStatic()`](http://www.php.net/manual/en/language.oop5.overloading.php#object.callstatic). + +If you care about IDE autocompletion, you can either implement the static methods yourself: + +```php +final class Action extends Enum +{ + private const VIEW = 'view'; + + /** + * @return Action + */ + public static function VIEW() { + return new Action(self::VIEW); + } +} +``` + +or you can use phpdoc (this is supported in PhpStorm for example): + +```php +/** + * @method static Action VIEW() + * @method static Action EDIT() + */ +final class Action extends Enum +{ + private const VIEW = 'view'; + private const EDIT = 'edit'; +} +``` + +## Native enums and migration +Native enum arrived to PHP in version 8.1: https://www.php.net/enumerations +If your project is running PHP 8.1+ or your library has it as a minimum requirement you should use it instead of this library. + +When migrating from `myclabs/php-enum`, the effort should be small if the usage was in the recommended way: +- private constants +- final classes +- no method overridden + +Changes for migration: +- Class definition should be changed from +```php +/** + * @method static Action VIEW() + * @method static Action EDIT() + */ +final class Action extends Enum +{ + private const VIEW = 'view'; + private const EDIT = 'edit'; +} +``` + to +```php +enum Action: string +{ + case VIEW = 'view'; + case EDIT = 'edit'; +} +``` +All places where the class was used as a type will continue to work. + +Usages and the change needed: + +| Operation | myclabs/php-enum | native enum | +|----------------------------------------------------------------|----------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Obtain an instance will change from | `$enumCase = Action::VIEW()` | `$enumCase = Action::VIEW` | +| Create an enum from a backed value | `$enumCase = new Action('view')` | `$enumCase = Action::from('view')` | +| Get the backed value of the enum instance | `$enumCase->getValue()` | `$enumCase->value` | +| Compare two enum instances | `$enumCase1 == $enumCase2`
or
`$enumCase1->equals($enumCase2)` | `$enumCase1 === $enumCase2` | +| Get the key/name of the enum instance | `$enumCase->getKey()` | `$enumCase->name` | +| Get a list of all the possible instances of the enum | `Action::values()` | `Action::cases()` | +| Get a map of possible instances of the enum mapped by name | `Action::values()` | `array_combine(array_map(fn($case) => $case->name, Action::cases()), Action::cases())`
or
`(new ReflectionEnum(Action::class))->getConstants()` | +| Get a list of all possible names of the enum | `Action::keys()` | `array_map(fn($case) => $case->name, Action::cases())` | +| Get a list of all possible backed values of the enum | `Action::toArray()` | `array_map(fn($case) => $case->value, Action::cases())` | +| Get a map of possible backed values of the enum mapped by name | `Action::toArray()` | `array_combine(array_map(fn($case) => $case->name, Action::cases()), array_map(fn($case) => $case->value, Action::cases()))`
or
`array_map(fn($case) => $case->value, (new ReflectionEnum(Action::class))->getConstants()))` | + +## Related projects + +- [PHP 8.1+ native enum](https://www.php.net/enumerations) +- [Doctrine enum mapping](https://github.com/acelaya/doctrine-enum-type) +- [Symfony ParamConverter integration](https://github.com/Ex3v/MyCLabsEnumParamConverter) +- [PHPStan integration](https://github.com/timeweb/phpstan-enum) + + +[GA Image]: https://github.com/myclabs/php-enum/workflows/CI/badge.svg + +[GA Link]: https://github.com/myclabs/php-enum/actions?query=workflow%3A%22CI%22+branch%3Amaster + +[Shepherd Image]: https://shepherd.dev/github/myclabs/php-enum/coverage.svg + +[Shepherd Link]: https://shepherd.dev/github/myclabs/php-enum diff --git a/vendor/myclabs/php-enum/SECURITY.md b/vendor/myclabs/php-enum/SECURITY.md new file mode 100644 index 0000000..84fd4e3 --- /dev/null +++ b/vendor/myclabs/php-enum/SECURITY.md @@ -0,0 +1,11 @@ +# Security Policy + +## Supported Versions + +Only the latest stable release is supported. + +## Reporting a Vulnerability + +To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). + +Tidelift will coordinate the fix and disclosure. diff --git a/vendor/myclabs/php-enum/composer.json b/vendor/myclabs/php-enum/composer.json new file mode 100644 index 0000000..eab6263 --- /dev/null +++ b/vendor/myclabs/php-enum/composer.json @@ -0,0 +1,36 @@ +{ + "name": "myclabs/php-enum", + "type": "library", + "description": "PHP Enum implementation", + "keywords": ["enum"], + "homepage": "https://github.com/myclabs/php-enum", + "license": "MIT", + "authors": [ + { + "name": "PHP Enum contributors", + "homepage": "https://github.com/myclabs/php-enum/graphs/contributors" + } + ], + "autoload": { + "psr-4": { + "MyCLabs\\Enum\\": "src/" + }, + "classmap": [ + "stubs/Stringable.php" + ] + }, + "autoload-dev": { + "psr-4": { + "MyCLabs\\Tests\\Enum\\": "tests/" + } + }, + "require": { + "php": "^7.3 || ^8.0", + "ext-json": "*" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "1.*", + "vimeo/psalm": "^4.6.2 || ^5.2" + } +} diff --git a/vendor/myclabs/php-enum/src/Enum.php b/vendor/myclabs/php-enum/src/Enum.php new file mode 100644 index 0000000..1bd5592 --- /dev/null +++ b/vendor/myclabs/php-enum/src/Enum.php @@ -0,0 +1,319 @@ + + * @author Daniel Costa + * @author Mirosław Filip + * + * @psalm-template T + * @psalm-immutable + * @psalm-consistent-constructor + */ +abstract class Enum implements \JsonSerializable, \Stringable +{ + /** + * Enum value + * + * @var mixed + * @psalm-var T + */ + protected $value; + + /** + * Enum key, the constant name + * + * @var string + */ + private $key; + + /** + * Store existing constants in a static cache per object. + * + * + * @var array + * @psalm-var array> + */ + protected static $cache = []; + + /** + * Cache of instances of the Enum class + * + * @var array + * @psalm-var array> + */ + protected static $instances = []; + + /** + * Creates a new value of some type + * + * @psalm-pure + * @param mixed $value + * + * @psalm-param T $value + * @throws \UnexpectedValueException if incompatible type is given. + */ + public function __construct($value) + { + if ($value instanceof static) { + /** @psalm-var T */ + $value = $value->getValue(); + } + + /** @psalm-suppress ImplicitToStringCast assertValidValueReturningKey returns always a string but psalm has currently an issue here */ + $this->key = static::assertValidValueReturningKey($value); + + /** @psalm-var T */ + $this->value = $value; + } + + /** + * This method exists only for the compatibility reason when deserializing a previously serialized version + * that didn't had the key property + */ + public function __wakeup() + { + /** @psalm-suppress DocblockTypeContradiction key can be null when deserializing an enum without the key */ + if ($this->key === null) { + /** + * @psalm-suppress InaccessibleProperty key is not readonly as marked by psalm + * @psalm-suppress PossiblyFalsePropertyAssignmentValue deserializing a case that was removed + */ + $this->key = static::search($this->value); + } + } + + /** + * @param mixed $value + * @return static + */ + public static function from($value): self + { + $key = static::assertValidValueReturningKey($value); + + return self::__callStatic($key, []); + } + + /** + * @psalm-pure + * @return mixed + * @psalm-return T + */ + public function getValue() + { + return $this->value; + } + + /** + * Returns the enum key (i.e. the constant name). + * + * @psalm-pure + * @return string + */ + public function getKey() + { + return $this->key; + } + + /** + * @psalm-pure + * @psalm-suppress InvalidCast + * @return string + */ + public function __toString() + { + return (string)$this->value; + } + + /** + * Determines if Enum should be considered equal with the variable passed as a parameter. + * Returns false if an argument is an object of different class or not an object. + * + * This method is final, for more information read https://github.com/myclabs/php-enum/issues/4 + * + * @psalm-pure + * @psalm-param mixed $variable + * @return bool + */ + final public function equals($variable = null): bool + { + return $variable instanceof self + && $this->getValue() === $variable->getValue() + && static::class === \get_class($variable); + } + + /** + * Returns the names (keys) of all constants in the Enum class + * + * @psalm-pure + * @psalm-return list + * @return array + */ + public static function keys() + { + return \array_keys(static::toArray()); + } + + /** + * Returns instances of the Enum class of all Enum constants + * + * @psalm-pure + * @psalm-return array + * @return static[] Constant name in key, Enum instance in value + */ + public static function values() + { + $values = array(); + + /** @psalm-var T $value */ + foreach (static::toArray() as $key => $value) { + /** @psalm-suppress UnsafeGenericInstantiation */ + $values[$key] = new static($value); + } + + return $values; + } + + /** + * Returns all possible values as an array + * + * @psalm-pure + * @psalm-suppress ImpureStaticProperty + * + * @psalm-return array + * @return array Constant name in key, constant value in value + */ + public static function toArray() + { + $class = static::class; + + if (!isset(static::$cache[$class])) { + /** @psalm-suppress ImpureMethodCall this reflection API usage has no side-effects here */ + $reflection = new \ReflectionClass($class); + /** @psalm-suppress ImpureMethodCall this reflection API usage has no side-effects here */ + static::$cache[$class] = $reflection->getConstants(); + } + + return static::$cache[$class]; + } + + /** + * Check if is valid enum value + * + * @param $value + * @psalm-param mixed $value + * @psalm-pure + * @psalm-assert-if-true T $value + * @return bool + */ + public static function isValid($value) + { + return \in_array($value, static::toArray(), true); + } + + /** + * Asserts valid enum value + * + * @psalm-pure + * @psalm-assert T $value + * @param mixed $value + */ + public static function assertValidValue($value): void + { + self::assertValidValueReturningKey($value); + } + + /** + * Asserts valid enum value + * + * @psalm-pure + * @psalm-assert T $value + * @param mixed $value + * @return string + */ + private static function assertValidValueReturningKey($value): string + { + if (false === ($key = static::search($value))) { + throw new \UnexpectedValueException("Value '$value' is not part of the enum " . static::class); + } + + return $key; + } + + /** + * Check if is valid enum key + * + * @param $key + * @psalm-param string $key + * @psalm-pure + * @return bool + */ + public static function isValidKey($key) + { + $array = static::toArray(); + + return isset($array[$key]) || \array_key_exists($key, $array); + } + + /** + * Return key for value + * + * @param mixed $value + * + * @psalm-param mixed $value + * @psalm-pure + * @return string|false + */ + public static function search($value) + { + return \array_search($value, static::toArray(), true); + } + + /** + * Returns a value when called statically like so: MyEnum::SOME_VALUE() given SOME_VALUE is a class constant + * + * @param string $name + * @param array $arguments + * + * @return static + * @throws \BadMethodCallException + * + * @psalm-pure + */ + public static function __callStatic($name, $arguments) + { + $class = static::class; + if (!isset(self::$instances[$class][$name])) { + $array = static::toArray(); + if (!isset($array[$name]) && !\array_key_exists($name, $array)) { + $message = "No static method or enum constant '$name' in class " . static::class; + throw new \BadMethodCallException($message); + } + /** @psalm-suppress UnsafeGenericInstantiation */ + return self::$instances[$class][$name] = new static($array[$name]); + } + return clone self::$instances[$class][$name]; + } + + /** + * Specify data which should be serialized to JSON. This method returns data that can be serialized by json_encode() + * natively. + * + * @return mixed + * @link http://php.net/manual/en/jsonserializable.jsonserialize.php + */ + #[\ReturnTypeWillChange] + public function jsonSerialize() + { + return $this->getValue(); + } +} diff --git a/vendor/myclabs/php-enum/src/PHPUnit/Comparator.php b/vendor/myclabs/php-enum/src/PHPUnit/Comparator.php new file mode 100644 index 0000000..7c65e4e --- /dev/null +++ b/vendor/myclabs/php-enum/src/PHPUnit/Comparator.php @@ -0,0 +1,54 @@ +register(new \MyCLabs\Enum\PHPUnit\Comparator()); + */ +final class Comparator extends \SebastianBergmann\Comparator\Comparator +{ + public function accepts($expected, $actual) + { + return $expected instanceof Enum && ( + $actual instanceof Enum || $actual === null + ); + } + + /** + * @param Enum $expected + * @param Enum|null $actual + * + * @return void + */ + public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false) + { + if ($expected->equals($actual)) { + return; + } + + throw new ComparisonFailure( + $expected, + $actual, + $this->formatEnum($expected), + $this->formatEnum($actual), + false, + 'Failed asserting that two Enums are equal.' + ); + } + + private function formatEnum(?Enum $enum = null) + { + if ($enum === null) { + return "null"; + } + + return get_class($enum)."::{$enum->getKey()}()"; + } +} diff --git a/vendor/myclabs/php-enum/stubs/Stringable.php b/vendor/myclabs/php-enum/stubs/Stringable.php new file mode 100644 index 0000000..4811af7 --- /dev/null +++ b/vendor/myclabs/php-enum/stubs/Stringable.php @@ -0,0 +1,11 @@ + phpd.log 2>&1 & + echo $! > mock-server.pid + + cd tests/socks5-server/ + nohup go run main.go > ../../socks5.log 2>&1 & + echo $! > ../../socks-server.pid + + - name: Setup php + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + + - name: Install dependencies + run: | + composer self-update + composer install --no-interaction --prefer-source --dev + + - name: Run cases + run: | + ./vendor/bin/phpcs --standard=PSR2 src + ./vendor/bin/phpcs --standard=PSR2 examples + ./vendor/bin/phpcs --standard=PSR2 tests + ./vendor/bin/phpunit --coverage-clover=coverage.xml + cat mock-server.pid | xargs kill + cat socks-server.pid | xargs kill + + env: + QINIU_ACCESS_KEY: ${{ secrets.QINIU_ACCESS_KEY }} + QINIU_SECRET_KEY: ${{ secrets.QINIU_SECRET_KEY }} + QINIU_TEST_BUCKET: ${{ secrets.QINIU_TEST_BUCKET }} + QINIU_TEST_DOMAIN: ${{ secrets.QINIU_TEST_DOMAIN }} + + - name: Print mock server log + if: ${{ failure() }} + run: | + cat phpd.log + + - name: Print socks5 server log + if: ${{ failure() }} + run: | + cat socks5.log + + - name: After_success + run: bash <(curl -s https://codecov.io/bash) diff --git a/vendor/qiniu/php-sdk/.github/workflows/version-check.yml b/vendor/qiniu/php-sdk/.github/workflows/version-check.yml new file mode 100644 index 0000000..983a98f --- /dev/null +++ b/vendor/qiniu/php-sdk/.github/workflows/version-check.yml @@ -0,0 +1,19 @@ +name: PHP SDK Version Check +on: + push: + tags: + - "v[0-9]+.[0-9]+.[0-9]+" +jobs: + linux: + name: Version Check + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Set env + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV + - name: Check + run: | + set -e + grep -qF "## ${RELEASE_VERSION}" CHANGELOG.md + grep -qF "const SDK_VER = '${RELEASE_VERSION}';" src/Qiniu/Config.php diff --git a/vendor/qiniu/php-sdk/.gitignore b/vendor/qiniu/php-sdk/.gitignore new file mode 100644 index 0000000..4c842c8 --- /dev/null +++ b/vendor/qiniu/php-sdk/.gitignore @@ -0,0 +1,12 @@ +*.phar +*.zip +build/artifacts +phpunit.xml +phpunit.functional.xml +.DS_Store +.swp +.build +composer.lock +vendor +src/package.xml +.idea/ diff --git a/vendor/qiniu/php-sdk/.scrutinizer.yml b/vendor/qiniu/php-sdk/.scrutinizer.yml new file mode 100644 index 0000000..6a2d0d8 --- /dev/null +++ b/vendor/qiniu/php-sdk/.scrutinizer.yml @@ -0,0 +1,42 @@ +filter: + excluded_paths: [tests/*] +checks: + php: + code_rating: true + remove_extra_empty_lines: true + remove_php_closing_tag: true + remove_trailing_whitespace: true + fix_use_statements: + remove_unused: true + preserve_multiple: false + preserve_blanklines: true + order_alphabetically: true + fix_php_opening_tag: true + fix_linefeed: true + fix_line_ending: true + fix_identation_4spaces: true + fix_doc_comments: true +tools: + external_code_coverage: + timeout: 1200 + runs: 3 + php_analyzer: true + php_code_coverage: false + php_code_sniffer: + config: + standard: PSR2 + filter: + paths: ['src'] + php_loc: + enabled: true + excluded_dirs: [vendor, tests] + php_cpd: + enabled: true + excluded_dirs: [vendor, tests] +build: + nodes: + analysis: + tests: + override: + - php-scrutinizer-run + diff --git a/vendor/qiniu/php-sdk/CHANGELOG.md b/vendor/qiniu/php-sdk/CHANGELOG.md new file mode 100644 index 0000000..6f8da5d --- /dev/null +++ b/vendor/qiniu/php-sdk/CHANGELOG.md @@ -0,0 +1,196 @@ +# Changelog + +## 7.14.0 (2024-10-16) +* 对象存储,持久化处理支持工作流模版 + +## 7.13.0 (2024-09-05) +* 对象存储,验证回调方法新增支持 Qiniu 签名 +* 对象存储,调整查询空间区域域名顺序与默认空间管理域名 +* 支持闲时任务配置 + +## 7.12.1 (2024-02-21) +* 对象存储,添加上传策略部分字段 + +## 7.12.0 (2023-12-11) +* 对象存储,支持归档直读存储 +* 对象存储,批量操作支持自动查询 rs 服务域名 + +## 7.11.0 (2023-09-05) +* 支持代理 + +## 7.10.1 (2023-08-04) +* 修复部分 API 调用中间件合并失败(#417) + +## 7.10.0 (2023-06-20) +* 对象存储,新增请求中间件逻辑,方便拓展请求逻辑 +* 对象存储,新增备用 UC 域名用于查询区域域名 +* 对象存储,修复分片上传初始化失败无法快速失败 +* 对象存储,移除首尔区域 + +## 7.9.0 (2023-03-31) +* 对象存储,修复无法对 key 为空字符串的对象进行操作 +* 修复 301 重定向无法正确获取 header 信息 +* 对象存储,新增查询区域域名过期时间 +* 对象存储,更新获取区域域名的接口 +* 对象存储,更新查询 bucket 域名为 uc 服务 +* 对象存储,新增 uc 服务可配置 + +## 7.8.0 (2022-10-25) +* 移除不推荐域名,并增加区域亚太-首尔和华东-浙江2 +* 对象存储,修复断点上传的文件内容不正确 +* 对象存储,优化分片上传 ctx 超时检测 + +## 7.7.0 (2022-09-02) +* 对象存储,新增支持设置文件级别生命周期 setObjectLifecycle API +* 对象存储,内置增加七牛新建存储区域域名信息 +* 修复当前已知问题 + +## 7.6.0 (2022-06-08) +* 对象存储,管理类 API 发送请求时增加 [X-Qiniu-Date](https://developer.qiniu.com/kodo/3924/common-request-headers) (生成请求的时间) header + + +## 7.5.0 (2022-04-18) +* 对象存储,新增支持 [深度归档存储类型](https://developer.qiniu.com/kodo/3956/kodo-category#deep_archive) + +## 7.4.3 (2022-04-01) +* 优化签名算法逻辑 + +## 7.4.2(2022-03-01) +* 修复已知关于请求 Header 处理不当问题,比如没有处理为大小写不敏感等问题 + +## 7.4.1(2021-09-24) +* 修复了 分片上传 v2 已知问题,明确给出了参数不合理情况下对应的错误提示信息 + +## 7.4.0 (2021-07-19) +* 【对象存储】支持 [分片上传 v2](https://developer.qiniu.com/kodo/7458/multipartupload) 和 断点续传,使用方式见 [开发者文档](https://developer.qiniu.com/kodo/1241/php#resume-upload-file) + +## 7.3.0 (2020-09-24) +### 新增 +* 【对象存储】增加异步抓取方法与demo +* 【融合cdn】增加查询CDN刷新记录、查询CDN预取记录方法与demo +* 【云短信】增加查询短信发送记录的方法 +* 【实时音视频】增加rtc停止房间的合流转推方法 +* 【内容审核】增加图片审核、视频审核方法与demo + +### 修复 +* 【对象存储】修复签算 token 时上传策略中的 forceSaveKey 字段不生效的问题 +* 【对象存储】修复更新空间事件通知规则方法 + +### 优化 +* 【对象存储】创建空间迁移到mkbucketv3 api +* 优化对 http2 返回头的判断 +* 优化 demo 中的文档注释说明 +* docs 目录下的 rtc demo 移动至 examples/rtc 目录下 +* docs 目录下的 sms demo 移动至 examples/sms 目录下 + +## 7.2.10 (2019-10-28) +* 去除云短信类类型指定 +* 修改不传文件名时存在表单上传错误的情况 + +## 7.2.9 (2019-07-09) +* 添加空间管理、云短信接口 +* 去除无效参数 + +## 7.2.7 (2018-11-06) +* 添加 QVM 内网上传到 KODO 的 zone 设置 + +## 7.2.6 (2018-05-18) +* 修复rs,rsf在不同机房默认的https域名 + +## 7.2.5 (2018-05-10) +* 修复表单上传中多余的参数checkCrc导致的fname错位问题 + +## 7.2.4 (2018-05-09) +### 增加 +* 连麦功能 + +## 7.2.3 (2018-01-20) +### 增加 +* 新加坡机房 +### 修正 +* 获取域名的入口域名 +* http回复头部兼容大小写 + +## 7.2.2 (2017-11-06) +### 增加 +* Qiniu算法的鉴权方法 + +## 7.1.4 (2017-06-21) +### 增加 +* cdn 文件/目录 刷新 +* cdn 获取 流量/带宽 +* cdn 获取域名的访问日志列表 +* cdn 对资源链接进行时间戳防盗链签名 + +## 7.1.3 (2016-11-18) +### 增加 +* move, copy操作增加force参数 + +## 7.1.2 (2016-11-12) +### 修正 +* 明确抛出获取各区域域名失败时的报错 + +## 7.1.1 (2016-11-02) +### 修正 +* 多区域配置文件存储目录从home修改到tmp目录 + + +## 7.1.0 (2016-10-22) +### 增加 +* 多存储区域的支持 + +## 7.0.8 (2016-07-19) +### 增加 +* demo +* https url 支持 +* deleteAfterDays 策略 +* 添加图片处理链接统一拼接方法 by @SherlockRen + +## 7.0.7 (2016-01-12) +### 修正 +* PersistentFop参数pipeline和notify_url失效 +* resume 模式 close file inputstream + +## 7.0.6 (2015-12-05) +### 修正 +* php7.0 Json 对空字符串解析单元测试报错 +* 开启安全模式或者设置可操作目录树时,设置CURLOPT_FOLLOWLOCATION报错, by @twocabbages +* fetch 支持不指定key, by @sinkcup + +## 7.0.5 (2015-10-29) +### 增加 +* 增加上传策略最小文件大小限制 fsizeMin +* 增加常见examples + +## 7.0.4 (2015-07-23) +### 修正 +* 一些地方的严格比较检查 +* resumeupload 备用地址失效 + +## 7.0.3 (2015-07-10) +### 修改 +* 多zone 支持 + +## 7.0.2 (2015-04-18) +### 修改 +* fetch 接口返回内容调整 +* pfop 接口调整 + +###修正 +* exception 类调用 + +## 7.0.1 (2015-03-27) +### 增加 +* 增加代码注释 + +## 7.0.0 (2015-02-03) + +### 增加 +* 简化上传接口 +* 自动选择断点续上传还是直传 +* 重构代码,接口和内部结构更清晰 +* 改变mime +* 代码覆盖度报告 +* policy改为array, 便于灵活增加,并加入过期字段检查 +* 文件列表支持目录形式 +* 利用元编程方式支持 fop 和 pfop diff --git a/vendor/qiniu/php-sdk/CONTRIBUTING.md b/vendor/qiniu/php-sdk/CONTRIBUTING.md new file mode 100644 index 0000000..0466bf9 --- /dev/null +++ b/vendor/qiniu/php-sdk/CONTRIBUTING.md @@ -0,0 +1,30 @@ +# 贡献代码指南 + +我们非常欢迎大家来贡献代码,我们会向贡献者致以最诚挚的敬意。 + +一般可以通过在Github上提交[Pull Request](https://github.com/qiniu/php-sdk)来贡献代码。 + +## Pull Request要求 + +- **[PSR-2 编码风格标准](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** 。要通过项目中的code sniffer检查。 + +- **代码格式** 提交前 请按 ./vendor/bin/phpcbf --standard=PSR2 进行格式化。 + +- **必须添加测试!** - 如果没有测试(单元测试、集成测试都可以),那么提交的补丁是不会通过的。 + +- **记得更新文档** - 保证`README.md`以及其他相关文档及时更新,和代码的变更保持一致性。 + +- **考虑我们的发布周期** - 我们的版本号会服从[SemVer v2.0.0](http://semver.org/),我们绝对不会随意变更对外的API。 + +- **创建feature分支** - 最好不要从你的master分支提交 pull request。 + +- **一个feature提交一个pull请求** - 如果你的代码变更了多个操作,那就提交多个pull请求吧。 + +- **清晰的commit历史** - 保证你的pull请求的每次commit操作都是有意义的。如果你开发中需要执行多次的即时commit操作,那么请把它们放到一起再提交pull请求。 + +## 运行测试 + +``` bash +./vendor/bin/phpunit tests/Qiniu/Tests/ + +``` diff --git a/vendor/qiniu/php-sdk/LICENSE b/vendor/qiniu/php-sdk/LICENSE new file mode 100644 index 0000000..ba646be --- /dev/null +++ b/vendor/qiniu/php-sdk/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 Qiniu, Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/qiniu/php-sdk/README.md b/vendor/qiniu/php-sdk/README.md new file mode 100644 index 0000000..784d735 --- /dev/null +++ b/vendor/qiniu/php-sdk/README.md @@ -0,0 +1,76 @@ +# Qiniu Cloud SDK for PHP +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE) +[![Build Status](https://travis-ci.org/qiniu/php-sdk.svg)](https://travis-ci.org/qiniu/php-sdk) +[![GitHub release](https://img.shields.io/github/v/tag/qiniu/php-sdk.svg?label=release)](https://github.com/qiniu/php-sdk/releases) +[![Latest Stable Version](https://img.shields.io/packagist/v/qiniu/php-sdk.svg)](https://packagist.org/packages/qiniu/php-sdk) +[![Total Downloads](https://img.shields.io/packagist/dt/qiniu/php-sdk.svg)](https://packagist.org/packages/qiniu/php-sdk) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/qiniu/php-sdk/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/qiniu/php-sdk/?branch=master) +[![Coverage Status](https://codecov.io/gh/qiniu/php-sdk/branch/master/graph/badge.svg)](https://codecov.io/gh/qiniu/php-sdk) +[![Join Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/qiniu/php-sdk?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![@qiniu on weibo](http://img.shields.io/badge/weibo-%40qiniutek-blue.svg)](http://weibo.com/qiniutek) + + +## 安装 + +推荐使用 `composer` 进行安装。可以使用 composer.json 声明依赖,或者运行下面的命令。SDK 包已经放到这里 [`qiniu/php-sdk`][install-packagist] 。 + +```bash +$ composer require qiniu/php-sdk +``` + +## 运行环境 + +| Qiniu SDK版本 | PHP 版本 | +|:--------------------:|:-----------------------------------------------:| +| 7.x | cURL extension, 5.3 - 5.6, 7.0 - 7.4, 8.0-8.1 | +| 6.x | cURL extension, 5.2 - 5.6 | + +## 使用方法 + +### 上传 +```php +use Qiniu\Storage\UploadManager; +use Qiniu\Auth; +... + $uploadMgr = new UploadManager(); + $auth = new Auth($accessKey, $secretKey); + $token = $auth->uploadToken($bucket); + list($ret, $error) = $uploadMgr->putFile($token, 'key', 'filePath'); +... +``` + +## 测试 + +``` bash +$ ./vendor/bin/phpunit tests/Qiniu/Tests/ +``` + +## 常见问题 + +- `$error` 保留了请求响应的信息,失败情况下 `ret` 为 `none`, 将 `$error` 可以打印出来,提交给我们。 +- API 的使用 demo 可以参考 [examples](https://github.com/qiniu/php-sdk/tree/master/examples)。 + +## 代码贡献 + +详情参考[代码提交指南](https://github.com/qiniu/php-sdk/blob/master/CONTRIBUTING.md)。 + +## 贡献记录 + +- [所有贡献者](https://github.com/qiniu/php-sdk/contributors) + +## 联系我们 + +- 如果需要帮助,请提交工单(在portal右侧点击咨询和建议提交工单,或者直接向 support@qiniu.com 发送邮件) +- 如果有什么问题,可以到问答社区提问,[问答社区](https://qiniu.segmentfault.com/) +- 更详细的文档,见[官方文档站](https://developer.qiniu.com/) +- 如果发现了 bug, 欢迎提交 [issue](https://github.com/qiniu/php-sdk/issues) +- 如果有功能需求,欢迎提交 [issue](https://github.com/qiniu/php-sdk/issues) +- 如果要提交代码,欢迎提交 pull request +- 欢迎关注我们的[微信](https://www.qiniu.com/#weixin) [微博](https://weibo.com/qiniutek),及时获取动态信息。 + +## 代码许可 + +The MIT License (MIT).详情见 [License文件](https://github.com/qiniu/php-sdk/blob/master/LICENSE). + +[packagist]: http://packagist.org +[install-packagist]: https://packagist.org/packages/qiniu/php-sdk diff --git a/vendor/qiniu/php-sdk/autoload.php b/vendor/qiniu/php-sdk/autoload.php new file mode 100644 index 0000000..9efddd7 --- /dev/null +++ b/vendor/qiniu/php-sdk/autoload.php @@ -0,0 +1,19 @@ +=5.3.3", + "ext-xml": "*", + "ext-curl": "*", + "myclabs/php-enum": "~1.5.2 || ~1.6.6 || ~1.7.7 || ~1.8.4" + }, + "require-dev": { + "paragonie/random_compat": ">=2", + "phpunit/phpunit": "^4.8 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4", + "squizlabs/php_codesniffer": "^2.3 || ~3.6" + }, + "autoload": { + "psr-4": { + "Qiniu\\": "src/Qiniu" + }, + "files": [ + "src/Qiniu/functions.php", + "src/Qiniu/Http/Middleware/Middleware.php" + ] + } +} diff --git a/vendor/qiniu/php-sdk/examples/README.md b/vendor/qiniu/php-sdk/examples/README.md new file mode 100644 index 0000000..b7b4f98 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/README.md @@ -0,0 +1,10 @@ +# examples + +这些 examples 旨在帮助你快速了解使用七牛的 SDK。这些 demo 都是可以直接运行的, 但是在运行之前需要填上您自己的参数。 + +比如: + +* `$bucket` 需要填上您想操作的 [bucket名字](https://portal.qiniu.com/kodo/bucket)。 +* `$accessKey` 和 `$secretKey` 可以在我们的[管理后台](https://portal.qiniu.com/user/key)找到。 +* 在进行`视频转码`, `压缩文件`等异步操作时 需要使用到的队列名称也可以在我们[管理后台](https://portal.qiniu.com/dora/media-gate/pipeline)新建。 + diff --git a/vendor/qiniu/php-sdk/examples/bucket_lifecycleRule.php b/vendor/qiniu/php-sdk/examples/bucket_lifecycleRule.php new file mode 100644 index 0000000..f51524c --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/bucket_lifecycleRule.php @@ -0,0 +1,42 @@ +bucketLifecycleRule( + $bucket, + $name, + $prefix, + $delete_after_days, + $to_line_after_days, + $to_archive_after_days, + $to_deep_archive_after_days, + $to_archive_ir_after_days +); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/cdn_get_bandwidth.php b/vendor/qiniu/php-sdk/examples/cdn_get_bandwidth.php new file mode 100644 index 0000000..c9de0e6 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/cdn_get_bandwidth.php @@ -0,0 +1,41 @@ +getBandwidthData( + $domains, + $startDate, + $endDate, + $granularity +); + +if ($getBandwidthErr != null) { + var_dump($getBandwidthErr); +} else { + echo "get bandwidth data success\n"; + print_r($bandwidthData); +} diff --git a/vendor/qiniu/php-sdk/examples/cdn_get_flux.php b/vendor/qiniu/php-sdk/examples/cdn_get_flux.php new file mode 100644 index 0000000..57df808 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/cdn_get_flux.php @@ -0,0 +1,35 @@ +getFluxData($domains, $startDate, $endDate, $granularity); +if ($getFluxErr != null) { + var_dump($getFluxErr); +} else { + echo "get flux data success\n"; + print_r($fluxData); +} diff --git a/vendor/qiniu/php-sdk/examples/cdn_get_log_list.php b/vendor/qiniu/php-sdk/examples/cdn_get_log_list.php new file mode 100644 index 0000000..2b3f7dd --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/cdn_get_log_list.php @@ -0,0 +1,31 @@ +getCdnLogList($domains, $logDate); +if ($getLogErr != null) { + var_dump($getLogErr); +} else { + echo "get cdn log list success\n"; + print_r($logListData); +} diff --git a/vendor/qiniu/php-sdk/examples/cdn_get_prefetch_list.php b/vendor/qiniu/php-sdk/examples/cdn_get_prefetch_list.php new file mode 100644 index 0000000..958e5eb --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/cdn_get_prefetch_list.php @@ -0,0 +1,46 @@ +getCdnPrefetchList( + $requestId, + $urls, + $state, + $pageNo, + $pageSize, + $startTime, + $endTime +); +echo "\n====> query prefetch list: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/cdn_get_refresh_list.php b/vendor/qiniu/php-sdk/examples/cdn_get_refresh_list.php new file mode 100644 index 0000000..ad4fca2 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/cdn_get_refresh_list.php @@ -0,0 +1,48 @@ +getCdnRefreshList( + $requestId, + $isDir, + $urls, + $state, + $pageNo, + $pageSize, + $startTime, + $endTime +); +echo "\n====> query refresh list: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/cdn_refresh_urls_dirs.php b/vendor/qiniu/php-sdk/examples/cdn_refresh_urls_dirs.php new file mode 100644 index 0000000..2140378 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/cdn_refresh_urls_dirs.php @@ -0,0 +1,59 @@ +refreshUrlsAndDirs($urls, $dirs); +if ($refreshErr != null) { + var_dump($refreshErr); +} else { + echo "refresh request sent\n"; + print_r($refreshResult); +} + +//---------------------------------------- demo2 ---------------------------------------- +// 刷新文件 + +list($refreshResult, $refreshErr) = $cdnManager->refreshUrls($urls); +if ($refreshErr != null) { + var_dump($refreshErr); +} else { + echo "refresh urls request sent\n"; + print_r($refreshResult); +} + +//---------------------------------------- demo3 ---------------------------------------- +// 刷新目录 + +list($refreshResult, $refreshErr) = $cdnManager->refreshDirs($dirs); +if ($refreshErr != null) { + var_dump($refreshErr); +} else { + echo "refresh dirs request sent\n"; + print_r($refreshResult); +} diff --git a/vendor/qiniu/php-sdk/examples/cdn_timestamp_antileech.php b/vendor/qiniu/php-sdk/examples/cdn_timestamp_antileech.php new file mode 100644 index 0000000..f2d7855 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/cdn_timestamp_antileech.php @@ -0,0 +1,20 @@ +censorImage($body); +echo "\n====> Result is: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/censor_video.php b/vendor/qiniu/php-sdk/examples/censor_video.php new file mode 100644 index 0000000..7ac056f --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/censor_video.php @@ -0,0 +1,52 @@ +censorVideo($body); +echo "\n====> Result is: \n"; +if ($err !== null) { + var_dump($err); +} else { + echo "job_id is: $jobid\n"; +} + +// 查询视频审核结果 +list($ret, $err) = $argusManager->censorStatus($jobid); +echo "\n====> job status: \n"; + +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/delete_bucket.php b/vendor/qiniu/php-sdk/examples/delete_bucket.php new file mode 100644 index 0000000..325a47a --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/delete_bucket.php @@ -0,0 +1,27 @@ +deleteBucket($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/delete_bucketEvent.php b/vendor/qiniu/php-sdk/examples/delete_bucketEvent.php new file mode 100644 index 0000000..7eb744d --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/delete_bucketEvent.php @@ -0,0 +1,28 @@ +deleteBucketEvent($bucket, $name); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/delete_bucketLifecycleRule.php b/vendor/qiniu/php-sdk/examples/delete_bucketLifecycleRule.php new file mode 100644 index 0000000..2146b1b --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/delete_bucketLifecycleRule.php @@ -0,0 +1,27 @@ +deleteBucketLifecycleRule($bucket, $name); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/get_bucketEvents.php b/vendor/qiniu/php-sdk/examples/get_bucketEvents.php new file mode 100644 index 0000000..2379584 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/get_bucketEvents.php @@ -0,0 +1,26 @@ +getBucketEvents($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/get_bucketLifecycleRules.php b/vendor/qiniu/php-sdk/examples/get_bucketLifecycleRules.php new file mode 100644 index 0000000..a35feed --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/get_bucketLifecycleRules.php @@ -0,0 +1,26 @@ +getBucketLifecycleRules($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/get_bucketList.php b/vendor/qiniu/php-sdk/examples/get_bucketList.php new file mode 100644 index 0000000..6a2f7b0 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/get_bucketList.php @@ -0,0 +1,26 @@ +listbuckets($region); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/get_bucketQuota.php b/vendor/qiniu/php-sdk/examples/get_bucketQuota.php new file mode 100644 index 0000000..93474b5 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/get_bucketQuota.php @@ -0,0 +1,26 @@ +getBucketQuota($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/get_bucketinfo.php b/vendor/qiniu/php-sdk/examples/get_bucketinfo.php new file mode 100644 index 0000000..98fd9f7 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/get_bucketinfo.php @@ -0,0 +1,25 @@ +bucketInfo($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/get_bucketinfos.php b/vendor/qiniu/php-sdk/examples/get_bucketinfos.php new file mode 100644 index 0000000..5eec1d8 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/get_bucketinfos.php @@ -0,0 +1,26 @@ +bucketInfos($region); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/get_corsRules.php b/vendor/qiniu/php-sdk/examples/get_corsRules.php new file mode 100644 index 0000000..58e28be --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/get_corsRules.php @@ -0,0 +1,26 @@ +getCorsRules($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/image_url_builder.php b/vendor/qiniu/php-sdk/examples/image_url_builder.php new file mode 100644 index 0000000..20e2b00 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/image_url_builder.php @@ -0,0 +1,74 @@ + + */ +$thumbLink = $imageUrlBuilder->thumbnail($url, 1, 100, 100); + +// 函数方式调用 也可拼接多个操作参数 图片+水印 +$thumbLink2 = \Qiniu\thumbnail($url2, 1, 100, 100); +var_dump($thumbLink, $thumbLink2); + +/** + * 图片水印 + * + * @param string $url 图片链接 + * @param string $image 水印图片链接 + * @param int $dissolve 透明度 [可选] + * @param string $gravity 水印位置 [可选] + * @param int $dx 横轴边距 [可选] + * @param int $dy 纵轴边距 [可选] + * @param int $watermarkScale 自适应原图的短边比例 [可选] + * @link https://developer.qiniu.com/dora/api/1316/image-watermarking-processing-watermark + * @return string + * @author Sherlock Ren + */ +$waterLink = $imageUrlBuilder->waterImg($url, $waterImage); +// 函数调用方法 +//$waterLink = \Qiniu\waterImg($url, $waterImage); +var_dump($waterLink); + +/** + * 文字水印 + * + * @param string $url 图片链接 + * @param string $text 文字 + * @param string $font 文字字体 + * @param string $fontSize 文字字号 + * @param string $fontColor 文字颜色 [可选] + * @param int $dissolve 透明度 [可选] + * @param string $gravity 水印位置 [可选] + * @param int $dx 横轴边距 [可选] + * @param int $dy 纵轴边距 [可选] + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html#text-watermark + * @return string + * @author Sherlock Ren + */ +$textLink = $imageUrlBuilder->waterText($url, '你瞅啥', '微软雅黑', 300); +// 函数调用方法 +// $textLink = \Qiniu\waterText($url, '你瞅啥', '微软雅黑', 300); +var_dump($textLink); diff --git a/vendor/qiniu/php-sdk/examples/persistent_fop_init.php b/vendor/qiniu/php-sdk/examples/persistent_fop_init.php new file mode 100644 index 0000000..baca846 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/persistent_fop_init.php @@ -0,0 +1,18 @@ +useHTTPS=true; + +// 初始化 +$pfop = new PersistentFop($auth, $config); diff --git a/vendor/qiniu/php-sdk/examples/persistent_fop_status.php b/vendor/qiniu/php-sdk/examples/persistent_fop_status.php new file mode 100644 index 0000000..73e85a3 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/persistent_fop_status.php @@ -0,0 +1,19 @@ +status($persistentId); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/pfop_mkzip.php b/vendor/qiniu/php-sdk/examples/pfop_mkzip.php new file mode 100644 index 0000000..fb95cc2 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/pfop_mkzip.php @@ -0,0 +1,58 @@ +execute($bucket, $key, $fops, $pipeline, $notify_url, $force); + +echo "\n====> pfop mkzip result: \n"; +if ($err != null) { + var_dump($err); +} else { + echo "PersistentFop Id: $id\n"; +} + +// 查询转码的进度和状态 +list($ret, $err) = $pfop->status($id); +echo "\n====> pfop mkzip status: \n"; +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/pfop_vframe.php b/vendor/qiniu/php-sdk/examples/pfop_vframe.php new file mode 100644 index 0000000..49fd36d --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/pfop_vframe.php @@ -0,0 +1,55 @@ +useHTTPS = true; +$pfop = new PersistentFop($auth, $config); + +// 视频处理完毕后保存到空间中的名称 +$saveasKey = 'qiniu_480x360.jpg'; + +// 进行视频截帧操作 +$fops = "vframe/jpg/offset/1/w/480/h/360/rotate/90|saveas/" . + \Qiniu\base64_urlSafeEncode("$bucket:$saveasKey"); + +list($id, $err) = $pfop->execute($bucket, $key, $fops, $pipeline, $notifyUrl, $force); +echo "\n====> pfop avthumb result: \n"; +if ($err != null) { + var_dump($err); +} else { + echo "PersistentFop Id: $id\n"; +} + +// 查询转码的进度和状态 +list($ret, $err) = $pfop->status($id); +echo "\n====> pfop avthumb status: \n"; +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/pfop_video_avthumb.php b/vendor/qiniu/php-sdk/examples/pfop_video_avthumb.php new file mode 100644 index 0000000..986aa8c --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/pfop_video_avthumb.php @@ -0,0 +1,55 @@ +useHTTPS=true; + +// 视频处理完毕后保存到空间中的名称 +$saveasKey = 'qiniu_640x360.mp4'; + +$pfop = new PersistentFop($auth, $config); + +// 进行视频转码操作 +$fops = "avthumb/mp4/s/640x360/vb/1.4m|saveas/" . \Qiniu\base64_urlSafeEncode("$bucket:$saveasKey"); + +list($id, $err) = $pfop->execute($bucket, $key, $fops, $pipeline, $notifyUrl, $force); +echo "\n====> pfop avthumb result: \n"; +if ($err != null) { + var_dump($err); +} else { + echo "PersistentFop Id: $id\n"; +} + +// 查询转码的进度和状态 +list($ret, $err) = $pfop->status($id); +echo "\n====> pfop avthumb status: \n"; +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/pfop_watermark.php b/vendor/qiniu/php-sdk/examples/pfop_watermark.php new file mode 100644 index 0000000..ea3d6bc --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/pfop_watermark.php @@ -0,0 +1,59 @@ +useHTTPS=true; +$pfop = new PersistentFop($auth, $config); + +// 图片水印的源路径,也就是给视频打图片水印的图片 +$base64URL = Qiniu\base64_urlSafeEncode('http://test-2.qiniudn.com/logo.png'); + +// 视频处理完毕后保存到空间中的名称 +$saveasKey = 'qiniu_watermark.mp4'; + +// 进行视频打图片水印操作 +$fops = "avthumb/mp4/wmImage/" . $base64URL . "|saveas/" + . \Qiniu\base64_urlSafeEncode("$bucket:$saveasKey"); + +list($id, $err) = $pfop->execute($bucket, $key, $fops, $pipeline, $notifyUrl, $force); +echo "\n====> pfop avthumb result: \n"; +if ($err != null) { + var_dump($err); +} else { + echo "PersistentFop Id: $id\n"; +} + +// 查询转码的进度和状态 +list($ret, $err) = $pfop->status($id); +echo "\n====> pfop avthumb status: \n"; +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/php-logo.png b/vendor/qiniu/php-sdk/examples/php-logo.png new file mode 100644 index 0000000..77e051f Binary files /dev/null and b/vendor/qiniu/php-sdk/examples/php-logo.png differ diff --git a/vendor/qiniu/php-sdk/examples/prefop.php b/vendor/qiniu/php-sdk/examples/prefop.php new file mode 100644 index 0000000..1b8950a --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/prefop.php @@ -0,0 +1,27 @@ +useHTTPS=true; + +$pfop = new PersistentFop($auth, $config); + +$id = "z2.01z201c4oyre6q1hgy00murnel0002nh"; + +// 查询持久化处理的进度和状态 +list($ret, $err) = $pfop->status($id); +echo "\n====> pfop avthumb status: \n"; +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/put_bucketAccessMode.php b/vendor/qiniu/php-sdk/examples/put_bucketAccessMode.php new file mode 100644 index 0000000..638ae3c --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/put_bucketAccessMode.php @@ -0,0 +1,27 @@ +putBucketAccessMode($bucket, $private); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/put_bucketAccessStyleMode.php b/vendor/qiniu/php-sdk/examples/put_bucketAccessStyleMode.php new file mode 100644 index 0000000..3cc2aec --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/put_bucketAccessStyleMode.php @@ -0,0 +1,27 @@ +putBucketAccessStyleMode($bucket, $mode); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/put_bucketEvent.php b/vendor/qiniu/php-sdk/examples/put_bucketEvent.php new file mode 100644 index 0000000..f3c830d --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/put_bucketEvent.php @@ -0,0 +1,32 @@ +putBucketEvent($bucket, $name, $prefix, $suffix, $event, $callbackURL); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/put_bucketMaxAge.php b/vendor/qiniu/php-sdk/examples/put_bucketMaxAge.php new file mode 100644 index 0000000..4890174 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/put_bucketMaxAge.php @@ -0,0 +1,27 @@ +putBucketMaxAge($bucket, $maxAge); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/put_bucketQuota.php b/vendor/qiniu/php-sdk/examples/put_bucketQuota.php new file mode 100644 index 0000000..b00ec48 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/put_bucketQuota.php @@ -0,0 +1,29 @@ +putBucketQuota($bucket, $size, $count); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/put_referAntiLeech.php b/vendor/qiniu/php-sdk/examples/put_referAntiLeech.php new file mode 100644 index 0000000..7d56d1e --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/put_referAntiLeech.php @@ -0,0 +1,30 @@ +putReferAntiLeech($bucket, $mode, $norefer, $pattern); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/qetag.php b/vendor/qiniu/php-sdk/examples/qetag.php new file mode 100644 index 0000000..1fe90d1 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/qetag.php @@ -0,0 +1,14 @@ +useHTTPS = true; // 接口是否使用 HTTPS 协议 + +$bucketManager = new BucketManager($auth, $config); + +// 异步第三方资源抓取 +// 参考文档:https://developer.qiniu.com/kodo/api/4097/asynch-fetch + +// 需要抓取的文件 URL +$url = 'http://devtools.qiniu.com/qiniu.png'; + +//回调 URL(需要可以公网访问,并能够相应 200 OK) +$callbackurl = "http://your.domain.com/upload_verify_callback.php"; + +// 回调Body +$callbackbody = '{"key":"$(key)","hash":"$(etag)","w":"$(imageInfo.width)","h":"$(imageInfo.height)"}'; + + +//---------------------------------------- demo1 ---------------------------------------- +// 指定抓取的文件保存到七牛云空间中的名称 + +$key = time() . '.png'; +list($ret, $err) = $bucketManager->asynchFetch($url, $bucket, null, $key, null, null, $callbackurl, $callbackbody); +echo "=====> asynch fetch $url to bucket: $bucket key: $key\n"; +if ($err !== null) { + var_dump($err); +} else { + $id = $ret['id']; + echo "id is: $id\n"; +} + +//---------------------------------------- demo2 ---------------------------------------- +// 不指定 key 时,以文件内容的 hash 作为文件名 + +$key = null; +list($ret, $err) = $bucketManager->asynchFetch($url, $bucket, null, $key, null, null, $callbackurl, $callbackbody); +echo "=====> asynch fetch $url to bucket: $bucket key: $(etag)\n"; +if ($err !== null) { + var_dump($err); +} else { + $id = $ret['id']; + echo "id is: $id\n"; +} + +// 查询异步抓取的进度和状态 + +// 华东:z0,华北:z1,华南:z2,北美:na0,东南亚:as0 +$zone = 'z2'; + +sleep(10); // 由于异步抓取需要耗时,等待 10 秒后再查询状态 +list($ret, $err) = $bucketManager->asynchFetchStatus($zone, $id); +echo "\n====> asynch fetch status: \n"; +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_batch_change_mime.php b/vendor/qiniu/php-sdk/examples/rs_batch_change_mime.php new file mode 100644 index 0000000..c5bd6b4 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_batch_change_mime.php @@ -0,0 +1,32 @@ + 'video/x-mp4', + 'qiniu.png' => 'image/x-png', + 'qiniu.jpg' => 'image/x-jpg' +); + +$ops = $bucketManager->buildBatchChangeMime($bucket, $keyMimePairs); +list($ret, $err) = $bucketManager->batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_batch_change_type.php b/vendor/qiniu/php-sdk/examples/rs_batch_change_type.php new file mode 100644 index 0000000..a19d0d4 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_batch_change_type.php @@ -0,0 +1,45 @@ +batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_batch_copy.php b/vendor/qiniu/php-sdk/examples/rs_batch_copy.php new file mode 100644 index 0000000..66c4d4d --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_batch_copy.php @@ -0,0 +1,40 @@ +buildBatchCopy($srcBucket, $keyPairs, $destBucket, true); +list($ret, $err) = $bucketManager->batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_batch_delete.php b/vendor/qiniu/php-sdk/examples/rs_batch_delete.php new file mode 100644 index 0000000..ebcdbe6 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_batch_delete.php @@ -0,0 +1,32 @@ +buildBatchDelete($bucket, $keys); +list($ret, $err) = $bucketManager->batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_batch_delete_after_days.php b/vendor/qiniu/php-sdk/examples/rs_batch_delete_after_days.php new file mode 100644 index 0000000..928dd14 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_batch_delete_after_days.php @@ -0,0 +1,39 @@ +buildBatchDeleteAfterDays($bucket, $keyDayPairs); +list($ret, $err) = $bucketManager->batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_batch_move.php b/vendor/qiniu/php-sdk/examples/rs_batch_move.php new file mode 100644 index 0000000..01d8c91 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_batch_move.php @@ -0,0 +1,40 @@ +buildBatchMove($srcBucket, $keyPairs, $destBucket, true); +list($ret, $err) = $bucketManager->batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_batch_restore_ar.php b/vendor/qiniu/php-sdk/examples/rs_batch_restore_ar.php new file mode 100644 index 0000000..b2f79d0 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_batch_restore_ar.php @@ -0,0 +1,41 @@ +batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_batch_stat.php b/vendor/qiniu/php-sdk/examples/rs_batch_stat.php new file mode 100644 index 0000000..88bc32e --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_batch_stat.php @@ -0,0 +1,32 @@ +buildBatchStat($bucket, $keys); +list($ret, $err) = $bucketManager->batch($ops); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_bucket_domains.php b/vendor/qiniu/php-sdk/examples/rs_bucket_domains.php new file mode 100644 index 0000000..3cc9cb3 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_bucket_domains.php @@ -0,0 +1,26 @@ +domains($bucket); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_buckets.php b/vendor/qiniu/php-sdk/examples/rs_buckets.php new file mode 100644 index 0000000..84263a9 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_buckets.php @@ -0,0 +1,25 @@ +buckets(true); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_change_mime.php b/vendor/qiniu/php-sdk/examples/rs_change_mime.php new file mode 100644 index 0000000..f4442aa --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_change_mime.php @@ -0,0 +1,29 @@ +changeMime($bucket, $key, $newMime); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_change_status.php b/vendor/qiniu/php-sdk/examples/rs_change_status.php new file mode 100644 index 0000000..bedf61c --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_change_status.php @@ -0,0 +1,29 @@ +changeStatus($bucket, $key, $status); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_change_type.php b/vendor/qiniu/php-sdk/examples/rs_change_type.php new file mode 100644 index 0000000..8b3201f --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_change_type.php @@ -0,0 +1,36 @@ +changeType($bucket, $key, $fileType); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_copy.php b/vendor/qiniu/php-sdk/examples/rs_copy.php new file mode 100644 index 0000000..aae4d96 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_copy.php @@ -0,0 +1,33 @@ +copy($srcBucket, $srcKey, $destBucket, $destKey, true); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_delete.php b/vendor/qiniu/php-sdk/examples/rs_delete.php new file mode 100644 index 0000000..ad97266 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_delete.php @@ -0,0 +1,27 @@ +delete($bucket, $key); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_delete_after_days.php b/vendor/qiniu/php-sdk/examples/rs_delete_after_days.php new file mode 100644 index 0000000..96e55de --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_delete_after_days.php @@ -0,0 +1,26 @@ +deleteAfterDays($bucket, $key, $days); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_download_urls.php b/vendor/qiniu/php-sdk/examples/rs_download_urls.php new file mode 100644 index 0000000..e803ddc --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_download_urls.php @@ -0,0 +1,19 @@ +/,一定要带访问协议,也就是 http:// 或者 https:// +$baseUrl = 'http://if-pri.qiniudn.com/qiniu.png?imageView2/1/h/500'; + +// 对链接进行签名,参考文档:https://developer.qiniu.com/kodo/manual/1656/download-private +$signedUrl = $auth->privateDownloadUrl($baseUrl); + +echo $signedUrl; diff --git a/vendor/qiniu/php-sdk/examples/rs_fetch.php b/vendor/qiniu/php-sdk/examples/rs_fetch.php new file mode 100644 index 0000000..5c1a5ab --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_fetch.php @@ -0,0 +1,43 @@ +fetch($url, $bucket, $key); +echo "=====> fetch $url to bucket: $bucket key: $key\n"; +if ($err !== null) { + var_dump($err); +} else { + print_r($ret); +} + +//---------------------------------------- demo2 ---------------------------------------- +// 不指定 key 时,以文件内容的 hash 作为文件名 + +$key = null; +list($ret, $err) = $bucketManager->fetch($url, $bucket, $key); +echo "=====> fetch $url to bucket: $bucket key: $(etag)\n"; +if ($err !== null) { + var_dump($err); +} else { + print_r($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_move.php b/vendor/qiniu/php-sdk/examples/rs_move.php new file mode 100644 index 0000000..a399665 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_move.php @@ -0,0 +1,29 @@ +move($srcBucket, $srcKey, $destBucket, $destKey, true); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_prefetch.php b/vendor/qiniu/php-sdk/examples/rs_prefetch.php new file mode 100644 index 0000000..28af115 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_prefetch.php @@ -0,0 +1,25 @@ +prefetch($bucket, $key); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_restore.php b/vendor/qiniu/php-sdk/examples/rs_restore.php new file mode 100644 index 0000000..a3bf070 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_restore.php @@ -0,0 +1,28 @@ +restoreAr($bucket, $key, 1); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rs_stat.php b/vendor/qiniu/php-sdk/examples/rs_stat.php new file mode 100644 index 0000000..36e863e --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rs_stat.php @@ -0,0 +1,28 @@ +stat($bucket, $key); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rsf_list_bucket.php b/vendor/qiniu/php-sdk/examples/rsf_list_bucket.php new file mode 100644 index 0000000..97a5838 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rsf_list_bucket.php @@ -0,0 +1,47 @@ +listFiles($bucket, $prefix, $marker, $limit, $delimiter); + if ($err !== null) { + echo "\n====> list file err: \n"; + var_dump($err); + } else { + $marker = null; + if (array_key_exists('marker', $ret)) { + $marker = $ret['marker']; + } + echo "Marker: $marker\n"; + echo "\nList Items====>\n"; + //var_dump($ret['items']); + print('items count:' . count($ret['items']) . "\n"); + if (array_key_exists('commonPrefixes', $ret)) { + print_r($ret['commonPrefixes']); + } + } +} while (!empty($marker)); diff --git a/vendor/qiniu/php-sdk/examples/rsf_list_files.php b/vendor/qiniu/php-sdk/examples/rsf_list_files.php new file mode 100644 index 0000000..31c455b --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rsf_list_files.php @@ -0,0 +1,39 @@ +listFiles($bucket, $prefix, $marker, $limit, $delimiter); +if ($err !== null) { + echo "\n====> list file err: \n"; + var_dump($err); +} else { + if (array_key_exists('marker', $ret)) { + echo "Marker:" . $ret["marker"] . "\n"; + } + echo "\nList Iterms====>\n"; +} diff --git a/vendor/qiniu/php-sdk/examples/rsf_v2list_bucket.php b/vendor/qiniu/php-sdk/examples/rsf_v2list_bucket.php new file mode 100644 index 0000000..5f9d763 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rsf_v2list_bucket.php @@ -0,0 +1,34 @@ +listFilesv2($bucket, $prefix, $marker, $limit, $delimiter, true); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rtc/README.md b/vendor/qiniu/php-sdk/examples/rtc/README.md new file mode 100644 index 0000000..c7fff4d --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rtc/README.md @@ -0,0 +1,34 @@ +# Rtc Streaming Cloud Server-Side Library For PHP + +## Features + +- RoomToken 签发 + - [x] 生成 RoomToken: client->appToken() + +- App 管理 + - [x] 创建应用: client->createApp() + - [x] 获取应用配置信息: client->getApp() + - [x] 更新应用配置信息: client->updateApp() + - [x] 删除应用: client->deleteApp() + +- 房间管理 + - [x] 列举房间下的所有用户: client->listUser() + - [x] 指定一个用户踢出房间: client->kickUser() + - [x] 停止一个房间的合流转推: client->stopMerge() + - [x] 获取当前所有活跃的房间: client->listActiveRooms() + +## Demo +- RoomToken 签发 + - [生成 RoomToken](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_create_roomToken.php) + +- App 管理 + - [创建应用](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_createApp.php) + - [获取应用配置信息](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_getApp.php) + - [更新应用配置信息](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_updateApp.php) + - [删除应用](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_deleteApp.php) + +- 房间管理 + - [列举房间下的所有用户](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_rooms_listUser.php) + - [指定一个用户踢出房间](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_rooms_kickUser.php) + - [停止一个房间的合流转推](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_rooms_stopMerge.php) + - [获取当前所有活跃的房间](https://github.com/qiniu/php-sdk/tree/master/examples/rtc/rtc_rooms_listActiveRooms.php) \ No newline at end of file diff --git a/vendor/qiniu/php-sdk/examples/rtc/rtc_createApp.php b/vendor/qiniu/php-sdk/examples/rtc/rtc_createApp.php new file mode 100644 index 0000000..039eadd --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rtc/rtc_createApp.php @@ -0,0 +1,32 @@ +createApp($hub, $title, $maxUsers); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Create Successfully: \n"; + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rtc/rtc_create_roomToken.php b/vendor/qiniu/php-sdk/examples/rtc/rtc_create_roomToken.php new file mode 100644 index 0000000..6a62aa2 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rtc/rtc_create_roomToken.php @@ -0,0 +1,34 @@ +appToken($appId, $roomName, $userId, $expireAt, $permission); +echo "\n====> Create RoomToken Successfully: \n"; +var_dump($RoomToken); diff --git a/vendor/qiniu/php-sdk/examples/rtc/rtc_deleteApp.php b/vendor/qiniu/php-sdk/examples/rtc/rtc_deleteApp.php new file mode 100644 index 0000000..68bff33 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rtc/rtc_deleteApp.php @@ -0,0 +1,25 @@ +deleteApp($appId); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Delete $appId Successfully \n"; +} diff --git a/vendor/qiniu/php-sdk/examples/rtc/rtc_getApp.php b/vendor/qiniu/php-sdk/examples/rtc/rtc_getApp.php new file mode 100644 index 0000000..9f8e374 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rtc/rtc_getApp.php @@ -0,0 +1,26 @@ +getApp($appId); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> $appId Conf: \n"; + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rtc/rtc_rooms_kickUser.php b/vendor/qiniu/php-sdk/examples/rtc/rtc_rooms_kickUser.php new file mode 100644 index 0000000..019c3f2 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rtc/rtc_rooms_kickUser.php @@ -0,0 +1,31 @@ +kickUser($appId, $roomName, $userId); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Kick User $userId Successfully \n"; +} diff --git a/vendor/qiniu/php-sdk/examples/rtc/rtc_rooms_listActiveRooms.php b/vendor/qiniu/php-sdk/examples/rtc/rtc_rooms_listActiveRooms.php new file mode 100644 index 0000000..16e6027 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rtc/rtc_rooms_listActiveRooms.php @@ -0,0 +1,35 @@ +listActiveRooms($appId, $prefix, $offset, $limit); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Active Rooms:\n"; + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rtc/rtc_rooms_listUser.php b/vendor/qiniu/php-sdk/examples/rtc/rtc_rooms_listUser.php new file mode 100644 index 0000000..a839728 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rtc/rtc_rooms_listUser.php @@ -0,0 +1,29 @@ +listUser($appId, $roomName); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> User List: \n"; + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/rtc/rtc_rooms_stopMerge.php b/vendor/qiniu/php-sdk/examples/rtc/rtc_rooms_stopMerge.php new file mode 100644 index 0000000..e140907 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rtc/rtc_rooms_stopMerge.php @@ -0,0 +1,28 @@ +stopMerge($appId, $roomName); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Stop Merge Successfully \n"; +} diff --git a/vendor/qiniu/php-sdk/examples/rtc/rtc_updateApp.php b/vendor/qiniu/php-sdk/examples/rtc/rtc_updateApp.php new file mode 100644 index 0000000..f771075 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/rtc/rtc_updateApp.php @@ -0,0 +1,40 @@ +updateApp($appId, $hub, $title, $maxUsers, false, $mergePublishRtmp); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Update $appId Conf Successfully: \n"; + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/saveas.php b/vendor/qiniu/php-sdk/examples/saveas.php new file mode 100644 index 0000000..5d51ef4 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/saveas.php @@ -0,0 +1,33 @@ +为生成缩略图的文件名 +$entry = ':'; + +// 生成的值 +$encodedEntryURI = \Qiniu\base64_urlSafeEncode($entry); + +// 使用 SecretKey 对新的下载 URL 进行 HMAC1-SHA1 签名 +$newurl = "78re52.com1.z0.glb.clouddn.com/resource/Ship.jpg?imageView2/2/w/200/h/200|saveas/" . $encodedEntryURI; + +$sign = hash_hmac("sha1", $newurl, $secretKey, true); + +// 对签名进行 URL 安全的 Base64 编码 +$encodedSign = \Qiniu\base64_urlSafeEncode($sign); + +// 最终得到的完整下载 URL +$finalURL = "http://" . $newurl . "/sign/" . $accessKey . ":" . $encodedSign; + +$callbackBody = file_get_contents("$finalURL"); + +echo $callbackBody; diff --git a/vendor/qiniu/php-sdk/examples/sms/README.md b/vendor/qiniu/php-sdk/examples/sms/README.md new file mode 100644 index 0000000..8c80a38 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/sms/README.md @@ -0,0 +1,45 @@ +# SMS Server-Side Library For PHP + +## Features + +- 签名管理 + - [x] 创建签名: client->createSignature() + - [x] 列出签名: client->checkSignature() + - [x] 查询单个签名: client->checkSingleSignature() + - [x] 编辑签名: client->updateSignature() + - [x] 删除签名: client->deleteSignature() + +- 模板管理 + - [x] 创建模板: client->createTemplate() + - [x] 列出模板: client->queryTemplate() + - [x] 查询单个模板: client->querySingleTemplate() + - [x] 编辑模板: client->updateTemplate() + - [x] 删除模板: client->deleteTemplate() + +- 发送短信 + - [x] 发送短信: client->sendMessage() + +- 查询发送记录 + - [x] 查询发送记录: client->querySendSms() + +## Demo + +- 签名管理 + - [创建签名](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_create_signature.php) + - [列出签名](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_query_signature.php) + - [查询单个签名](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_query_single_signature.php) + - [编辑签名](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_edit_signature.php) + - [删除签名](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_delete_signature.php) + +- 模板管理 + - [创建模板](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_create_template.php) + - [列出模板](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_query_template.php) + - [查询单个模板](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_query_single_template.php) + - [编辑模板](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_edit_template.php) + - [删除模板](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_delete_template.php) + +- 发送短信 + - [发送短信](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_send_message.php) + +- 查询发送记录 + - [查询发送记录](https://github.com/qiniu/php-sdk/tree/master/examples/sms/sms_query_send_sms.php) diff --git a/vendor/qiniu/php-sdk/examples/sms/sms_create_signature.php b/vendor/qiniu/php-sdk/examples/sms/sms_create_signature.php new file mode 100644 index 0000000..ea1f158 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/sms/sms_create_signature.php @@ -0,0 +1,29 @@ +createSignature($signature, $source, $pics); + +echo "\n====> create signature result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/sms/sms_create_template.php b/vendor/qiniu/php-sdk/examples/sms/sms_create_template.php new file mode 100644 index 0000000..3cb3874 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/sms/sms_create_template.php @@ -0,0 +1,33 @@ +createTemplate($name, $template, $type, $description, $signature_id); + +echo "\n====> create signature result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/sms/sms_delete_signature.php b/vendor/qiniu/php-sdk/examples/sms/sms_delete_signature.php new file mode 100644 index 0000000..fd873fa --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/sms/sms_delete_signature.php @@ -0,0 +1,25 @@ +deleteSignature($signature_id); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Delete Signature $signature_id Successfully\n"; +} diff --git a/vendor/qiniu/php-sdk/examples/sms/sms_delete_template.php b/vendor/qiniu/php-sdk/examples/sms/sms_delete_template.php new file mode 100644 index 0000000..4590835 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/sms/sms_delete_template.php @@ -0,0 +1,25 @@ +deleteTemplate($template_id); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Delete Template $template_id Successfully\n"; +} diff --git a/vendor/qiniu/php-sdk/examples/sms/sms_edit_signature.php b/vendor/qiniu/php-sdk/examples/sms/sms_edit_signature.php new file mode 100644 index 0000000..edf14e0 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/sms/sms_edit_signature.php @@ -0,0 +1,30 @@ +updateSignature($id, $signature, $source, $pics); + +echo "\n====> edit signature result: \n"; +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Update Signature Successfully\n"; +} diff --git a/vendor/qiniu/php-sdk/examples/sms/sms_edit_template.php b/vendor/qiniu/php-sdk/examples/sms/sms_edit_template.php new file mode 100644 index 0000000..1be5509 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/sms/sms_edit_template.php @@ -0,0 +1,31 @@ +updateTemplate($template_id, $name, $template, $description, $signature_id); + +echo "\n====> edit template result: \n"; +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Update Template Successfully\n"; +} diff --git a/vendor/qiniu/php-sdk/examples/sms/sms_query_send_sms.php b/vendor/qiniu/php-sdk/examples/sms/sms_query_send_sms.php new file mode 100644 index 0000000..cdbbe71 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/sms/sms_query_send_sms.php @@ -0,0 +1,50 @@ +querySendSms( + $job_id, + $message_id, + $mobile, + $status, + $template_id, + $type, + $start, + $end, + $page, + $page_size +); +echo "\n====> query send sms result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/sms/sms_query_signature.php b/vendor/qiniu/php-sdk/examples/sms/sms_query_signature.php new file mode 100644 index 0000000..224d09b --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/sms/sms_query_signature.php @@ -0,0 +1,28 @@ +querySignature($audit_status, $page, $page_size); +echo "\n====> query signature result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/sms/sms_query_single_signature.php b/vendor/qiniu/php-sdk/examples/sms/sms_query_single_signature.php new file mode 100644 index 0000000..8afb4d5 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/sms/sms_query_single_signature.php @@ -0,0 +1,26 @@ +checkSingleSignature($signature_id); +echo "\n====> query single signature result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/sms/sms_query_single_template.php b/vendor/qiniu/php-sdk/examples/sms/sms_query_single_template.php new file mode 100644 index 0000000..8e0b279 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/sms/sms_query_single_template.php @@ -0,0 +1,26 @@ +querySingleTemplate($template_id); +echo "\n====> query single template result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/sms/sms_query_template.php b/vendor/qiniu/php-sdk/examples/sms/sms_query_template.php new file mode 100644 index 0000000..6be260e --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/sms/sms_query_template.php @@ -0,0 +1,28 @@ +queryTemplate($audit_status, $page, $page_size); +echo "\n====> query template result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/sms/sms_send_message.php b/vendor/qiniu/php-sdk/examples/sms/sms_send_message.php new file mode 100644 index 0000000..d943e52 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/sms/sms_send_message.php @@ -0,0 +1,32 @@ + 'xxxx'); + +list($ret, $err) = $client->sendMessage($template_id, $mobiles, $code); +if ($err !== null) { + var_dump($err); +} else { + echo "\n====> Send Message Successfully: \n"; + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/update_bucketEvent.php b/vendor/qiniu/php-sdk/examples/update_bucketEvent.php new file mode 100644 index 0000000..7b0d1d0 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/update_bucketEvent.php @@ -0,0 +1,31 @@ +updateBucketEvent($bucket, $name, $prefix, $suffix, $event, $callbackURL); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/update_bucketLifecycleRule.php b/vendor/qiniu/php-sdk/examples/update_bucketLifecycleRule.php new file mode 100644 index 0000000..73f0f56 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/update_bucketLifecycleRule.php @@ -0,0 +1,36 @@ +updateBucketLifecycleRule( + $bucket, + $name, + $prefix, + $delete_after_days, + $to_line_after_days +); +if ($err != null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/upload_and_callback.php b/vendor/qiniu/php-sdk/examples/upload_and_callback.php new file mode 100644 index 0000000..a0c793a --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/upload_and_callback.php @@ -0,0 +1,31 @@ + 'http://your.domain.com/upload_verify_callback.php', + 'callbackBody' => 'filename=$(fname)&filesize=$(fsize)' +); +$uptoken = $auth->uploadToken($bucket, null, 3600, $policy); + +// 上传文件的本地路径 +$filePath = './php-logo.png'; + +$uploadMgr = new UploadManager(); +list($ret, $err) = $uploadMgr->putFile($uptoken, null, $filePath); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/upload_and_pfop.php b/vendor/qiniu/php-sdk/examples/upload_and_pfop.php new file mode 100644 index 0000000..32c1eb5 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/upload_and_pfop.php @@ -0,0 +1,49 @@ + $pfop, + 'persistentNotifyUrl' => $notifyUrl, + 'persistentPipeline' => $pipeline +); +$token = $auth->uploadToken($bucket, null, 3600, $policy); + +list($ret, $err) = $uploadMgr->putFile($token, $key, $filePath); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/upload_mgr_init.php b/vendor/qiniu/php-sdk/examples/upload_mgr_init.php new file mode 100644 index 0000000..1164c90 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/upload_mgr_init.php @@ -0,0 +1,19 @@ +uploadToken($bucket); + +// 构建 UploadManager 对象 +$uploadMgr = new UploadManager(); diff --git a/vendor/qiniu/php-sdk/examples/upload_multi_demos.php b/vendor/qiniu/php-sdk/examples/upload_multi_demos.php new file mode 100644 index 0000000..d724235 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/upload_multi_demos.php @@ -0,0 +1,89 @@ +uploadToken($bucket); +$uploadMgr = new UploadManager(); + +//---------------------------------------- upload demo1 ---------------------------------------- +// 上传字符串到七牛 + +list($ret, $err) = $uploadMgr->put($token, null, 'content string'); +echo "\n====> put result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} + + +//---------------------------------------- upload demo2 ---------------------------------------- +// 上传文件到七牛 + +$filePath = './php-logo.png'; +$key = 'php-logo.png'; +list($ret, $err) = $uploadMgr->putFile($token, $key, $filePath); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} + + +//---------------------------------------- upload demo3 ---------------------------------------- +// 上传文件到七牛后, 七牛将文件名和文件大小回调给业务服务器. +// 可参考文档: https://developer.qiniu.com/kodo/manual/1206/put-policy + +$policy = array( + 'callbackUrl' => 'http://172.30.251.210/upload_verify_callback.php', + 'callbackBody' => 'filename=$(fname)&filesize=$(fsize)' +// 'callbackBodyType' => 'application/json', +// 'callbackBody' => '{"filename":$(fname), "filesize": $(fsize)}' //设置application/json格式回调 +); +$token = $auth->uploadToken($bucket, null, 3600, $policy); + + +list($ret, $err) = $uploadMgr->putFile($token, null, $key); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} + + +//---------------------------------------- upload demo4 ---------------------------------------- +// 上传视频,上传完成后进行 m3u8 的转码, 并给视频打水印 + +$wmImg = Qiniu\base64_urlSafeEncode('http://devtools.qiniudn.com/qiniu.png'); +$pfop = "avthumb/m3u8/wmImage/$wmImg"; + +// 转码完成后回调到业务服务器。(公网可以访问,并相应 200 OK) +$notifyUrl = 'http://notify.fake.com'; + +$policy = array( + 'persistentOps' => $pfop, + 'persistentNotifyUrl' => $notifyUrl, + 'persistentPipeline' => $pipeline +); +$token = $auth->uploadToken($bucket, null, 3600, $policy); +print($token); +list($ret, $err) = $uploadMgr->putFile($token, null, $key); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/upload_simple_file.php b/vendor/qiniu/php-sdk/examples/upload_simple_file.php new file mode 100644 index 0000000..f495a02 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/upload_simple_file.php @@ -0,0 +1,37 @@ +uploadToken($bucket); + +// 要上传文件的本地路径 +$filePath = './php-logo.png'; + +// 上传到七牛存储后保存的文件名 +$key = 'my-php-logo.png'; + +// 初始化 UploadManager 对象并进行文件的上传。 +$uploadMgr = new UploadManager(); + +// 调用 UploadManager 的 putFile 方法进行文件的上传,该方法会判断文件大小,进而决定使用表单上传还是分片上传,无需手动配置。 +list($ret, $err) = $uploadMgr->putFile($token, $key, $filePath); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/upload_tokens.php b/vendor/qiniu/php-sdk/examples/upload_tokens.php new file mode 100644 index 0000000..d2cf02c --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/upload_tokens.php @@ -0,0 +1,82 @@ +uploadToken($bucket, null, $expires, $policy, true); +print($upToken . "\n"); + +//---------------------------------------- demo2 ---------------------------------------- +// 自定义凭证有效期(示例2小时) + +$expires = 7200; +$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true); +print($upToken . "\n"); + +//---------------------------------------- demo3 ---------------------------------------- +// 覆盖上传凭证 + +$expires = 3600; +$keyToOverwrite = 'qiniu.mp4'; +$upToken = $auth->uploadToken($bucket, $keyToOverwrite, $expires, $policy, true); +print($upToken . "\n"); + +//---------------------------------------- demo4 ---------------------------------------- +// 自定义上传回复(非callback模式)凭证 + +$returnBody = '{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}'; +$policy = array( + 'returnBody' => $returnBody +); +$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true); +print($upToken . "\n"); + +//---------------------------------------- demo5 ---------------------------------------- +// 带回调业务服务器的凭证(application/json) + +$policy = array( + 'callbackUrl' => 'http://api.example.com/qiniu/upload/callback', + 'callbackBody' => '{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}', + 'callbackBodyType' => 'application/json' +); +$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true); +print($upToken . "\n"); + +//---------------------------------------- demo6 ---------------------------------------- +// 带回调业务服务器的凭证(application/x-www-form-urlencoded) + +$policy = array( + 'callbackUrl' => 'http://api.example.com/qiniu/upload/callback', + 'callbackBody' => 'key=$(key)&hash=$(etag)&bucket=$(bucket)&fsize=$(fsize)&name=$(x:name)' +); +$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true); +print($upToken . "\n"); + +//---------------------------------------- demo7 ---------------------------------------- +// 带数据处理的凭证 + +$saveMp4Entry = \Qiniu\base64_urlSafeEncode($bucket . ":avthumb_test_target.mp4"); +$saveJpgEntry = \Qiniu\base64_urlSafeEncode($bucket . ":vframe_test_target.jpg"); +$avthumbMp4Fop = "avthumb/mp4|saveas/" . $saveMp4Entry; +$vframeJpgFop = "vframe/jpg/offset/1|saveas/" . $saveJpgEntry; +$policy = array( + 'persistentOps' => $avthumbMp4Fop . ";" . $vframeJpgFop, + 'persistentPipeline' => "video-pipe", + 'persistentNotifyUrl' => "http://api.example.com/qiniu/pfop/notify", +); +$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true); +print($upToken . "\n"); diff --git a/vendor/qiniu/php-sdk/examples/upload_verify_callback.php b/vendor/qiniu/php-sdk/examples/upload_verify_callback.php new file mode 100644 index 0000000..dcb64c9 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/upload_verify_callback.php @@ -0,0 +1,34 @@ +verifyCallback($contentType, $authorization, $url, $callbackBody); + +if ($isQiniuCallback) { + $resp = array('ret' => 'success'); +} else { + $resp = array('ret' => 'failed'); +} + +echo json_encode($resp); diff --git a/vendor/qiniu/php-sdk/examples/upload_with_qvmzone.php b/vendor/qiniu/php-sdk/examples/upload_with_qvmzone.php new file mode 100644 index 0000000..ce2b21f --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/upload_with_qvmzone.php @@ -0,0 +1,40 @@ +uploadToken($bucket); + +// 上传文件的本地路径 +$filePath = './php-logo.png'; + +// 七牛云主机QVM和七牛对象存储KODO内网上传,目前支持华东1区域(杭州)和华北2区域(北京)的云主机可以访问同区域的对象存储服务 +// 参考文档:https://developer.qiniu.com/qvm/manual/4269/qvm-kodo + +$zone = Zone::qvmZonez0(); // 华东:z0,华北:z1 +$config = new Config($zone); +$config->useHTTPS = true; + +// 指定 config +$uploadMgr = new UploadManager($config); + +list($ret, $err) = $uploadMgr->putFile($uptoken, $key, $filePath); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/examples/upload_with_zone.php b/vendor/qiniu/php-sdk/examples/upload_with_zone.php new file mode 100644 index 0000000..6192666 --- /dev/null +++ b/vendor/qiniu/php-sdk/examples/upload_with_zone.php @@ -0,0 +1,39 @@ +uploadToken($bucket); + +// 上传文件的本地路径 +$filePath = './php-logo.png'; + +// 指定 zone 上传 +// 参考文档:https://developer.qiniu.com/kodo/manual/1671/region-endpoint +$zone = Zone::zonez0(); // 华东:z0,华北:z1,华南:z2,北美:na0,东南亚:as0 +$config = new Config($zone); +$config->useHTTPS = true; + +// 指定 config +$uploadMgr = new UploadManager($config); + +list($ret, $err) = $uploadMgr->putFile($uptoken, $key, $filePath); +echo "\n====> putFile result: \n"; +if ($err !== null) { + var_dump($err); +} else { + var_dump($ret); +} diff --git a/vendor/qiniu/php-sdk/phpunit.xml.dist b/vendor/qiniu/php-sdk/phpunit.xml.dist new file mode 100644 index 0000000..840f6e5 --- /dev/null +++ b/vendor/qiniu/php-sdk/phpunit.xml.dist @@ -0,0 +1,18 @@ + + + + + tests + + + + diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Auth.php b/vendor/qiniu/php-sdk/src/Qiniu/Auth.php new file mode 100644 index 0000000..6da2be4 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Auth.php @@ -0,0 +1,285 @@ +accessKey = $accessKey; + $this->secretKey = $secretKey; + $defaultOptions = array( + 'disableQiniuTimestampSignature' => null + ); + if ($options == null) { + $options = $defaultOptions; + } + $this->options = array_merge($defaultOptions, $options); + } + + public function getAccessKey() + { + return $this->accessKey; + } + + public function sign($data) + { + $hmac = hash_hmac('sha1', $data, $this->secretKey, true); + return $this->accessKey . ':' . \Qiniu\base64_urlSafeEncode($hmac); + } + + public function signWithData($data) + { + $encodedData = \Qiniu\base64_urlSafeEncode($data); + return $this->sign($encodedData) . ':' . $encodedData; + } + + public function signRequest($urlString, $body, $contentType = null) + { + $url = parse_url($urlString); + $data = ''; + if (array_key_exists('path', $url)) { + $data = $url['path']; + } + if (array_key_exists('query', $url)) { + $data .= '?' . $url['query']; + } + $data .= "\n"; + + if ($body !== null && $contentType === 'application/x-www-form-urlencoded') { + $data .= $body; + } + return $this->sign($data); + } + + /** + * @param string $urlString + * @param string $method + * @param string $body + * @param null|Header $headers + */ + public function signQiniuAuthorization($urlString, $method = "GET", $body = "", $headers = null) + { + $url = parse_url($urlString); + if (!$url) { + return array(null, new \Exception("parse_url error")); + } + + // append method, path and query + if ($method === "") { + $data = "GET "; + } else { + $data = $method . " "; + } + if (isset($url["path"])) { + $data .= $url["path"]; + } + if (isset($url["query"])) { + $data .= "?" . $url["query"]; + } + + // append Host + $data .= "\n"; + $data .= "Host: "; + if (isset($url["host"])) { + $data .= $url["host"]; + } + if (isset($url["port"]) && $url["port"] > 0) { + $data .= ":" . $url["port"]; + } + + // try to append content type + if ($headers != null && isset($headers["Content-Type"])) { + // append content type + $data .= "\n"; + $data .= "Content-Type: " . $headers["Content-Type"]; + } + + // try append xQiniuHeaders + if ($headers != null) { + $headerLines = array(); + $keyPrefix = "X-Qiniu-"; + foreach ($headers as $k => $v) { + if (strlen($k) > strlen($keyPrefix) && strpos($k, $keyPrefix) === 0) { + array_push( + $headerLines, + $k . ": " . $v + ); + } + } + if (count($headerLines) > 0) { + $data .= "\n"; + sort($headerLines); + $data .= implode("\n", $headerLines); + } + } + + // append body + $data .= "\n\n"; + if (!is_null($body) + && strlen($body) > 0 + && isset($headers["Content-Type"]) + && $headers["Content-Type"] != "application/octet-stream" + ) { + $data .= $body; + } + + return array($this->sign($data), null); + } + + public function verifyCallback( + $contentType, + $originAuthorization, + $url, + $body, + $method = "GET", + $headers = array() + ) { + if (strpos($originAuthorization, 'Qiniu') === 0) { + $qnHeaders = new Header($headers); + if (!isset($qnHeaders['Content-Type'])) { + $qnHeaders['Content-Type'] = $contentType; + } + list($sign, $err) = $this->signQiniuAuthorization( + $url, + $method, + $body, + $qnHeaders + ); + if ($err !== null) { + return false; + } + $authorization = 'Qiniu ' . $sign; + } else { + $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType); + } + return $originAuthorization === $authorization; + } + + public function privateDownloadUrl($baseUrl, $expires = 3600) + { + $deadline = time() + $expires; + + $pos = strpos($baseUrl, '?'); + if ($pos !== false) { + $baseUrl .= '&e='; + } else { + $baseUrl .= '?e='; + } + $baseUrl .= $deadline; + + $token = $this->sign($baseUrl); + return "$baseUrl&token=$token"; + } + + public function uploadToken($bucket, $key = null, $expires = 3600, $policy = null, $strictPolicy = true) + { + $deadline = time() + $expires; + $scope = $bucket; + if ($key !== null) { + $scope .= ':' . $key; + } + + $args = self::copyPolicy($args, $policy, $strictPolicy); + $args['scope'] = $scope; + $args['deadline'] = $deadline; + + $b = json_encode($args); + return $this->signWithData($b); + } + + /** + *上传策略,参数规格详见 + *http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html + */ + private static $policyFields = array( + 'callbackUrl', + 'callbackBody', + 'callbackHost', + 'callbackBodyType', + 'callbackFetchKey', + + 'returnUrl', + 'returnBody', + + 'endUser', + 'saveKey', + 'forceSaveKey', + 'insertOnly', + + 'detectMime', + 'mimeLimit', + 'fsizeMin', + 'fsizeLimit', + + 'persistentOps', // 与 persistentWorkflowTemplateID 二选一 + 'persistentNotifyUrl', + 'persistentPipeline', + 'persistentType', // 为 `1` 时开启闲时任务 + 'persistentWorkflowTemplateID', // 与 persistentOps 二选一 + + 'deleteAfterDays', + 'fileType', + 'isPrefixalScope', + + 'transform', // deprecated + 'transformFallbackKey', // deprecated + 'transformFallbackMode', // deprecated + ); + + private static function copyPolicy(&$policy, $originPolicy, $strictPolicy) + { + if ($originPolicy === null) { + return array(); + } + foreach ($originPolicy as $key => $value) { + if (!$strictPolicy || in_array((string)$key, self::$policyFields, true)) { + $policy[$key] = $value; + } + } + return $policy; + } + + public function authorization($url, $body = null, $contentType = null) + { + $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType); + return array('Authorization' => $authorization); + } + + public function authorizationV2($url, $method, $body = null, $contentType = null) + { + $headers = new Header(); + $result = array(); + if ($contentType != null) { + $headers['Content-Type'] = $contentType; + $result['Content-Type'] = $contentType; + } + + $signDate = gmdate('Ymd\THis\Z', time()); + if ($this->options['disableQiniuTimestampSignature'] !== null) { + if (!$this->options['disableQiniuTimestampSignature']) { + $headers['X-Qiniu-Date'] = $signDate; + $result['X-Qiniu-Date'] = $signDate; + } + } elseif (getenv("DISABLE_QINIU_TIMESTAMP_SIGNATURE")) { + if (strtolower(getenv("DISABLE_QINIU_TIMESTAMP_SIGNATURE")) !== "true") { + $headers['X-Qiniu-Date'] = $signDate; + $result['X-Qiniu-Date'] = $signDate; + } + } else { + $headers['X-Qiniu-Date'] = $signDate; + $result['X-Qiniu-Date'] = $signDate; + } + + list($sign) = $this->signQiniuAuthorization($url, $method, $body, $headers); + $result['Authorization'] = 'Qiniu ' . $sign; + return $result; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Cdn/CdnManager.php b/vendor/qiniu/php-sdk/src/Qiniu/Cdn/CdnManager.php new file mode 100644 index 0000000..60052d3 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Cdn/CdnManager.php @@ -0,0 +1,263 @@ +auth = $auth; + $this->server = 'http://fusion.qiniuapi.com'; + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + /** + * @param array $urls 待刷新的文件链接数组 + * @return array + */ + public function refreshUrls(array $urls) + { + return $this->refreshUrlsAndDirs($urls, array()); + } + + /** + * @param array $dirs 待刷新的文件链接数组 + * @return array + * 目前客户默认没有目录刷新权限,刷新会有400038报错,参考:https://developer.qiniu.com/fusion/api/1229/cache-refresh + * 需要刷新目录请工单联系技术支持 https://support.qiniu.com/tickets/category + */ + public function refreshDirs(array $dirs) + { + return $this->refreshUrlsAndDirs(array(), $dirs); + } + + /** + * @param array $urls 待刷新的文件链接数组 + * @param array $dirs 待刷新的目录链接数组 + * + * @return array 刷新的请求回复和错误,参考 examples/cdn_manager.php 代码 + * @link http://developer.qiniu.com/article/fusion/api/refresh.html + * + * 目前客户默认没有目录刷新权限,刷新会有400038报错,参考:https://developer.qiniu.com/fusion/api/1229/cache-refresh + * 需要刷新目录请工单联系技术支持 https://support.qiniu.com/tickets/category + */ + public function refreshUrlsAndDirs(array $urls, array $dirs) + { + $req = array(); + if (!empty($urls)) { + $req['urls'] = $urls; + } + if (!empty($dirs)) { + $req['dirs'] = $dirs; + } + + $url = $this->server . '/v2/tune/refresh'; + $body = json_encode($req); + return $this->post($url, $body); + } + + /** + * 查询 CDN 刷新记录 + * + * @param string $requestId 指定要查询记录所在的刷新请求id + * @param string $isDir 指定是否查询目录,取值为 yes/no,默认不填则为两种类型记录都查询 + * @param array $urls 要查询的url列表,每个url可以是文件url,也可以是目录url + * @param string $state 指定要查询记录的状态,取值processing/success/failure + * @param int $pageNo 要求返回的页号,默认为0 + * @param int $pageSize 要求返回的页长度,默认为100 + * @param string $startTime 指定查询的开始日期,格式2006-01-01 + * @param string $endTime 指定查询的结束日期,格式2006-01-01 + * @return array + * @link https://developer.qiniu.com/fusion/api/1229/cache-refresh#4 + */ + public function getCdnRefreshList( + $requestId = null, + $isDir = null, + $urls = array(), + $state = null, + $pageNo = 0, + $pageSize = 100, + $startTime = null, + $endTime = null + ) { + $req = array(); + \Qiniu\setWithoutEmpty($req, 'requestId', $requestId); + \Qiniu\setWithoutEmpty($req, 'isDir', $isDir); + \Qiniu\setWithoutEmpty($req, 'urls', $urls); + \Qiniu\setWithoutEmpty($req, 'state', $state); + \Qiniu\setWithoutEmpty($req, 'pageNo', $pageNo); + \Qiniu\setWithoutEmpty($req, 'pageSize', $pageSize); + \Qiniu\setWithoutEmpty($req, 'startTime', $startTime); + \Qiniu\setWithoutEmpty($req, 'endTime', $endTime); + + $body = json_encode($req); + $url = $this->server . '/v2/tune/refresh/list'; + return $this->post($url, $body); + } + + /** + * @param array $urls 待预取的文件链接数组 + * + * @return array 预取的请求回复和错误,参考 examples/cdn_manager.php 代码 + * + * @link http://developer.qiniu.com/article/fusion/api/refresh.html + */ + public function prefetchUrls(array $urls) + { + $req = array( + 'urls' => $urls, + ); + + $url = $this->server . '/v2/tune/prefetch'; + $body = json_encode($req); + return $this->post($url, $body); + } + + /** + * 查询 CDN 预取记录 + * + * @param string $requestId 指定要查询记录所在的刷新请求id + * @param array $urls 要查询的url列表,每个url可以是文件url,也可以是目录url + * @param string $state 指定要查询记录的状态,取值processing/success/failure + * @param int $pageNo 要求返回的页号,默认为0 + * @param int $pageSize 要求返回的页长度,默认为100 + * @param string $startTime 指定查询的开始日期,格式2006-01-01 + * @param string $endTime 指定查询的结束日期,格式2006-01-01 + * @return array + * @link https://developer.qiniu.com/fusion/api/1227/file-prefetching#4 + */ + public function getCdnPrefetchList( + $requestId = null, + $urls = array(), + $state = null, + $pageNo = 0, + $pageSize = 100, + $startTime = null, + $endTime = null + ) { + $req = array(); + \Qiniu\setWithoutEmpty($req, 'requestId', $requestId); + \Qiniu\setWithoutEmpty($req, 'urls', $urls); + \Qiniu\setWithoutEmpty($req, 'state', $state); + \Qiniu\setWithoutEmpty($req, 'pageNo', $pageNo); + \Qiniu\setWithoutEmpty($req, 'pageSize', $pageSize); + \Qiniu\setWithoutEmpty($req, 'startTime', $startTime); + \Qiniu\setWithoutEmpty($req, 'endTime', $endTime); + + $body = json_encode($req); + $url = $this->server . '/v2/tune/prefetch/list'; + return $this->post($url, $body); + } + + /** + * @param array $domains 待获取带宽数据的域名数组 + * @param string $startDate 开始的日期,格式类似 2017-01-01 + * @param string $endDate 结束的日期,格式类似 2017-01-01 + * @param string $granularity 获取数据的时间间隔,可以是 5min, hour 或者 day + * + * @return array 带宽数据和错误信息,参考 examples/cdn_manager.php 代码 + * + * @link http://developer.qiniu.com/article/fusion/api/traffic-bandwidth.html + */ + public function getBandwidthData(array $domains, $startDate, $endDate, $granularity) + { + $req = array(); + $req['domains'] = implode(';', $domains); + $req['startDate'] = $startDate; + $req['endDate'] = $endDate; + $req['granularity'] = $granularity; + + $url = $this->server . '/v2/tune/bandwidth'; + $body = json_encode($req); + return $this->post($url, $body); + } + + /** + * @param array $domains 待获取流量数据的域名数组 + * @param string $startDate 开始的日期,格式类似 2017-01-01 + * @param string $endDate 结束的日期,格式类似 2017-01-01 + * @param string $granularity 获取数据的时间间隔,可以是 5min, hour 或者 day + * + * @return array 流量数据和错误信息,参考 examples/cdn_manager.php 代码 + * + * @link http://developer.qiniu.com/article/fusion/api/traffic-bandwidth.html + */ + public function getFluxData(array $domains, $startDate, $endDate, $granularity) + { + $req = array(); + $req['domains'] = implode(';', $domains); + $req['startDate'] = $startDate; + $req['endDate'] = $endDate; + $req['granularity'] = $granularity; + + $url = $this->server . '/v2/tune/flux'; + $body = json_encode($req); + return $this->post($url, $body); + } + + /** + * @param array $domains 待获取日志下载链接的域名数组 + * @param string $logDate 获取指定日期的日志下载链接,格式类似 2017-01-01 + * + * @return array 日志下载链接数据和错误信息,参考 examples/cdn_manager.php 代码 + * + * @link http://developer.qiniu.com/article/fusion/api/log.html + */ + public function getCdnLogList(array $domains, $logDate) + { + $req = array(); + $req['domains'] = implode(';', $domains); + $req['day'] = $logDate; + + $url = $this->server . '/v2/tune/log/list'; + $body = json_encode($req); + return $this->post($url, $body); + } + + private function post($url, $body) + { + $headers = $this->auth->authorization($url, $body, 'application/json'); + $headers['Content-Type'] = 'application/json'; + $ret = Client::post($url, $body, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = ($ret->body === null) ? array() : $ret->json(); + return array($r, null); + } + + /** + * 构建时间戳防盗链鉴权的访问外链 + * + * @param string $rawUrl 需要签名的资源url + * @param string $encryptKey 时间戳防盗链密钥 + * @param string $durationInSeconds 链接的有效期(以秒为单位) + * + * @return string 带鉴权信息的资源外链,参考 examples/cdn_timestamp_antileech.php 代码 + */ + public static function createTimestampAntiLeechUrl($rawUrl, $encryptKey, $durationInSeconds) + { + $parsedUrl = parse_url($rawUrl); + $deadline = time() + $durationInSeconds; + $expireHex = dechex($deadline); + $path = isset($parsedUrl['path']) ? $parsedUrl['path'] : ''; + $strToSign = $encryptKey . $path . $expireHex; + $signStr = md5($strToSign); + if (isset($parsedUrl['query'])) { + $signedUrl = $rawUrl . '&sign=' . $signStr . '&t=' . $expireHex; + } else { + $signedUrl = $rawUrl . '?sign=' . $signStr . '&t=' . $expireHex; + } + return $signedUrl; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Config.php b/vendor/qiniu/php-sdk/src/Qiniu/Config.php new file mode 100644 index 0000000..3ce7fa5 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Config.php @@ -0,0 +1,398 @@ +zone = $z; + $this->useHTTPS = false; + $this->useCdnDomains = false; + $this->regionCache = array(); + $this->ucHost = Config::UC_HOST; + $this->queryRegionHost = Config::QUERY_REGION_HOST; + $this->backupQueryRegionHosts = array( + "kodo-config.qiniuapi.com", + "uc.qbox.me", + ); + $this->backupUcHostsRetryTimes = 2; + } + + public function setUcHost($ucHost) + { + $this->ucHost = $ucHost; + $this->setQueryRegionHost($ucHost); + } + + public function getUcHost() + { + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return $scheme . $this->ucHost; + } + + public function setQueryRegionHost($host, $backupHosts = array()) + { + $this->queryRegionHost = $host; + $this->backupQueryRegionHosts = $backupHosts; + } + + public function getQueryRegionHost() + { + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return $scheme . $this->queryRegionHost; + } + + public function setBackupQueryRegionHosts($hosts = array()) + { + $this->backupQueryRegionHosts = $hosts; + } + + public function getBackupQueryRegionHosts() + { + return $this->backupQueryRegionHosts; + } + + public function getUpHost($accessKey, $bucket, $reqOpt = null) + { + $region = $this->getRegion($accessKey, $bucket, $reqOpt); + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + $host = $region->srcUpHosts[0]; + if ($this->useCdnDomains === true) { + $host = $region->cdnUpHosts[0]; + } + + return $scheme . $host; + } + + public function getUpHostV2($accessKey, $bucket, $reqOpt = null) + { + list($region, $err) = $this->getRegionV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + $host = $region->srcUpHosts[0]; + if ($this->useCdnDomains === true) { + $host = $region->cdnUpHosts[0]; + } + + return array($scheme . $host, null); + } + + public function getUpBackupHost($accessKey, $bucket, $reqOpt = null) + { + $region = $this->getRegion($accessKey, $bucket, $reqOpt); + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + $host = $region->cdnUpHosts[0]; + if ($this->useCdnDomains === true) { + $host = $region->srcUpHosts[0]; + } + + return $scheme . $host; + } + + public function getUpBackupHostV2($accessKey, $bucket, $reqOpt = null) + { + list($region, $err) = $this->getRegionV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + $host = $region->cdnUpHosts[0]; + if ($this->useCdnDomains === true) { + $host = $region->srcUpHosts[0]; + } + + return array($scheme . $host, null); + } + + public function getRsHost($accessKey, $bucket, $reqOpt = null) + { + $region = $this->getRegion($accessKey, $bucket, $reqOpt); + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return $scheme . $region->rsHost; + } + + public function getRsHostV2($accessKey, $bucket, $reqOpt = null) + { + list($region, $err) = $this->getRegionV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return array($scheme . $region->rsHost, null); + } + + public function getRsfHost($accessKey, $bucket, $reqOpt = null) + { + $region = $this->getRegion($accessKey, $bucket, $reqOpt); + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return $scheme . $region->rsfHost; + } + + public function getRsfHostV2($accessKey, $bucket, $reqOpt = null) + { + list($region, $err) = $this->getRegionV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return array($scheme . $region->rsfHost, null); + } + + public function getIovipHost($accessKey, $bucket, $reqOpt = null) + { + $region = $this->getRegion($accessKey, $bucket, $reqOpt); + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return $scheme . $region->iovipHost; + } + + public function getIovipHostV2($accessKey, $bucket, $reqOpt = null) + { + list($region, $err) = $this->getRegionV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return array($scheme . $region->iovipHost, null); + } + + public function getApiHost($accessKey, $bucket, $reqOpt = null) + { + $region = $this->getRegion($accessKey, $bucket, $reqOpt); + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return $scheme . $region->apiHost; + } + + public function getApiHostV2($accessKey, $bucket, $reqOpt = null) + { + list($region, $err) = $this->getRegionV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + if ($this->useHTTPS === true) { + $scheme = "https://"; + } else { + $scheme = "http://"; + } + + return array($scheme . $region->apiHost, null); + } + + + /** + * 从缓存中获取区域 + * + * @param string $cacheId 缓存 ID + * @return null|Region + */ + private function getRegionCache($cacheId) + { + if (isset($this->regionCache[$cacheId]) && + isset($this->regionCache[$cacheId]["deadline"]) && + time() < $this->regionCache[$cacheId]["deadline"]) { + return $this->regionCache[$cacheId]["region"]; + } + + return null; + } + + /** + * 将区域设置到缓存中 + * + * @param string $cacheId 缓存 ID + * @param Region $region 缓存 ID + * @return void + */ + private function setRegionCache($cacheId, $region) + { + $this->regionCache[$cacheId] = array( + "region" => $region, + ); + if (isset($region->ttl)) { + $this->regionCache[$cacheId]["deadline"] = time() + $region->ttl; + } + } + + /** + * 从缓存中获取区域 + * + * @param string $accessKey + * @param string $bucket + * @return Region + * + * @throws \Exception + */ + private function getRegion($accessKey, $bucket, $reqOpt = null) + { + if (isset($this->zone)) { + return $this->zone; + } + + $cacheId = "$accessKey:$bucket"; + $regionCache = $this->getRegionCache($cacheId); + if ($regionCache) { + return $regionCache; + } + + $region = Zone::queryZone( + $accessKey, + $bucket, + $this->getQueryRegionHost(), + $this->getBackupQueryRegionHosts(), + $this->backupUcHostsRetryTimes, + $reqOpt + ); + if (is_array($region)) { + list($region, $err) = $region; + if ($err != null) { + throw new \Exception($err->message()); + } + } + + $this->setRegionCache($cacheId, $region); + return $region; + } + + private function getRegionV2($accessKey, $bucket, $reqOpt = null) + { + if (isset($this->zone)) { + return array($this->zone, null); + } + + $cacheId = "$accessKey:$bucket"; + $regionCache = $this->getRegionCache($cacheId); + if (isset($regionCache)) { + return array($regionCache, null); + } + + $region = Zone::queryZone( + $accessKey, + $bucket, + $this->getQueryRegionHost(), + $this->getBackupQueryRegionHosts(), + $this->backupUcHostsRetryTimes, + $reqOpt + ); + if (is_array($region)) { + list($region, $err) = $region; + return array($region, $err); + } + + $this->setRegionCache($cacheId, $region); + return array($region, null); + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Enum/QiniuEnum.php b/vendor/qiniu/php-sdk/src/Qiniu/Enum/QiniuEnum.php new file mode 100644 index 0000000..8399b54 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Enum/QiniuEnum.php @@ -0,0 +1,53 @@ + $val) { + array_push($data, '--' . $mimeBoundary); + array_push($data, "Content-Disposition: form-data; name=\"$key\""); + array_push($data, ''); + array_push($data, $val); + } + + array_push($data, '--' . $mimeBoundary); + $finalMimeType = empty($mimeType) ? 'application/octet-stream' : $mimeType; + $finalFileName = self::escapeQuotes($fileName); + array_push($data, "Content-Disposition: form-data; name=\"$name\"; filename=\"$finalFileName\""); + array_push($data, "Content-Type: $finalMimeType"); + array_push($data, ''); + array_push($data, $fileBody); + + array_push($data, '--' . $mimeBoundary . '--'); + array_push($data, ''); + + $body = implode("\r\n", $data); + $contentType = 'multipart/form-data; boundary=' . $mimeBoundary; + $headers['Content-Type'] = $contentType; + $request = new Request('POST', $url, $headers, $body, $opt); + return self::sendRequest($request); + } + + private static function userAgent() + { + $sdkInfo = "QiniuPHP/" . Config::SDK_VER; + + $systemInfo = php_uname("s"); + $machineInfo = php_uname("m"); + + $envInfo = "($systemInfo/$machineInfo)"; + + $phpVer = phpversion(); + + $ua = "$sdkInfo $envInfo PHP/$phpVer"; + return $ua; + } + + /** + * @param Request $request + * @return Response + */ + public static function sendRequestWithMiddleware($request) + { + $middlewares = $request->opt->middlewares; + $handle = Middleware\compose($middlewares, function ($req) { + return Client::sendRequest($req); + }); + return $handle($request); + } + + /** + * @param Request $request + * @return Response + */ + public static function sendRequest($request) + { + $t1 = microtime(true); + $ch = curl_init(); + $options = array( + CURLOPT_USERAGENT => self::userAgent(), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_NOBODY => false, + CURLOPT_CUSTOMREQUEST => $request->method, + CURLOPT_URL => $request->url, + ); + foreach ($request->opt->getCurlOpt() as $k => $v) { + $options[$k] = $v; + } + // Handle open_basedir & safe mode + if (!ini_get('safe_mode') && !ini_get('open_basedir')) { + $options[CURLOPT_FOLLOWLOCATION] = true; + } + if (!empty($request->headers)) { + $headers = array(); + foreach ($request->headers as $key => $val) { + array_push($headers, "$key: $val"); + } + $options[CURLOPT_HTTPHEADER] = $headers; + } + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); + if (!empty($request->body)) { + $options[CURLOPT_POSTFIELDS] = $request->body; + } + curl_setopt_array($ch, $options); + $result = curl_exec($ch); + $t2 = microtime(true); + $duration = round($t2 - $t1, 3); + $ret = curl_errno($ch); + if ($ret !== 0) { + $r = new Response(-1, $duration, array(), null, curl_error($ch)); + curl_close($ch); + return $r; + } + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $headers = Header::parseRawText(substr($result, 0, $header_size)); + $body = substr($result, $header_size); + curl_close($ch); + return new Response($code, $duration, $headers, $body, null); + } + + private static function escapeQuotes($str) + { + if (is_null($str)) { + return null; + } + $find = array("\\", "\""); + $replace = array("\\\\", "\\\""); + return str_replace($find, $replace, $str); + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Http/Error.php b/vendor/qiniu/php-sdk/src/Qiniu/Http/Error.php new file mode 100644 index 0000000..8fba74f --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Http/Error.php @@ -0,0 +1,38 @@ + + * {"error" : "detailed error message"} + * + */ +final class Error +{ + private $url; + /** + * @var Response + */ + private $response; + + public function __construct($url, $response) + { + $this->url = $url; + $this->response = $response; + } + + public function code() + { + return $this->response->statusCode; + } + + public function getResponse() + { + return $this->response; + } + + public function message() + { + return $this->response->error; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Http/Header.php b/vendor/qiniu/php-sdk/src/Qiniu/Http/Header.php new file mode 100644 index 0000000..1dcf328 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Http/Header.php @@ -0,0 +1,291 @@ + $values) { + $normalizedKey = self::normalizeKey($key); + $normalizedValues = array(); + if (!is_array($values)) { + array_push( + $normalizedValues, + self::normalizeValue($values) + ); + } else { + foreach ($values as $value) { + array_push( + $normalizedValues, + self::normalizeValue($value) + ); + } + } + $this->data[$normalizedKey] = $normalizedValues; + } + return $this; + } + + /** + * return origin headers, which is field name case-sensitive + * + * @param string $raw + * + * @return array + */ + public static function parseRawText($raw) + { + $multipleHeaders = explode("\r\n\r\n", trim($raw)); + $headers = array(); + $headerLines = explode("\r\n", end($multipleHeaders)); + foreach ($headerLines as $line) { + $headerLine = trim($line); + $kv = explode(':', $headerLine); + if (count($kv) <= 1) { + continue; + } + // for http2 [Pseudo-Header Fields](https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.1) + if ($kv[0] == "") { + $fieldName = ":" . $kv[1]; + } else { + $fieldName = $kv[0]; + } + $fieldValue = trim(substr($headerLine, strlen($fieldName . ":"))); + if (isset($headers[$fieldName])) { + array_push($headers[$fieldName], $fieldValue); + } else { + $headers[$fieldName] = array($fieldValue); + } + } + return $headers; + } + + /** + * @param string $raw + * + * @return Header + */ + public static function fromRawText($raw) + { + return new Header(self::parseRawText($raw)); + } + + /** + * @param string $key + * + * @return string + */ + public static function normalizeKey($key) + { + $key = trim($key); + + if (!self::isValidKeyName($key)) { + return $key; + } + + return \Qiniu\ucwords(strtolower($key), '-'); + } + + /** + * @param string|numeric $value + * + * @return string|numeric + */ + public static function normalizeValue($value) + { + if (is_numeric($value)) { + return $value + 0; + } + return trim($value); + } + + /** + * @return array + */ + public function getRawData() + { + return $this->data; + } + + /** + * @param $offset string + * + * @return boolean + */ + #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x + public function offsetExists($offset) + { + $key = self::normalizeKey($offset); + return isset($this->data[$key]); + } + + /** + * @param $offset string + * + * @return string|null + */ + #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x + public function offsetGet($offset) + { + $key = self::normalizeKey($offset); + if (isset($this->data[$key]) && count($this->data[$key])) { + return $this->data[$key][0]; + } else { + return null; + } + } + + /** + * @param $offset string + * @param $value string + * + * @return void + */ + #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x + public function offsetSet($offset, $value) + { + $key = self::normalizeKey($offset); + if (isset($this->data[$key]) && count($this->data[$key]) > 0) { + $this->data[$key][0] = self::normalizeValue($value); + } else { + $this->data[$key] = array(self::normalizeValue($value)); + } + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x + public function offsetUnset($offset) + { + $key = self::normalizeKey($offset); + unset($this->data[$key]); + } + + /** + * @return \ArrayIterator + */ + #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x + public function getIterator() + { + $arr = array(); + foreach ($this->data as $k => $v) { + $arr[$k] = $v[0]; + } + return new \ArrayIterator($arr); + } + + /** + * @return int + */ + #[\ReturnTypeWillChange] // temporarily suppress the type check of php 8.x + public function count() + { + return count($this->data); + } + + private static $isTokenTable = array( + '!' => true, + '#' => true, + '$' => true, + '%' => true, + '&' => true, + '\'' => true, + '*' => true, + '+' => true, + '-' => true, + '.' => true, + '0' => true, + '1' => true, + '2' => true, + '3' => true, + '4' => true, + '5' => true, + '6' => true, + '7' => true, + '8' => true, + '9' => true, + 'A' => true, + 'B' => true, + 'C' => true, + 'D' => true, + 'E' => true, + 'F' => true, + 'G' => true, + 'H' => true, + 'I' => true, + 'J' => true, + 'K' => true, + 'L' => true, + 'M' => true, + 'N' => true, + 'O' => true, + 'P' => true, + 'Q' => true, + 'R' => true, + 'S' => true, + 'T' => true, + 'U' => true, + 'W' => true, + 'V' => true, + 'X' => true, + 'Y' => true, + 'Z' => true, + '^' => true, + '_' => true, + '`' => true, + 'a' => true, + 'b' => true, + 'c' => true, + 'd' => true, + 'e' => true, + 'f' => true, + 'g' => true, + 'h' => true, + 'i' => true, + 'j' => true, + 'k' => true, + 'l' => true, + 'm' => true, + 'n' => true, + 'o' => true, + 'p' => true, + 'q' => true, + 'r' => true, + 's' => true, + 't' => true, + 'u' => true, + 'v' => true, + 'w' => true, + 'x' => true, + 'y' => true, + 'z' => true, + '|' => true, + '~' => true, + ); + + /** + * @param string $str + * + * @return boolean + */ + private static function isValidKeyName($str) + { + for ($i = 0; $i < strlen($str); $i += 1) { + if (!isset(self::$isTokenTable[$str[$i]])) { + return false; + } + } + return true; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Http/Middleware/Middleware.php b/vendor/qiniu/php-sdk/src/Qiniu/Http/Middleware/Middleware.php new file mode 100644 index 0000000..fe8a64c --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Http/Middleware/Middleware.php @@ -0,0 +1,31 @@ + $middlewares + * @param callable(Request): Response $handler + * @return callable(Request): Response + */ +function compose($middlewares, $handler) +{ + $next = $handler; + foreach (array_reverse($middlewares) as $middleware) { + $next = function ($request) use ($middleware, $next) { + return $middleware->send($request, $next); + }; + } + return $next; +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Http/Middleware/RetryDomainsMiddleware.php b/vendor/qiniu/php-sdk/src/Qiniu/Http/Middleware/RetryDomainsMiddleware.php new file mode 100644 index 0000000..829ab87 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Http/Middleware/RetryDomainsMiddleware.php @@ -0,0 +1,76 @@ + backup domains. + */ + private $backupDomains; + + /** + * @var numeric max retry times for each backup domains. + */ + private $maxRetryTimes; + + /** + * @var callable args response and request; returns bool; If true will retry with backup domains. + */ + private $retryCondition; + + /** + * @param array $backupDomains + * @param numeric $maxRetryTimes + */ + public function __construct($backupDomains, $maxRetryTimes = 2, $retryCondition = null) + { + $this->backupDomains = $backupDomains; + $this->maxRetryTimes = $maxRetryTimes; + $this->retryCondition = $retryCondition; + } + + private function shouldRetry($resp, $req) + { + if (is_callable($this->retryCondition)) { + return call_user_func($this->retryCondition, $resp, $req); + } + + return !$resp || $resp->needRetry(); + } + + /** + * @param Request $request + * @param callable(Request): Response $next + * @return Response + */ + public function send($request, $next) + { + $response = null; + $urlComponents = parse_url($request->url); + + foreach (array_merge(array($urlComponents["host"]), $this->backupDomains) as $backupDomain) { + $urlComponents["host"] = $backupDomain; + $request->url = \Qiniu\unparse_url($urlComponents); + $retriedTimes = 0; + + while ($retriedTimes < $this->maxRetryTimes) { + $response = $next($request); + + $retriedTimes += 1; + + if (!$this->shouldRetry($response, $request)) { + return $response; + } + } + } + + if (!$response) { + $response = $next($request); + } + + return $response; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Http/Proxy.php b/vendor/qiniu/php-sdk/src/Qiniu/Http/Proxy.php new file mode 100644 index 0000000..fac6ba1 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Http/Proxy.php @@ -0,0 +1,34 @@ +proxy = $proxy; + $this->proxy_auth = $proxy_auth; + $this->proxy_user_password = $proxy_user_password; + } + + public function makeReqOpt() + { + $reqOpt = new RequestOptions(); + if ($this->proxy !== null) { + $reqOpt->proxy = $this->proxy; + } + if ($this->proxy_auth !== null) { + $reqOpt->proxy_auth = $this->proxy_auth; + } + if ($this->proxy_user_password !== null) { + $reqOpt->proxy_user_password = $this->proxy_user_password; + } + return $reqOpt; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Http/Request.php b/vendor/qiniu/php-sdk/src/Qiniu/Http/Request.php new file mode 100644 index 0000000..5a31bf6 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Http/Request.php @@ -0,0 +1,42 @@ + + */ + public $headers; + + /** + * @var mixed|null + */ + public $body; + + /** + * @var string + */ + public $method; + + /** + * @var RequestOptions + */ + public $opt; + + public function __construct($method, $url, array $headers = array(), $body = null, $opt = null) + { + $this->method = strtoupper($method); + $this->url = $url; + $this->headers = $headers; + $this->body = $body; + if ($opt === null) { + $opt = new RequestOptions(); + } + $this->opt = $opt; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Http/RequestOptions.php b/vendor/qiniu/php-sdk/src/Qiniu/Http/RequestOptions.php new file mode 100644 index 0000000..be0c6d5 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Http/RequestOptions.php @@ -0,0 +1,104 @@ + + */ + public $middlewares; + + public function __construct( + $connection_timeout = null, + $connection_timeout_ms = null, + $timeout = null, + $timeout_ms = null, + $middlewares = array(), + $proxy = null, + $proxy_auth = null, + $proxy_user_password = null + ) { + $this->connection_timeout = $connection_timeout; + $this->connection_timeout_ms = $connection_timeout_ms; + $this->timeout = $timeout; + $this->timeout_ms = $timeout_ms; + $this->proxy = $proxy; + $this->proxy_auth = $proxy_auth; + $this->proxy_user_password = $proxy_user_password; + $this->middlewares = $middlewares; + } + + public function getCurlOpt() + { + $result = array(); + if ($this->connection_timeout != null) { + $result[CURLOPT_CONNECTTIMEOUT] = $this->connection_timeout; + } + if ($this->connection_timeout_ms != null) { + $result[CURLOPT_CONNECTTIMEOUT_MS] = $this->connection_timeout_ms; + } + if ($this->timeout != null) { + $result[CURLOPT_TIMEOUT] = $this->timeout; + } + if ($this->timeout_ms != null) { + $result[CURLOPT_TIMEOUT_MS] = $this->timeout_ms; + } + if ($this->proxy != null) { + $result[CURLOPT_PROXY] = $this->proxy; + } + if ($this->proxy_auth != null) { + $result[CURLOPT_PROXYAUTH] = $this->proxy_auth; + } + if ($this->proxy_user_password != null) { + $result[CURLOPT_PROXYUSERPWD] = $this->proxy_user_password; + } + return $result; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Http/Response.php b/vendor/qiniu/php-sdk/src/Qiniu/Http/Response.php new file mode 100644 index 0000000..cd77903 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Http/Response.php @@ -0,0 +1,220 @@ + 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-Status', + 208 => 'Already Reported', + 226 => 'IM Used', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 307 => 'Temporary Redirect', + 308 => 'Permanent Redirect', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 422 => 'Unprocessable Entity', + 423 => 'Locked', + 424 => 'Failed Dependency', + 425 => 'Reserved for WebDAV advanced collections expired proposal', + 426 => 'Upgrade required', + 428 => 'Precondition Required', + 429 => 'Too Many Requests', + 431 => 'Request Header Fields Too Large', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates (Experimental)', + 507 => 'Insufficient Storage', + 508 => 'Loop Detected', + 510 => 'Not Extended', + 511 => 'Network Authentication Required', + ); + + /** + * @param int $code 状态码 + * @param double $duration 请求时长 + * @param array $headers 响应头部 + * @param string $body 响应内容 + * @param string $error 错误描述 + */ + public function __construct($code, $duration, array $headers = array(), $body = null, $error = null) + { + $this->statusCode = $code; + $this->duration = $duration; + $this->headers = array(); + $this->body = $body; + $this->error = $error; + $this->jsonData = null; + + if ($error !== null) { + return; + } + + foreach ($headers as $k => $vs) { + if (is_array($vs)) { + $this->headers[$k] = $vs[count($vs) - 1]; + } else { + $this->headers[$k] = $vs; + } + } + $this->normalizedHeaders = new Header($headers); + + if ($body === null) { + if ($code >= 400) { + $this->error = self::$statusTexts[$code]; + } + return; + } + if (self::isJson($this->normalizedHeaders)) { + try { + $jsonData = self::bodyJson($body); + if ($code >= 400) { + $this->error = $body; + if ($jsonData['error'] !== null) { + $this->error = $jsonData['error']; + } + } + $this->jsonData = $jsonData; + } catch (\InvalidArgumentException $e) { + $this->error = $body; + if ($code >= 200 && $code < 300) { + $this->error = $e->getMessage(); + } + } + } elseif ($code >= 400) { + $this->error = $body; + } + return; + } + + public function json() + { + return $this->jsonData; + } + + public function headers($normalized = false) + { + if ($normalized) { + return $this->normalizedHeaders; + } + return $this->headers; + } + + public function body() + { + return $this->body; + } + + private static function bodyJson($body) + { + return \Qiniu\json_decode((string) $body, true, 512); + } + + public function xVia() + { + $via = $this->normalizedHeaders['X-Via']; + if ($via === null) { + $via = $this->normalizedHeaders['X-Px']; + } + if ($via === null) { + $via = $this->normalizedHeaders['Fw-Via']; + } + return $via; + } + + public function xLog() + { + return $this->normalizedHeaders['X-Log']; + } + + public function xReqId() + { + return $this->normalizedHeaders['X-Reqid']; + } + + public function ok() + { + return $this->statusCode >= 200 && $this->statusCode < 300 && $this->error === null; + } + + public function needRetry() + { + if ($this->statusCode > 0 && $this->statusCode < 500) { + return false; + } + + // https://developer.qiniu.com/fusion/kb/1352/the-http-request-return-a-status-code + if (in_array($this->statusCode, array( + 501, 509, 573, 579, 608, 612, 614, 616, 618, 630, 631, 632, 640, 701 + ))) { + return false; + } + + return true; + } + + private static function isJson($headers) + { + return isset($headers['Content-Type']) && strpos($headers['Content-Type'], 'application/json') === 0; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Processing/ImageUrlBuilder.php b/vendor/qiniu/php-sdk/src/Qiniu/Processing/ImageUrlBuilder.php new file mode 100644 index 0000000..f5575ed --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Processing/ImageUrlBuilder.php @@ -0,0 +1,292 @@ + + */ + public function thumbnail( + $url, + $mode, + $width, + $height, + $format = null, + $interlace = null, + $quality = null, + $ignoreError = 1 + ) { + + // url合法效验 + if (!$this->isUrl($url)) { + return $url; + } + + // 参数合法性效验 + if (!in_array(intval($mode), $this->modeArr, true)) { + return $url; + } + + if (!$width || !$height) { + return $url; + } + + $thumbStr = 'imageView2/' . $mode . '/w/' . $width . '/h/' . $height . '/'; + + // 拼接输出格式 + if (!is_null($format) + && in_array($format, $this->formatArr) + ) { + $thumbStr .= 'format/' . $format . '/'; + } + + // 拼接渐进显示 + if (!is_null($interlace) + && in_array(intval($interlace), array(0, 1), true) + ) { + $thumbStr .= 'interlace/' . $interlace . '/'; + } + + // 拼接图片质量 + if (!is_null($quality) + && intval($quality) >= 0 + && intval($quality) <= 100 + ) { + $thumbStr .= 'q/' . $quality . '/'; + } + + $thumbStr .= 'ignore-error/' . $ignoreError . '/'; + + // 如果有query_string用|线分割实现多参数 + return $url . ($this->hasQuery($url) ? '|' : '?') . $thumbStr; + } + + /** + * 图片水印 + * + * @param string $url 图片链接 + * @param string $image 水印图片链接 + * @param int $dissolve 透明度 + * @param string $gravity 水印位置 + * @param int $dx 横轴边距 + * @param int $dy 纵轴边距 + * @param int $watermarkScale 自适应原图的短边比例 + * @return string + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html + * @author Sherlock Ren + */ + public function waterImg( + $url, + $image, + $dissolve = 100, + $gravity = 'SouthEast', + $dx = null, + $dy = null, + $watermarkScale = null + ) { + // url合法效验 + if (!$this->isUrl($url)) { + return $url; + } + + $waterStr = 'watermark/1/image/' . \Qiniu\base64_urlSafeEncode($image) . '/'; + + // 拼接水印透明度 + if (is_numeric($dissolve) + && $dissolve <= 100 + ) { + $waterStr .= 'dissolve/' . $dissolve . '/'; + } + + // 拼接水印位置 + if (in_array($gravity, $this->gravityArr, true)) { + $waterStr .= 'gravity/' . $gravity . '/'; + } + + // 拼接横轴边距 + if (!is_null($dx) + && is_numeric($dx) + ) { + $waterStr .= 'dx/' . $dx . '/'; + } + + // 拼接纵轴边距 + if (!is_null($dy) + && is_numeric($dy) + ) { + $waterStr .= 'dy/' . $dy . '/'; + } + + // 拼接自适应原图的短边比例 + if (!is_null($watermarkScale) + && is_numeric($watermarkScale) + && $watermarkScale > 0 + && $watermarkScale < 1 + ) { + $waterStr .= 'ws/' . $watermarkScale . '/'; + } + + // 如果有query_string用|线分割实现多参数 + return $url . ($this->hasQuery($url) ? '|' : '?') . $waterStr; + } + + /** + * 文字水印 + * + * @param string $url 图片链接 + * @param string $text 文字 + * @param string $font 文字字体 + * @param string $fontSize 文字字号 + * @param string $fontColor 文字颜色 + * @param int $dissolve 透明度 + * @param string $gravity 水印位置 + * @param int $dx 横轴边距 + * @param int $dy 纵轴边距 + * @return string + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html#text-watermark + * @author Sherlock Ren + */ + public function waterText( + $url, + $text, + $font = '黑体', + $fontSize = 0, + $fontColor = null, + $dissolve = 100, + $gravity = 'SouthEast', + $dx = null, + $dy = null + ) { + // url合法效验 + if (!$this->isUrl($url)) { + return $url; + } + + $waterStr = 'watermark/2/text/' + . \Qiniu\base64_urlSafeEncode($text) . '/font/' + . \Qiniu\base64_urlSafeEncode($font) . '/'; + + // 拼接文字大小 + if (is_int($fontSize)) { + $waterStr .= 'fontsize/' . $fontSize . '/'; + } + + // 拼接文字颜色 + if (!is_null($fontColor) + && $fontColor + ) { + $waterStr .= 'fill/' . \Qiniu\base64_urlSafeEncode($fontColor) . '/'; + } + + // 拼接水印透明度 + if (is_numeric($dissolve) + && $dissolve <= 100 + ) { + $waterStr .= 'dissolve/' . $dissolve . '/'; + } + + // 拼接水印位置 + if (in_array($gravity, $this->gravityArr, true)) { + $waterStr .= 'gravity/' . $gravity . '/'; + } + + // 拼接横轴边距 + if (!is_null($dx) + && is_numeric($dx) + ) { + $waterStr .= 'dx/' . $dx . '/'; + } + + // 拼接纵轴边距 + if (!is_null($dy) + && is_numeric($dy) + ) { + $waterStr .= 'dy/' . $dy . '/'; + } + + // 如果有query_string用|线分割实现多参数 + return $url . ($this->hasQuery($url) ? '|' : '?') . $waterStr; + } + + /** + * 效验url合法性 + * + * @param string $url url链接 + * @return string + * @author Sherlock Ren + */ + protected function isUrl($url) + { + $urlArr = parse_url($url); + + return $urlArr['scheme'] + && in_array($urlArr['scheme'], array('http', 'https')) + && $urlArr['host'] + && $urlArr['path']; + } + + /** + * 检测是否有query + * + * @param string $url url链接 + * @return string + * @author Sherlock Ren + */ + protected function hasQuery($url) + { + $urlArr = parse_url($url); + + return !empty($urlArr['query']); + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Processing/Operation.php b/vendor/qiniu/php-sdk/src/Qiniu/Processing/Operation.php new file mode 100644 index 0000000..839703c --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Processing/Operation.php @@ -0,0 +1,69 @@ +auth = $auth; + $this->domain = $domain; + $this->token_expire = $token_expire; + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + + /** + * 对资源文件进行处理 + * + * @param string $key 待处理的资源文件名 + * @param string $fops string|array fop操作,多次fop操作以array的形式传入。 + * eg. imageView2/1/w/200/h/200, imageMogr2/thumbnail/!75px + * + * @return array 文件处理后的结果及错误。 + * + * @link http://developer.qiniu.com/docs/v6/api/reference/fop/ + */ + public function execute($key, $fops) + { + $url = $this->buildUrl($key, $fops); + $resp = Client::get($url, array(), $this->proxy->makeReqOpt()); + if (!$resp->ok()) { + return array(null, new Error($url, $resp)); + } + if ($resp->json() !== null) { + return array($resp->json(), null); + } + return array($resp->body, null); + } + + public function buildUrl($key, $fops, $protocol = 'http') + { + if (is_array($fops)) { + $fops = implode('|', $fops); + } + + $url = $protocol . "://$this->domain/$key?$fops"; + if ($this->auth !== null) { + $url = $this->auth->privateDownloadUrl($url, $this->token_expire); + } + + return $url; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Processing/PersistentFop.php b/vendor/qiniu/php-sdk/src/Qiniu/Processing/PersistentFop.php new file mode 100644 index 0000000..8dca4a9 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Processing/PersistentFop.php @@ -0,0 +1,135 @@ +auth = $auth; + if ($config == null) { + $this->config = new Config(); + } else { + $this->config = $config; + } + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + /** + * 对资源文件进行异步持久化处理 + * @param string $bucket 资源所在空间 + * @param string $key 待处理的源文件 + * @param string|array $fops 待处理的pfop操作,多个pfop操作以array的形式传入。 + * eg. avthumb/mp3/ab/192k, vframe/jpg/offset/7/w/480/h/360 + * @param string $pipeline 资源处理队列 + * @param string $notify_url 处理结果通知地址 + * @param bool $force 是否强制执行一次新的指令 + * @param int $type 为 `1` 时开启闲时任务 + * + * + * @return array 返回持久化处理的 persistentId 与可能出现的错误。 + * + * @link http://developer.qiniu.com/docs/v6/api/reference/fop/ + */ + public function execute( + $bucket, + $key, + $fops = null, + $pipeline = null, + $notify_url = null, + $force = false, + $type = null, + $workflow_template_id = null + ) { + if (is_array($fops)) { + $fops = implode(';', $fops); + } + + if (!$fops && !$workflow_template_id) { + throw new \InvalidArgumentException('Must provide one of fops or template_id'); + } + + $params = array('bucket' => $bucket, 'key' => $key); + \Qiniu\setWithoutEmpty($params, 'fops', $fops); + \Qiniu\setWithoutEmpty($params, 'pipeline', $pipeline); + \Qiniu\setWithoutEmpty($params, 'notifyURL', $notify_url); + \Qiniu\setWithoutEmpty($params, 'type', $type); + \Qiniu\setWithoutEmpty($params, 'workflowTemplateID', $workflow_template_id); + if ($force) { + $params['force'] = 1; + } + $data = http_build_query($params); + $scheme = "http://"; + if ($this->config->useHTTPS === true) { + $scheme = "https://"; + } + $apiHost = $this->getApiHost(); + $url = $scheme . $apiHost . '/pfop/'; + $headers = $this->auth->authorization($url, $data, 'application/x-www-form-urlencoded'); + $headers['Content-Type'] = 'application/x-www-form-urlencoded'; + $response = Client::post($url, $data, $headers, $this->proxy->makeReqOpt()); + if (!$response->ok()) { + return array(null, new Error($url, $response)); + } + $r = $response->json(); + $id = $r['persistentId']; + return array($id, null); + } + + /** + * @param string $id + * @return array 返回任务状态与可能出现的错误 + */ + public function status($id) + { + $scheme = "http://"; + + if ($this->config->useHTTPS === true) { + $scheme = "https://"; + } + $apiHost = $this->getApiHost(); + $url = $scheme . $apiHost . "/status/get/prefop?id=$id"; + $response = Client::get($url, array(), $this->proxy->makeReqOpt()); + if (!$response->ok()) { + return array(null, new Error($url, $response)); + } + return array($response->json(), null); + } + + private function getApiHost() + { + if (!empty($this->config->zone) && !empty($this->config->zone->apiHost)) { + $apiHost = $this->config->zone->apiHost; + } else { + $apiHost = Config::API_HOST; + } + return $apiHost; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Region.php b/vendor/qiniu/php-sdk/src/Qiniu/Region.php new file mode 100644 index 0000000..220a5a3 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Region.php @@ -0,0 +1,229 @@ +srcUpHosts = $srcUpHosts; + $this->cdnUpHosts = $cdnUpHosts; + $this->rsHost = $rsHost; + $this->rsfHost = $rsfHost; + $this->apiHost = $apiHost; + $this->iovipHost = $iovipHost; + $this->ttl = $ttl; + } + + //华东机房 + public static function regionHuadong() + { + $regionHuadong = new Region( + array("up.qiniup.com"), + array('upload.qiniup.com'), + 'rs-z0.qiniuapi.com', + 'rsf-z0.qiniuapi.com', + 'api.qiniuapi.com', + 'iovip.qbox.me' + ); + return $regionHuadong; + } + + //华东机房内网上传 + public static function qvmRegionHuadong() + { + $qvmRegionHuadong = new Region( + array("free-qvm-z0-xs.qiniup.com"), + 'rs-z0.qiniuapi.com', + 'rsf-z0.qiniuapi.com', + 'api.qiniuapi.com', + 'iovip.qbox.me' + ); + return $qvmRegionHuadong; + } + + //华北机房内网上传 + public static function qvmRegionHuabei() + { + $qvmRegionHuabei = new Region( + array("free-qvm-z1-zz.qiniup.com"), + "rs-z1.qiniuapi.com", + "rsf-z1.qiniuapi.com", + "api-z1.qiniuapi.com", + "iovip-z1.qbox.me" + ); + return $qvmRegionHuabei; + } + + //华北机房 + public static function regionHuabei() + { + $regionHuabei = new Region( + array('up-z1.qiniup.com'), + array('upload-z1.qiniup.com'), + "rs-z1.qiniuapi.com", + "rsf-z1.qiniuapi.com", + "api-z1.qiniuapi.com", + "iovip-z1.qbox.me" + ); + + return $regionHuabei; + } + + //华南机房 + public static function regionHuanan() + { + $regionHuanan = new Region( + array('up-z2.qiniup.com'), + array('upload-z2.qiniup.com'), + "rs-z2.qiniuapi.com", + "rsf-z2.qiniuapi.com", + "api-z2.qiniuapi.com", + "iovip-z2.qbox.me" + ); + return $regionHuanan; + } + + //华东2 机房 + public static function regionHuadong2() + { + return new Region( + array('up-cn-east-2.qiniup.com'), + array('upload-cn-east-2.qiniup.com'), + "rs-cn-east-2.qiniuapi.com", + "rsf-cn-east-2.qiniuapi.com", + "api-cn-east-2.qiniuapi.com", + "iovip-cn-east-2.qiniuio.com" + ); + } + + //北美机房 + public static function regionNorthAmerica() + { + //北美机房 + $regionNorthAmerica = new Region( + array('up-na0.qiniup.com'), + array('upload-na0.qiniup.com'), + "rs-na0.qiniuapi.com", + "rsf-na0.qiniuapi.com", + "api-na0.qiniuapi.com", + "iovip-na0.qbox.me" + ); + return $regionNorthAmerica; + } + + //新加坡机房 + public static function regionSingapore() + { + //新加坡机房 + $regionSingapore = new Region( + array('up-as0.qiniup.com'), + array('upload-as0.qiniup.com'), + "rs-as0.qiniuapi.com", + "rsf-as0.qiniuapi.com", + "api-as0.qiniuapi.com", + "iovip-as0.qbox.me" + ); + return $regionSingapore; + } + + /* + * GET /v4/query?ak=&bucket= + * @param string $ak + * @param string $bucket + * @param string $ucHost|null + * @param array $backupUcHosts + * @param int $retryTimes + * @param RequestOptions|null $reqOpt + * @return Response + **/ + public static function queryRegion( + $ak, + $bucket, + $ucHost = null, + $backupUcHosts = array(), + $retryTimes = 2, + $reqOpt = null + ) { + $region = new Region(); + if (!$ucHost) { + $ucHost = "https://" . Config::QUERY_REGION_HOST; + } + $url = $ucHost . '/v4/query' . "?ak=$ak&bucket=$bucket"; + if ($reqOpt == null) { + $reqOpt = new RequestOptions(); + } + $reqOpt->middlewares = array( + new RetryDomainsMiddleware( + $backupUcHosts, + $retryTimes + ) + ); + $ret = Client::get($url, array(), $reqOpt); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = ($ret->body === null) ? array() : $ret->json(); + if (!is_array($r["hosts"]) || count($r["hosts"]) == 0) { + return array(null, new Error($url, $ret)); + } + + // parse region; + $regionHost = $r["hosts"][0]; + $region->cdnUpHosts = array_merge($region->cdnUpHosts, $regionHost['up']['domains']); + $region->srcUpHosts = array_merge($region->srcUpHosts, $regionHost['up']['domains']); + + // set specific hosts + $region->iovipHost = $regionHost['io']['domains'][0]; + if (isset($regionHost['rs']['domains']) && count($regionHost['rs']['domains']) > 0) { + $region->rsHost = $regionHost['rs']['domains'][0]; + } else { + $region->rsHost = Config::RS_HOST; + } + if (isset($regionHost['rsf']['domains']) && count($regionHost['rsf']['domains']) > 0) { + $region->rsfHost = $regionHost['rsf']['domains'][0]; + } else { + $region->rsfHost = Config::RSF_HOST; + } + if (isset($regionHost['api']['domains']) && count($regionHost['api']['domains']) > 0) { + $region->apiHost = $regionHost['api']['domains'][0]; + } else { + $region->apiHost = Config::API_HOST; + } + + // set ttl + $region->ttl = $regionHost['ttl']; + + return $region; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Rtc/AppClient.php b/vendor/qiniu/php-sdk/src/Qiniu/Rtc/AppClient.php new file mode 100644 index 0000000..3f245db --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Rtc/AppClient.php @@ -0,0 +1,236 @@ +auth = $auth; + $this->baseURL = sprintf("%s/%s/apps", Config::RTCAPI_HOST, Config::RTCAPI_VERSION); + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + /** + * 创建应用 + * + * @param string $hub 绑定的直播 hub + * @param string $title app 的名称 注意,Title 不是唯一标识,重复 create 动作将生成多个 app + * @param int $maxUsers 连麦房间支持的最大在线人数 + * @param bool $noAutoKickUser 禁止自动踢人(抢流),默认为 false + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_1 + */ + public function createApp($hub, $title, $maxUsers = null, $noAutoKickUser = null) + { + $params = array(); + $params['hub'] = $hub; + $params['title'] = $title; + if (!empty($maxUsers)) { + $params['maxUsers'] = $maxUsers; + } + if ($noAutoKickUser !== null) { + $params['noAutoKickUser'] = $noAutoKickUser; + } + $body = json_encode($params); + return $this->post($this->baseURL, $body); + } + + /** + * 更新一个应用的配置信息 + * + * @param string $appId app 的唯一标识,创建的时候由系统生成 + * @param string $hub app 的名称,可选 + * @param string $title 绑定的直播 hub,可选,用于合流后 rtmp 推流 + * @param int $maxUsers 连麦房间支持的最大在线人数,可选 + * @param bool $noAutoKickUser 禁止自动踢人,可选 + * @param null $mergePublishRtmp 连麦合流转推 RTMP 的配置,可选择。其详细配置可以参考文档 + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_1 + */ + public function updateApp($appId, $hub, $title, $maxUsers = null, $noAutoKickUser = null, $mergePublishRtmp = null) + { + $url = $this->baseURL . '/' . $appId; + $params = array(); + $params['hub'] = $hub; + $params['title'] = $title; + if (!empty($maxUsers)) { + $params['maxUsers'] = $maxUsers; + } + if ($noAutoKickUser !== null) { + $params['noAutoKickUser'] = $noAutoKickUser; + } + if (!empty($mergePublishRtmp)) { + $params['mergePublishRtmp'] = $mergePublishRtmp; + } + $body = json_encode($params); + return $this->post($url, $body); + } + + /** + * 获取应用信息 + * + * @param string $appId + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_1 + */ + public function getApp($appId) + { + $url = $this->baseURL . '/' . $appId; + return $this->get($url); + } + + /** + * 删除应用 + * + * @param string $appId app 的唯一标识,创建的时候由系统生成 + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_1 + */ + public function deleteApp($appId) + { + $url = $this->baseURL . '/' . $appId; + return $this->delete($url); + } + + /** + * 获取房间内用户列表 + * + * @param string $appId app 的唯一标识,创建的时候由系统生成 + * @param string $roomName 操作所查询的连麦房间 + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_2 + */ + public function listUser($appId, $roomName) + { + $url = sprintf("%s/%s/rooms/%s/users", $this->baseURL, $appId, $roomName); + return $this->get($url); + } + + /** + * 指定一个用户踢出房间 + * + * @param string $appId app 的唯一标识,创建的时候由系统生成 + * @param string $roomName 连麦房间 + * @param string $userId 操作所剔除的用户 + * @return mixed + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_2 + */ + public function kickUser($appId, $roomName, $userId) + { + $url = sprintf("%s/%s/rooms/%s/users/%s", $this->baseURL, $appId, $roomName, $userId); + return $this->delete($url); + } + + /** + * 停止一个房间的合流转推 + * + * @param string $appId + * @param string $roomName + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_2 + */ + public function stopMerge($appId, $roomName) + { + $url = sprintf("%s/%s/rooms/%s/merge", $this->baseURL, $appId, $roomName); + return $this->delete($url); + } + + /** + * 获取应用中活跃房间 + * + * @param string $appId 连麦房间所属的 app + * @param null $prefix 所查询房间名的前缀索引,可以为空。 + * @param int $offset 分页查询的位移标记 + * @param int $limit 此次查询的最大长度 + * @return array + * @link https://doc.qnsdk.com/rtn/docs/server_overview#2_2 + */ + public function listActiveRooms($appId, $prefix = null, $offset = null, $limit = null) + { + $query = array(); + if (isset($prefix)) { + $query['prefix'] = $prefix; + } + if (isset($offset)) { + $query['offset'] = $offset; + } + if (isset($limit)) { + $query['limit'] = $limit; + } + if (isset($query) && !empty($query)) { + $query = '?' . http_build_query($query); + $url = sprintf("%s/%s/rooms%s", $this->baseURL, $appId, $query); + } else { + $url = sprintf("%s/%s/rooms", $this->baseURL, $appId); + } + return $this->get($url); + } + + /** + * 生成加入房间的令牌 + * + * @param string $appId app 的唯一标识,创建的时候由系统生成 + * @param string $roomName 房间名称,需满足规格 ^[a-zA-Z0-9_-]{3,64}$ + * @param string $userId 请求加入房间的用户 ID,需满足规格 ^[a-zA-Z0-9_-]{3,50}$ + * @param int $expireAt 鉴权的有效时间,传入以秒为单位的64位 Unix 绝对时间 + * @param string $permission 该用户的房间管理权限,"admin" 或 "user",默认为 "user" + * @return string + * @link https://doc.qnsdk.com/rtn/docs/server_overview#1 + */ + public function appToken($appId, $roomName, $userId, $expireAt, $permission) + { + $params = array(); + $params['appId'] = $appId; + $params['userId'] = $userId; + $params['roomName'] = $roomName; + $params['permission'] = $permission; + $params['expireAt'] = $expireAt; + $appAccessString = json_encode($params); + return $this->auth->signWithData($appAccessString); + } + + private function get($url, $cType = null) + { + $rtcToken = $this->auth->authorizationV2($url, "GET", null, $cType); + $rtcToken['Content-Type'] = $cType; + $ret = Client::get($url, $rtcToken, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + return array($ret->json(), null); + } + + private function delete($url, $contentType = 'application/json') + { + $rtcToken = $this->auth->authorizationV2($url, "DELETE", null, $contentType); + $rtcToken['Content-Type'] = $contentType; + $ret = Client::delete($url, $rtcToken, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + return array($ret->json(), null); + } + + private function post($url, $body, $contentType = 'application/json') + { + $rtcToken = $this->auth->authorizationV2($url, "POST", $body, $contentType); + $rtcToken['Content-Type'] = $contentType; + $ret = Client::post($url, $body, $rtcToken, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = ($ret->body === null) ? array() : $ret->json(); + return array($r, null); + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Sms/Sms.php b/vendor/qiniu/php-sdk/src/Qiniu/Sms/Sms.php new file mode 100644 index 0000000..c96409b --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Sms/Sms.php @@ -0,0 +1,382 @@ +auth = $auth; + $this->baseURL = sprintf("%s/%s/", Config::SMS_HOST, Config::SMS_VERSION); + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + /** + * 创建签名 + * + * @param string $signature 签名 + * @param string $source 签名来源,申请签名时必须指定签名来源 + * @param string $pics 签名对应的资质证明图片进行 base64 编码格式转换后的字符串,可选 + * @return array + * + * @link https://developer.qiniu.com/sms/api/5844/sms-api-create-signature + */ + public function createSignature($signature, $source, $pics = null) + { + $params = array(); + $params['signature'] = $signature; + $params['source'] = $source; + if (!empty($pics)) { + $params['pics'] = array($this->imgToBase64($pics)); + } + $body = json_encode($params); + $url = $this->baseURL . 'signature'; + return $this->post($url, $body); + } + + /** + * 编辑签名 + * + * @param string $id 签名 ID + * @param string $signature 签名 + * @param string $source 签名来源 + * @param string $pics 签名对应的资质证明图片进行 base64 编码格式转换后的字符串,可选 + * @return array + * @link https://developer.qiniu.com/sms/api/5890/sms-api-edit-signature + */ + public function updateSignature($id, $signature, $source, $pics = null) + { + $params = array(); + $params['signature'] = $signature; + $params['source'] = $source; + if (!empty($pics)) { + $params['pics'] = array($this->imgToBase64($pics)); + } + $body = json_encode($params); + $url = $this->baseURL . 'signature/' . $id; + return $this->PUT($url, $body); + } + + /** + * 列出签名 + * + * @param string $audit_status 审核状态:"passed"(通过), "rejected"(未通过), "reviewing"(审核中) + * @param int $page 页码。默认为 1 + * @param int $page_size 分页大小。默认为 20 + * @return array + * @link https://developer.qiniu.com/sms/api/5889/sms-api-query-signature + */ + public function querySignature($audit_status = null, $page = 1, $page_size = 20) + { + + $url = sprintf( + "%s?audit_status=%s&page=%s&page_size=%s", + $this->baseURL . 'signature', + $audit_status, + $page, + $page_size + ); + return $this->get($url); + } + + /** + * 查询单个签名 + * + * @param string $signature_id + * @return array + * @link https://developer.qiniu.com/sms/api/5970/query-a-single-signature + */ + public function checkSingleSignature($signature_id) + { + + $url = sprintf( + "%s/%s", + $this->baseURL . 'signature', + $signature_id + ); + return $this->get($url); + } + + /** + * 删除签名 + * + * @param string $signature_id 签名 ID + * @return array + * @link https://developer.qiniu.com/sms/api/5891/sms-api-delete-signature + */ + public function deleteSignature($signature_id) + { + $url = $this->baseURL . 'signature/' . $signature_id; + return $this->delete($url); + } + + /** + * 创建模板 + * + * @param string $name 模板名称 + * @param string $template 模板内容 可设置自定义变量,发送短信时候使用,参考:${code} + * @param string $type notification:通知类,verification:验证码,marketing:营销类,voice:语音类 + * @param string $description 申请理由简述 + * @param string $signature_id 已经审核通过的签名 + * @return array array + * @link https://developer.qiniu.com/sms/api/5893/sms-api-create-template + */ + public function createTemplate( + $name, + $template, + $type, + $description, + $signature_id + ) { + $params = array(); + $params['name'] = $name; + $params['template'] = $template; + $params['type'] = $type; + $params['description'] = $description; + $params['signature_id'] = $signature_id; + + $body = json_encode($params); + $url = $this->baseURL . 'template'; + return $this->post($url, $body); + } + + /** + * 列出模板 + * + * @param string $audit_status 审核状态:passed (通过), rejected (未通过), reviewing (审核中) + * @param int $page 页码。默认为 1 + * @param int $page_size 分页大小。默认为 20 + * @return array + * @link https://developer.qiniu.com/sms/api/5894/sms-api-query-template + */ + public function queryTemplate($audit_status = null, $page = 1, $page_size = 20) + { + + $url = sprintf( + "%s?audit_status=%s&page=%s&page_size=%s", + $this->baseURL . 'template', + $audit_status, + $page, + $page_size + ); + return $this->get($url); + } + + /** + * 查询单个模版 + * + * @param string $template_id 模版ID + * @return array + * @link https://developer.qiniu.com/sms/api/5969/query-a-single-template + */ + public function querySingleTemplate($template_id) + { + + $url = sprintf( + "%s/%s", + $this->baseURL . 'template', + $template_id + ); + return $this->get($url); + } + + /** + * 编辑模板 + * + * @param string $id 模板 ID + * @param string $name 模板名称 + * @param string $template 模板内容 + * @param string $description 申请理由简述 + * @param string $signature_id 已经审核通过的签名 ID + * @return array + * @link https://developer.qiniu.com/sms/api/5895/sms-api-edit-template + */ + public function updateTemplate( + $id, + $name, + $template, + $description, + $signature_id + ) { + $params = array(); + $params['name'] = $name; + $params['template'] = $template; + $params['description'] = $description; + $params['signature_id'] = $signature_id; + $body = json_encode($params); + $url = $this->baseURL . 'template/' . $id; + return $this->PUT($url, $body); + } + + /** + * 删除模板 + * + * @param string $template_id 模板 ID + * @return array + * @link https://developer.qiniu.com/sms/api/5896/sms-api-delete-template + */ + public function deleteTemplate($template_id) + { + $url = $this->baseURL . 'template/' . $template_id; + return $this->delete($url); + } + + /** + * 发送短信 + * + * @param string $template_id 模板 ID + * @param array $mobiles 手机号 + * @param array $parameters 自定义模板变量,变量设置在创建模板时,参数template指定 + * @return array + * @link https://developer.qiniu.com/sms/api/5897/sms-api-send-message + */ + public function sendMessage($template_id, $mobiles, $parameters = null) + { + $params = array(); + $params['template_id'] = $template_id; + $params['mobiles'] = $mobiles; + if (!empty($parameters)) { + $params['parameters'] = $parameters; + } + $body = json_encode($params); + $url = $this->baseURL . 'message'; + return $this->post($url, $body); + } + + /** + * 查询发送记录 + * + * @param string $job_id 发送任务返回的 id + * @param string $message_id 单条短信发送接口返回的 id + * @param string $mobile 接收短信的手机号码 + * @param string $status sending: 发送中,success: 发送成功,failed: 发送失败,waiting: 等待发送 + * @param string $template_id 模版 id + * @param string $type marketing:营销,notification:通知,verification:验证码,voice:语音 + * @param string $start 开始时间,timestamp,例如: 1563280448 + * @param int $end 结束时间,timestamp,例如: 1563280471 + * @param int $page 页码,默认为 1 + * @param int $page_size 每页返回的数据条数,默认20,最大200 + * @return array + * @link https://developer.qiniu.com/sms/api/5852/query-send-sms + */ + public function querySendSms( + $job_id = null, + $message_id = null, + $mobile = null, + $status = null, + $template_id = null, + $type = null, + $start = null, + $end = null, + $page = 1, + $page_size = 20 + ) { + $query = array(); + \Qiniu\setWithoutEmpty($query, 'job_id', $job_id); + \Qiniu\setWithoutEmpty($query, 'message_id', $message_id); + \Qiniu\setWithoutEmpty($query, 'mobile', $mobile); + \Qiniu\setWithoutEmpty($query, 'status', $status); + \Qiniu\setWithoutEmpty($query, 'template_id', $template_id); + \Qiniu\setWithoutEmpty($query, 'type', $type); + \Qiniu\setWithoutEmpty($query, 'start', $start); + \Qiniu\setWithoutEmpty($query, 'end', $end); + \Qiniu\setWithoutEmpty($query, 'page', $page); + \Qiniu\setWithoutEmpty($query, 'page_size', $page_size); + + $url = $this->baseURL . 'messages?' . http_build_query($query); + return $this->get($url); + } + + + public function imgToBase64($img_file) + { + $img_base64 = ''; + if (file_exists($img_file)) { + $app_img_file = $img_file; // 图片路径 + $img_info = getimagesize($app_img_file); // 取得图片的大小,类型等 + $fp = fopen($app_img_file, "r"); // 图片是否可读权限 + if ($fp) { + $filesize = filesize($app_img_file); + if ($filesize > 5 * 1024 * 1024) { + die("pic size < 5M !"); + } + $img_type = null; + $content = fread($fp, $filesize); + $file_content = chunk_split(base64_encode($content)); // base64编码 + switch ($img_info[2]) { //判读图片类型 + case 1: + $img_type = 'gif'; + break; + case 2: + $img_type = 'jpg'; + break; + case 3: + $img_type = 'png'; + break; + } + //合成图片的base64编码 + $img_base64 = 'data:image/' . $img_type . ';base64,' . $file_content; + } + fclose($fp); + } + + return $img_base64; + } + + private function get($url, $contentType = 'application/x-www-form-urlencoded') + { + $headers = $this->auth->authorizationV2($url, "GET", null, $contentType); + $headers['Content-Type'] = $contentType; + $ret = Client::get($url, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + return array($ret->json(), null); + } + + private function delete($url, $contentType = 'application/json') + { + $headers = $this->auth->authorizationV2($url, "DELETE", null, $contentType); + $headers['Content-Type'] = $contentType; + $ret = Client::delete($url, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + return array($ret->json(), null); + } + + private function post($url, $body, $contentType = 'application/json') + { + $headers = $this->auth->authorizationV2($url, "POST", $body, $contentType); + + $headers['Content-Type'] = $contentType; + $ret = Client::post($url, $body, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = ($ret->body === null) ? array() : $ret->json(); + return array($r, null); + } + + private function PUT($url, $body, $contentType = 'application/json') + { + $headers = $this->auth->authorizationV2($url, "PUT", $body, $contentType); + $headers['Content-Type'] = $contentType; + $ret = Client::put($url, $body, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = ($ret->body === null) ? array() : $ret->json(); + return array($r, null); + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Storage/ArgusManager.php b/vendor/qiniu/php-sdk/src/Qiniu/Storage/ArgusManager.php new file mode 100644 index 0000000..51b4200 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Storage/ArgusManager.php @@ -0,0 +1,129 @@ +auth = $auth; + if ($config == null) { + $this->config = new Config(); + } else { + $this->config = $config; + } + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + /** + * 视频审核 + * + * @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()) { + 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, $this->proxy->makeReqOpt()); + } + + 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, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + 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); + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Storage/BucketManager.php b/vendor/qiniu/php-sdk/src/Qiniu/Storage/BucketManager.php new file mode 100644 index 0000000..bfca4fc --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Storage/BucketManager.php @@ -0,0 +1,1324 @@ +auth = $auth; + if ($config == null) { + $this->config = new Config(); + } else { + $this->config = $config; + } + $this->proxy = new Proxy($proxy, $proxy_auth, $proxy_user_password); + } + + /** + * 获取指定账号下所有的空间名 + * + * @param bool $shared 指定共享空间,rw:读写权限空间,rd:读权限空间 + * @return array 包含所有空间名 + */ + public function buckets($shared = true) + { + $includeShared = "false"; + if ($shared === true) { + $includeShared = "true"; + } + return $this->getV2($this->config->getUcHost() . '/buckets?shared=' . $includeShared); + } + + /** + * 列举空间,返回bucket列表 + * + * @param string $region 区域 + * @param string $line + * @param string $shared 指定共享空间,rw:读写权限空间,rd:读权限空间 + * @return array + */ + public function listbuckets( + $region = null, + $line = 'false', + $shared = 'false' + ) { + $path = '/v3/buckets?region=' . $region . '&line=' . $line . '&shared=' . $shared; + return $this->ucPost($path); + } + + /** + * 创建空间 + * + * @param string $name 创建的空间名 + * @param string $region 创建的区域,默认华东 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1382/mkbucketv3 + */ + public function createBucket($name, $region = 'z0') + { + $path = '/mkbucketv3/' . $name . '/region/' . $region; + return $this->postV2($this->config->getUcHost() . $path, null); + } + + /** + * 删除空间 + * + * @param string $name 需要删除的目标空间名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1601/drop-bucket + */ + public function deleteBucket($name) + { + $path = '/drop/' . $name; + return $this->postV2($this->config->getUcHost() . $path, null); + } + + /** + * 获取指定空间绑定的所有的域名 + * + * @param string $bucket 空间名称 + * @return array + */ + public function domains($bucket) + { + return $this->ucGet('/v2/domains?tbl=' . $bucket); + } + + /** + * 获取指定空间的相关信息 + * + * @param string $bucket 空间名称 + * @return array + */ + public function bucketInfo($bucket) + { + $path = '/v2/bucketInfo?bucket=' . $bucket; + return $this->ucPost($path); + } + + /** + * 获取指定zone的空间信息列表 + * + * @param string $region 区域 + * @param string $shared 指定共享空间,rw:读写权限空间,rd:读权限空间 + * @param string $fs 如果为 true,会返回每个空间当前的文件数和存储量(实时数据) + * @return array + */ + public function bucketInfos($region = null, $shared = 'false', $fs = 'false') + { + $path = '/v2/bucketInfos?region=' . $region . '&shared=' . $shared . '&fs=' . $fs; + return $this->ucPost($path); + } + + /** + * 列取空间的文件列表 + * + * @param string $bucket 空间名 + * @param string $prefix 列举前缀 + * @param string $marker 列举标识符 + * @param int $limit 单次列举个数限制 + * @param string $delimiter 指定目录分隔符 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1284/list + */ + public function listFiles( + $bucket, + $prefix = null, + $marker = null, + $limit = 1000, + $delimiter = null + ) { + $query = array('bucket' => $bucket); + \Qiniu\setWithoutEmpty($query, 'prefix', $prefix); + \Qiniu\setWithoutEmpty($query, 'marker', $marker); + \Qiniu\setWithoutEmpty($query, 'limit', $limit); + \Qiniu\setWithoutEmpty($query, 'delimiter', $delimiter); + return $this->rsfGet($bucket, '/list?' . http_build_query($query)); + } + + /** + * 列取空间的文件列表 + * + * @deprecated API 可能返回仅包含 marker,不包含 item 或 dir 的项,请使用 {@link listFiles} + * + * @param string $bucket 空间名 + * @param string $prefix 列举前缀 + * @param string $marker 列举标识符 + * @param int $limit 单次列举个数限制 + * @param string $delimiter 指定目录分隔符 + * @param bool $skipconfirm 是否跳过已删除条目的确认机制 + * + * @return array + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/list.html + */ + public function listFilesv2( + $bucket, + $prefix = null, + $marker = null, + $limit = 1000, + $delimiter = null, + $skipconfirm = true + ) { + $query = array('bucket' => $bucket); + \Qiniu\setWithoutEmpty($query, 'prefix', $prefix); + \Qiniu\setWithoutEmpty($query, 'marker', $marker); + \Qiniu\setWithoutEmpty($query, 'limit', $limit); + \Qiniu\setWithoutEmpty($query, 'delimiter', $delimiter); + \Qiniu\setWithoutEmpty($query, 'skipconfirm', $skipconfirm); + $path = '/v2/list?' . http_build_query($query); + + list($host, $err) = $this->config->getRsfHostV2( + $this->auth->getAccessKey(), + $bucket, + $this->proxy->makeReqOpt() + ); + + if ($err != null) { + return array(null, $err); + } + + $url = $host . $path; + $headers = $this->auth->authorizationV2($url, 'POST', null, 'application/x-www-form-urlencoded'); + $ret = Client::post($url, null, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = explode("\n", $ret->body); + array_pop($r); + return array($r, null); + } + + /** + * 增加bucket生命规则 + * + * @param string $bucket + * 空间名 + * @param string $name + * 规则名称 bucket 内唯一,长度小于50,不能为空,只能为字母、数字、下划线 + * @param string $prefix + * 同一个 bucket 里面前缀不能重复 + * @param int $delete_after_days + * 指定上传文件多少天后删除,指定为0表示不删除,大于0表示多少天后删除。 + * 需大于 to_line_after_days + * @param int $to_line_after_days + * 指定文件上传多少天后转低频存储。指定为0表示不转低频存储 + * @param int $to_archive_ir_after_days + * 指定文件上传多少天后转归档直读。指定为0表示不转归档直读 + * @param int $to_archive_after_days + * 指定文件上传多少天后转归档存储。指定为0表示不转归档存储 + * @param int $to_deep_archive_after_days + * 指定文件上传多少天后转深度归档存储。指定为0表示不转深度归档存储 + * @return array + */ + public function bucketLifecycleRule( + $bucket, + $name, + $prefix, + $delete_after_days = null, + $to_line_after_days = null, + $to_archive_after_days = null, + $to_deep_archive_after_days = null, + $to_archive_ir_after_days = null + ) { + $path = '/rules/add'; + $params = array(); + if ($bucket) { + $params['bucket'] = $bucket; + } + if ($name) { + $params['name'] = $name; + } + if ($prefix) { + $params['prefix'] = $prefix; + } + if ($delete_after_days) { + $params['delete_after_days'] = $delete_after_days; + } + if ($to_line_after_days) { + $params['to_line_after_days'] = $to_line_after_days; + } + if ($to_archive_ir_after_days) { + $params['to_archive_ir_after_days'] = $to_archive_ir_after_days; + } + if ($to_archive_after_days) { + $params['to_archive_after_days'] = $to_archive_after_days; + } + if ($to_deep_archive_after_days) { + $params['to_deep_archive_after_days'] = $to_deep_archive_after_days; + } + $data = http_build_query($params); + $info = $this->ucPost($path, $data); + return $info; + } + + /** + * 更新bucket生命规则 + * + * @param string $bucket + * 空间名 + * @param string $name + * 规则名称 bucket 内唯一,长度小于50,不能为空,只能为字母、数字、下划线 + * @param string $prefix + * 同一个 bucket 里面前缀不能重复 + * @param int $delete_after_days + * 指定上传文件多少天后删除,指定为0表示不删除,大于0表示多少天后删除 + * 需大于 to_line_after_days + * @param int $to_line_after_days + * 指定文件上传多少天后转低频存储。指定为0表示不转低频存储 + * @param int $to_archive_ir_after_days + * 指定文件上传多少天后转归档只读。指定为0表示不转归档只读 + * @param int $to_archive_after_days + * 指定文件上传多少天后转归档存储。指定为0表示不转归档存储 + * @param int $to_deep_archive_after_days + * 指定文件上传多少天后转深度归档存储。指定为0表示不转深度归档存储 + * @return array + */ + public function updateBucketLifecycleRule( + $bucket, + $name, + $prefix, + $delete_after_days = null, + $to_line_after_days = null, + $to_archive_after_days = null, + $to_deep_archive_after_days = null, + $to_archive_ir_after_days = null + ) { + $path = '/rules/update'; + $params = array(); + if ($bucket) { + $params['bucket'] = $bucket; + } + if ($name) { + $params['name'] = $name; + } + if ($prefix) { + $params['prefix'] = $prefix; + } + if ($delete_after_days) { + $params['delete_after_days'] = $delete_after_days; + } + if ($to_line_after_days) { + $params['to_line_after_days'] = $to_line_after_days; + } + if ($to_archive_ir_after_days) { + $params['to_archive_ir_after_days'] = $to_archive_ir_after_days; + } + if ($to_archive_after_days) { + $params['to_archive_after_days'] = $to_archive_after_days; + } + if ($to_deep_archive_after_days) { + $params['to_deep_archive_after_days'] = $to_deep_archive_after_days; + } + $data = http_build_query($params); + return $this->ucPost($path, $data); + } + + /** + * 获取bucket生命规则 + * + * @param string $bucket 空间名 + * @return array + */ + public function getBucketLifecycleRules($bucket) + { + $path = '/rules/get?bucket=' . $bucket; + $info = $this->ucGet($path); + return $info; + } + + /** + * 删除bucket生命规则 + * + * @param string $bucket 空间名 + * @param string $name 规则名称 bucket 内唯一,长度小于50,不能为空, + * 只能为字母、数字、下划线() + * @return array + */ + public function deleteBucketLifecycleRule($bucket, $name) + { + $path = '/rules/delete'; + $params = array(); + if ($bucket) { + $params['bucket'] = $bucket; + } + if ($name) { + $params['name'] = $name; + } + $data = http_build_query($params); + $info = $this->ucPost($path, $data); + return $info; + } + + /** + * 增加bucket事件通知规则 + * + * @param string $bucket 空间名 + * @param string $name 规则名称 bucket 内唯一,长度小于50,不能为空, + * 只能为字母、数字、下划线() + * @param string $prefix 同一个 bucket 里面前缀不能重复 + * @param string $suffix 可选,文件配置的后缀 + * @param array $event 事件类型,可以指定多个,包括 put,mkfile,delete,copy,move,append, + * disable,enable,deleteMarkerCreate + * @param string $callbackURL 通知URL,可以指定多个,失败依次重试 + * @param string $access_key 可选,设置的话会对通知请求用对应的ak、sk进行签名 + * @param string $host 可选,通知请求的host + * + * @return array + */ + public function putBucketEvent( + $bucket, + $name, + $prefix, + $suffix, + $event, + $callbackURL, + $access_key = null, + $host = null + ) { + $path = '/events/add'; + $params = array(); + if (!empty($bucket)) { + $params['bucket'] = $bucket; + } + if (!empty($name)) { + $params['name'] = $name; + } + if (!empty($prefix)) { + $params['prefix'] = $prefix; + } + if (!empty($suffix)) { + $params['suffix'] = $suffix; + } + if (!empty($callbackURL)) { + $params['callbackURL'] = $callbackURL; + } + if (!empty($access_key)) { + $params['access_key'] = $access_key; + } + if (!empty($host)) { + $params['host'] = $host; + } + $data = http_build_query($params); + if (!empty($event)) { + $eventpath = ""; + foreach ($event as $key => $value) { + $eventpath .= "&event=$value"; + } + $data .= $eventpath; + } + $info = $this->ucPost($path, $data); + return $info; + } + + /** + * 更新bucket事件通知规则 + * + * @param string $bucket 空间名 + * @param string $name 规则名称 bucket 内唯一,长度小于50,不能为空, + * 只能为字母、数字、下划线() + * @param string $prefix 同一个 bucket 里面前缀不能重复 + * @param string $suffix 可选,文件配置的后缀 + * @param array $event 事件类型,可以指定多个,包括 put,mkfile,delete,copy,move,append,disable, + * enable,deleteMarkerCreate + * @param string $callbackURL 通知URL,可以指定多个,失败依次重试 + * @param string $access_key 可选,设置的话会对通知请求用对应的ak、sk进行签名 + * @param string $host 可选,通知请求的host + * + * @return array + */ + public function updateBucketEvent( + $bucket, + $name, + $prefix, + $suffix, + $event, + $callbackURL, + $access_key = null, + $host = null + ) { + $path = '/events/update'; + $params = array(); + if (!empty($bucket)) { + $params['bucket'] = $bucket; + } + if (!empty($name)) { + $params['name'] = $name; + } + if (!empty($prefix)) { + $params['prefix'] = $prefix; + } + if ($suffix) { + $params['suffix'] = $suffix; + } + if (!empty($event)) { + $params['event'] = $event; + } + if (!empty($callbackURL)) { + $params['callbackURL'] = $callbackURL; + } + if (!empty($access_key)) { + $params['access_key'] = $access_key; + } + if (!empty($host)) { + $params['host'] = $host; + } + $data = http_build_query($params); + if (!empty($event)) { + $eventpath = ""; + foreach ($event as $key => $value) { + $eventpath .= "&event=$value"; + } + $data .= $eventpath; + } + return $this->ucPost($path, $data); + } + + /** + * 获取bucket事件通知规则 + * + * @param string $bucket 空间名 + * @return array + */ + public function getBucketEvents($bucket) + { + $path = '/events/get?bucket=' . $bucket; + return $this->ucGet($path); + } + + /** + * 删除bucket事件通知规则 + * + * @param string $bucket 空间名 + * @param string $name 规则名称bucket内唯一,长度小于50,不能为空,只能为字母、数字、下划线 + * @return array + */ + public function deleteBucketEvent($bucket, $name) + { + $path = '/events/delete'; + $params = array(); + if ($bucket) { + $params['bucket'] = $bucket; + } + if ($name) { + $params['name'] = $name; + } + $data = http_build_query($params); + return $this->ucPost($path, $data); + } + + /** + * 获取bucket的跨域信息 + * + * @param string $bucket 空间名 + * @return array + */ + public function getCorsRules($bucket) + { + $path = '/corsRules/get/' . $bucket; + return $this->ucGet($path); + } + + /** + * 开关原图保护 + * + * @param string $bucket 空间名称 + * @param int $mode mode 为1表示开启原图保护,0表示关闭 + * @return array + */ + public function putBucketAccessStyleMode($bucket, $mode) + { + $path = '/accessMode/' . $bucket . '/mode/' . $mode; + return $this->ucPost($path, null); + } + + /** + * 设置私有属性 + * + * @param string $bucket 空间名称 + * @param int $private private为0表示公开,为1表示私有 + * @return array + */ + public function putBucketAccessMode($bucket, $private) + { + $path = "/private?bucket=$bucket&private=$private"; + return $this->ucPost($path, null); + } + + /** + * 设置 referer 防盗链 + * + * @param string $bucket 空间名称 + * @param int $mode 0:关闭Referer(使用此选项将会忽略以下参数并将恢复默认值); + * 1:设置Referer白名单; 2:设置Referer黑名单 + * @param string $norefer 0:不允许空 Refer 访问; 1:表示允许空Refer访问 + * @param string $pattern 规则字符串 + * @param int $enabled 源站是否支持,默认为0只给CDN配置, 设置为1表示开启源站防盗链 + * @return array + * @link https://developer.qiniu.com/kodo/manual/6093/set-the-hotlinking-prevention + */ + public function putReferAntiLeech($bucket, $mode, $norefer, $pattern, $enabled = 1) + { + $path = "/referAntiLeech?bucket=$bucket&mode=$mode&norefer=$norefer&pattern=$pattern&source_enabled=$enabled"; + return $this->ucPost($path, null); + } + + /** + * 设置Bucket的maxAge + * + * @param string $bucket 空间名称 + * @param int $maxAge maxAge为0或者负数表示为默认值(31536000) + * @return array + */ + public function putBucketMaxAge($bucket, $maxAge) + { + $path = '/maxAge?bucket=' . $bucket . '&maxAge=' . $maxAge; + return $this->ucPost($path, null); + } + + /** + * 设置空间配额 + * + * @param string $bucket 空间名称,不支持授权空间 + * @param string $size 空间存储量配额,参数传入0或不传表示不更改当前配置,传入-1表示取消限额,新创建的空间默认没有限额 + * @param string $count 空间文件数配额,参数含义同 + * @return array + */ + public function putBucketQuota($bucket, $size, $count) + { + $path = '/setbucketquota/' . $bucket . '/size/' . $size . '/count/' . $count; + return $this->apiPost($bucket, $path); + } + + /** + * 获取空间配额 + * + * @param string $bucket 空间名称 + * @return array + */ + public function getBucketQuota($bucket) + { + $path = '/getbucketquota/' . $bucket; + return $this->apiPost($bucket, $path); + } + + /** + * 获取资源的元信息,但不返回文件内容 + * + * @param string $bucket 待获取信息资源所在的空间 + * @param string $key 待获取资源的文件名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1308/stat + */ + public function stat($bucket, $key) + { + $path = '/stat/' . \Qiniu\entry($bucket, $key); + return $this->rsGet($bucket, $path); + } + + /** + * 删除指定资源 + * + * @param string $bucket 待删除资源所在的空间 + * @param string $key 待删除资源的文件名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1257/delete + */ + public function delete($bucket, $key) + { + $path = '/delete/' . \Qiniu\entry($bucket, $key); + return $this->rsPost($bucket, $path); + } + + /** + * 给资源进行重命名,本质为move操作。 + * + * @param string $bucket 待操作资源所在空间 + * @param string $oldname 待操作资源文件名 + * @param string $newname 目标资源文件名 + * + * @return array + */ + public function rename($bucket, $oldname, $newname) + { + return $this->move($bucket, $oldname, $bucket, $newname); + } + + /** + * 对资源进行复制。 + * + * @param string $from_bucket 待操作资源所在空间 + * @param string $from_key 待操作资源文件名 + * @param string $to_bucket 目标资源空间名 + * @param string $to_key 目标资源文件名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1254/copy + */ + public function copy($from_bucket, $from_key, $to_bucket, $to_key, $force = false) + { + $from = \Qiniu\entry($from_bucket, $from_key); + $to = \Qiniu\entry($to_bucket, $to_key); + $path = '/copy/' . $from . '/' . $to; + if ($force === true) { + $path .= '/force/true'; + } + return $this->rsPost($from_bucket, $path); + } + + /** + * 将资源从一个空间到另一个空间 + * + * @param string $from_bucket 待操作资源所在空间 + * @param string $from_key 待操作资源文件名 + * @param string $to_bucket 目标资源空间名 + * @param string $to_key 目标资源文件名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1288/move + */ + public function move($from_bucket, $from_key, $to_bucket, $to_key, $force = false) + { + $from = \Qiniu\entry($from_bucket, $from_key); + $to = \Qiniu\entry($to_bucket, $to_key); + $path = '/move/' . $from . '/' . $to; + if ($force) { + $path .= '/force/true'; + } + return $this->rsPost($from_bucket, $path); + } + + /** + * 主动修改指定资源的文件元信息 + * + * @param string $bucket 待操作资源所在空间 + * @param string $key 待操作资源文件名 + * @param string $mime 待操作文件目标mimeType + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1252/chgm + */ + public function changeMime($bucket, $key, $mime) + { + $resource = \Qiniu\entry($bucket, $key); + $encode_mime = \Qiniu\base64_urlSafeEncode($mime); + $path = '/chgm/' . $resource . '/mime/' . $encode_mime; + return $this->rsPost($bucket, $path); + } + + + /** + * 修改指定资源的存储类型 + * + * @param string $bucket 待操作资源所在空间 + * @param string $key 待操作资源文件名 + * @param int $fileType 对象存储类型 + * 0 表示标准存储; + * 1 表示低频存储; + * 2 表示归档存储; + * 3 表示深度归档存储; + * 4 表示归档直读存储; + * + * @return array + * @link https://developer.qiniu.com/kodo/api/3710/chtype + */ + public function changeType($bucket, $key, $fileType) + { + $resource = \Qiniu\entry($bucket, $key); + $path = '/chtype/' . $resource . '/type/' . $fileType; + return $this->rsPost($bucket, $path); + } + + /** + * 解冻指定资源的存储类型 + * + * @param string $bucket 待操作资源所在空间 + * @param string $key 待操作资源文件名 + * @param int $freezeAfterDays 解冻有效时长,取值范围 1~7 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/6380/restore-archive + */ + public function restoreAr($bucket, $key, $freezeAfterDays) + { + $resource = \Qiniu\entry($bucket, $key); + $path = '/restoreAr/' . $resource . '/freezeAfterDays/' . $freezeAfterDays; + return $this->rsPost($bucket, $path); + } + + /** + * 修改文件的存储状态,即禁用状态和启用状态间的的互相转换 + * + * @param string $bucket 待操作资源所在空间 + * @param string $key 待操作资源文件名 + * @param int $status 0表示启用;1表示禁用 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/4173/modify-the-file-status + */ + public function changeStatus($bucket, $key, $status) + { + $resource = \Qiniu\entry($bucket, $key); + $path = '/chstatus/' . $resource . '/status/' . $status; + return $this->rsPost($bucket, $path); + } + + /** + * 从指定URL抓取资源,并将该资源存储到指定空间中 + * + * @param string $url 指定的URL + * @param string $bucket 目标资源空间 + * @param string $key 目标资源文件名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1263/fetch + */ + public function fetch($url, $bucket, $key = null) + { + + $resource = \Qiniu\base64_urlSafeEncode($url); + $to = \Qiniu\entry($bucket, $key); + $path = '/fetch/' . $resource . '/to/' . $to; + + $ak = $this->auth->getAccessKey(); + + + list($ioHost, $err) = $this->config->getIovipHostV2($ak, $bucket, $this->proxy->makeReqOpt()); + if ($err != null) { + return array(null, $err); + } + + $url = $ioHost . $path; + return $this->postV2($url, null); + } + + /** + * 从指定URL异步抓取资源,并将该资源存储到指定空间中 + * + * @param string $url 需要抓取的url + * @param string $bucket 所在区域的bucket + * @param string $host 从指定url下载数据时使用的Host + * @param string $key 文件存储的key + * @param string $md5 文件md5 + * @param string $etag 文件etag + * @param string $callbackurl 回调URL + * @param string $callbackbody 回调Body + * @param string $callbackbodytype 回调Body内容类型,默认为"application/x-www-form-urlencoded" + * @param string $callbackhost 回调时使用的Host + * @param int $file_type 存储文件类型 + * 0:标准存储(默认) + * 1:低频存储 + * 2:归档存储 + * 3:深度归档存储 + * 4:归档直读存储 + * @param bool $ignore_same_key 如果空间中已经存在同名文件则放弃本次抓取 + * @return array + * @link https://developer.qiniu.com/kodo/api/4097/asynch-fetch + */ + public function asynchFetch( + $url, + $bucket, + $host = null, + $key = null, + $md5 = null, + $etag = null, + $callbackurl = null, + $callbackbody = null, + $callbackbodytype = 'application/x-www-form-urlencoded', + $callbackhost = null, + $file_type = 0, + $ignore_same_key = false + ) { + $path = '/sisyphus/fetch'; + + $params = array('url' => $url, 'bucket' => $bucket); + \Qiniu\setWithoutEmpty($params, 'host', $host); + \Qiniu\setWithoutEmpty($params, 'key', $key); + \Qiniu\setWithoutEmpty($params, 'md5', $md5); + \Qiniu\setWithoutEmpty($params, 'etag', $etag); + \Qiniu\setWithoutEmpty($params, 'callbackurl', $callbackurl); + \Qiniu\setWithoutEmpty($params, 'callbackbody', $callbackbody); + \Qiniu\setWithoutEmpty($params, 'callbackbodytype', $callbackbodytype); + \Qiniu\setWithoutEmpty($params, 'callbackhost', $callbackhost); + \Qiniu\setWithoutEmpty($params, 'file_type', $file_type); + \Qiniu\setWithoutEmpty($params, 'ignore_same_key', $ignore_same_key); + $data = json_encode($params); + + return $this->apiPost($bucket, $path, $data); + } + + + /** + * 查询异步第三方资源抓取任务状态 + * + * @param string $zone + * @param string $id + * @return array + * @link https://developer.qiniu.com/kodo/api/4097/asynch-fetch + */ + public function asynchFetchStatus($zone, $id) + { + $scheme = "http://"; + + if ($this->config->useHTTPS === true) { + $scheme = "https://"; + } + + $url = $scheme . "api-" . $zone . ".qiniuapi.com/sisyphus/fetch?id=" . $id; + + list($ret, $err) = $this->getV2($url); + + if ($err != null) { + return array(null, $err); + } + return array($ret, null); + } + + + /** + * 从镜像源站抓取资源到空间中,如果空间中已经存在,则覆盖该资源 + * + * @param string $bucket 待获取资源所在的空间 + * @param string $key 代获取资源文件名 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/1293/prefetch + */ + public function prefetch($bucket, $key) + { + $resource = \Qiniu\entry($bucket, $key); + $path = '/prefetch/' . $resource; + + $ak = $this->auth->getAccessKey(); + list($ioHost, $err) = $this->config->getIovipHostV2($ak, $bucket, $this->proxy->makeReqOpt()); + + if ($err != null) { + return array(null, $err); + } + + $url = $ioHost . $path; + return $this->postV2($url, null); + } + + /** + * 在单次请求中进行多个资源管理操作 + * + * @param array $operations 资源管理操作数组 + * + * @return array 每个资源的处理情况,结果类似: + * [ + * { "code" => , "data" => }, + * { "code" => }, + * { "code" => }, + * { "code" => }, + * { "code" => , "data" => { "error": "" } }, + * ... + * ] + * @link http://developer.qiniu.com/docs/v6/api/reference/rs/batch.html + */ + public function batch($operations) + { + $scheme = "http://"; + if ($this->config->useHTTPS === true) { + $scheme = "https://"; + } + $params = 'op=' . implode('&op=', $operations); + $errResp = new Response(0, 0); + if (count($operations) <= 0) { + $errResp->error = 'empty operations'; + return array(null, new Error($scheme . '/batch', $errResp)); + } + $bucket = ''; + foreach ($operations as $op) { + $segments = explode('/', $op); + if (count($segments) < 3) { + continue; + } + list($bucket,) = \Qiniu\decodeEntry($segments[2]); + } + return $this->rsPost($bucket, '/batch', $params); + } + + /** + * 设置文件的生命周期 + * + * @param string $bucket 设置文件生命周期文件所在的空间 + * @param string $key 设置文件生命周期文件的文件名 + * @param int $days 设置该文件多少天后删除,当$days设置为0时表示取消该文件的生命周期 + * + * @return array + * @link https://developer.qiniu.com/kodo/api/update-file-lifecycle + */ + public function deleteAfterDays($bucket, $key, $days) + { + $entry = \Qiniu\entry($bucket, $key); + $path = "/deleteAfterDays/$entry/$days"; + return $this->rsPost($bucket, $path); + } + + /** + * 更新 object 生命周期 + * + * @param string $bucket 空间名 + * @param string $key 目标资源 + * @param int $to_line_after_days 多少天后将文件转为低频存储。 + * -1 表示取消已设置的转低频存储的生命周期规则; + * 0 表示不修改转低频生命周期规则。 + * @param int $to_archive_ir_after_days 多少天后转为归档直读存储。 + * -1 表示取消已设置的转归档直读存储的生命周期规则; + * 0 表示不修改转归档直读生命周期规则。 + * @param int $to_archive_after_days 多少天后将文件转为归档存储。 + * -1 表示取消已设置的转归档存储的生命周期规则; + * 0 表示不修改转归档生命周期规则。 + * @param int $to_deep_archive_after_days 多少天后将文件转为深度归档存储。 + * -1 表示取消已设置的转深度归档存储的生命周期规则; + * 0 表示不修改转深度归档生命周期规则。 + * @param int $delete_after_days 多少天后将文件删除。 + * -1 表示取消已设置的删除存储的生命周期规则; + * 0 表示不修改删除存储的生命周期规则。 + * @return array + */ + public function setObjectLifecycle( + $bucket, + $key, + $to_line_after_days = 0, + $to_archive_after_days = 0, + $to_deep_archive_after_days = 0, + $delete_after_days = 0, + $to_archive_ir_after_days = 0 + ) { + return $this->setObjectLifecycleWithCond( + $bucket, + $key, + null, + $to_line_after_days, + $to_archive_after_days, + $to_deep_archive_after_days, + $delete_after_days, + $to_archive_ir_after_days + ); + } + + /** + * 更新 object 生命周期 + * + * @param string $bucket 空间名 + * @param string $key 目标资源 + * @param int $to_line_after_days 多少天后将文件转为低频存储。 + * 设置为 -1 表示取消已设置的转低频存储的生命周期规则; + * 0 表示不修改转低频生命周期规则。 + * @param int $to_archive_ir_after_days 多少天后将文件转为归档直读存储。 + * 设置为 -1 表示取消已设置的转归档直读存储的生命周期规则; + * 0 表示不修改转归档直读生命周期规则。 + * @param int $to_archive_after_days 多少天后将文件转为归档存储。 + * -1 表示取消已设置的转归档存储的生命周期规则; + * 0 表示不修改转归档生命周期规则。 + * @param int $to_deep_archive_after_days 多少天后将文件转为深度归档存储。 + * -1 表示取消已设置的转深度归档存储的生命周期规则; + * 0 表示不修改转深度归档生命周期规则。 + * @param int $delete_after_days 多少天后将文件删除。 + * -1 表示取消已设置的删除存储的生命周期规则; + * 0 表示不修改删除存储的生命周期规则。 + * @param array $cond 匹配条件,只有条件匹配才会设置成功。 + * 目前支持:hash、mime、fsize、putTime + * @return array + */ + public function setObjectLifecycleWithCond( + $bucket, + $key, + $cond = null, + $to_line_after_days = 0, + $to_archive_after_days = 0, + $to_deep_archive_after_days = 0, + $delete_after_days = 0, + $to_archive_ir_after_days = 0 + ) { + $encodedEntry = \Qiniu\entry($bucket, $key); + $path = '/lifecycle/' . $encodedEntry . + '/toIAAfterDays/' . $to_line_after_days . + '/toArchiveIRAfterDays/' . $to_archive_ir_after_days . + '/toArchiveAfterDays/' . $to_archive_after_days . + '/toDeepArchiveAfterDays/' . $to_deep_archive_after_days . + '/deleteAfterDays/' . $delete_after_days; + if ($cond != null) { + $condStrArr = array(); + foreach ($cond as $key => $value) { + array_push($condStrArr, $key . '=' . $value); + } + $condStr = implode('&', $condStrArr); + $path .= '/cond' . \Qiniu\base64_urlSafeEncode($condStr); + } + return $this->rsPost($bucket, $path); + } + + private function rsfGet($bucket, $path) + { + list($host, $err) = $this->config->getRsfHostV2( + $this->auth->getAccessKey(), + $bucket, + $this->proxy->makeReqOpt() + ); + + if ($err != null) { + return array(null, $err); + } + + return $this->getV2($host . $path); + } + + private function rsGet($bucket, $path) + { + list($host, $err) = $this->config->getRsHostV2( + $this->auth->getAccessKey(), + $bucket, + $this->proxy->makeReqOpt() + ); + + if ($err != null) { + return array(null, $err); + } + + return $this->getV2($host . $path); + } + + private function rsPost($bucket, $path, $body = null) + { + list($host, $err) = $this->config->getRsHostV2( + $this->auth->getAccessKey(), + $bucket, + $this->proxy->makeReqOpt() + ); + + if ($err != null) { + return array(null, $err); + } + + return $this->postV2($host . $path, $body); + } + + private function apiGet($bucket, $path) + { + list($host, $err) = $this->config->getApiHostV2( + $this->auth->getAccessKey(), + $bucket, + $this->proxy->makeReqOpt() + ); + + if ($err != null) { + return array(null, $err); + } + + return $this->getV2($host . $path); + } + + private function apiPost($bucket, $path, $body = null) + { + + list($host, $err) = $this->config->getApiHostV2( + $this->auth->getAccessKey(), + $bucket, + $this->proxy->makeReqOpt() + ); + + if ($err != null) { + return array(null, $err); + } + + return $this->postV2($host . $path, $body); + } + + private function ucGet($path) + { + $url = $this->config->getUcHost() . $path; + return $this->getV2($url); + } + + private function ucPost($path, $body = null) + { + $url = $this->config->getUcHost() . $path; + return $this->postV2($url, $body); + } + + private function getV2($url) + { + $headers = $this->auth->authorizationV2($url, 'GET', null, 'application/x-www-form-urlencoded'); + $ret = Client::get($url, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + return array($ret->json(), null); + } + + private function postV2($url, $body) + { + $headers = $this->auth->authorizationV2($url, 'POST', $body, 'application/x-www-form-urlencoded'); + $ret = Client::post($url, $body, $headers, $this->proxy->makeReqOpt()); + if (!$ret->ok()) { + return array(null, new Error($url, $ret)); + } + $r = ($ret->body === null) ? array() : $ret->json(); + return array($r, null); + } + + public static function buildBatchCopy($source_bucket, $key_pairs, $target_bucket, $force) + { + return self::twoKeyBatch('/copy', $source_bucket, $key_pairs, $target_bucket, $force); + } + + + public static function buildBatchRename($bucket, $key_pairs, $force) + { + return self::buildBatchMove($bucket, $key_pairs, $bucket, $force); + } + + + public static function buildBatchMove($source_bucket, $key_pairs, $target_bucket, $force) + { + return self::twoKeyBatch('/move', $source_bucket, $key_pairs, $target_bucket, $force); + } + + + public static function buildBatchDelete($bucket, $keys) + { + return self::oneKeyBatch('/delete', $bucket, $keys); + } + + + public static function buildBatchStat($bucket, $keys) + { + return self::oneKeyBatch('/stat', $bucket, $keys); + } + + public static function buildBatchDeleteAfterDays($bucket, $key_day_pairs) + { + $data = array(); + foreach ($key_day_pairs as $key => $day) { + array_push($data, '/deleteAfterDays/' . \Qiniu\entry($bucket, $key) . '/' . $day); + } + return $data; + } + + /** + * @param string $bucket 空间名 + * @param array $keys 目标资源 + * @param int $to_line_after_days 多少天后将文件转为低频存储。 + * -1 表示取消已设置的转低频存储的生命周期规则; + * 0 表示不修改转低频生命周期规则。 + * @param int $to_archive_ir_after_days 多少天后将文件转为归档直读。 + * -1 表示取消已设置的转归档只读的生命周期规则; + * 0 表示不修改转归档只读周期规则。 + * @param int $to_archive_after_days 多少天后将文件转为归档存储。 + * -1 表示取消已设置的转归档存储的生命周期规则; + * 0 表示不修改转归档生命周期规则。 + * @param int $to_deep_archive_after_days 多少天后将文件转为深度归档存储。 + * -1 表示取消已设置的转深度归档存储的生命周期规则; + * 0 表示不修改转深度归档生命周期规则。 + * @param int $delete_after_days 多少天后将文件删除。 + * -1 表示取消已设置的删除存储的生命周期规则; + * 0 表示不修改删除存储的生命周期规则。 + * + * @retrun array + */ + public static function buildBatchSetObjectLifecycle( + $bucket, + $keys, + $to_line_after_days, + $to_archive_after_days, + $to_deep_archive_after_days, + $delete_after_days, + $to_archive_ir_after_days = 0 + ) { + $result = array(); + foreach ($keys as $key) { + $encodedEntry = \Qiniu\entry($bucket, $key); + $op = '/lifecycle/' . $encodedEntry . + '/toIAAfterDays/' . $to_line_after_days . + '/toArchiveIRAfterDays/' . $to_archive_ir_after_days . + '/toArchiveAfterDays/' . $to_archive_after_days . + '/toDeepArchiveAfterDays/' . $to_deep_archive_after_days . + '/deleteAfterDays/' . $delete_after_days; + array_push($result, $op); + } + return $result; + } + + public static function buildBatchChangeMime($bucket, $key_mime_pairs) + { + $data = array(); + foreach ($key_mime_pairs as $key => $mime) { + array_push($data, '/chgm/' . \Qiniu\entry($bucket, $key) . '/mime/' . base64_encode($mime)); + } + return $data; + } + + public static function buildBatchChangeType($bucket, $key_type_pairs) + { + $data = array(); + foreach ($key_type_pairs as $key => $type) { + array_push($data, '/chtype/' . \Qiniu\entry($bucket, $key) . '/type/' . $type); + } + return $data; + } + + public static function buildBatchRestoreAr($bucket, $key_restore_days_pairs) + { + $data = array(); + foreach ($key_restore_days_pairs as $key => $restore_days) { + array_push($data, '/restoreAr/' . \Qiniu\entry($bucket, $key) . '/freezeAfterDays/' . $restore_days); + } + return $data; + } + + private static function oneKeyBatch($operation, $bucket, $keys) + { + $data = array(); + foreach ($keys as $key) { + array_push($data, $operation . '/' . \Qiniu\entry($bucket, $key)); + } + return $data; + } + + private static function twoKeyBatch($operation, $source_bucket, $key_pairs, $target_bucket, $force) + { + if ($target_bucket === null) { + $target_bucket = $source_bucket; + } + $data = array(); + $forceOp = "false"; + if ($force) { + $forceOp = "true"; + } + foreach ($key_pairs as $from_key => $to_key) { + $from = \Qiniu\entry($source_bucket, $from_key); + $to = \Qiniu\entry($target_bucket, $to_key); + array_push($data, $operation . '/' . $from . '/' . $to . "/force/" . $forceOp); + } + return $data; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Storage/FormUploader.php b/vendor/qiniu/php-sdk/src/Qiniu/Storage/FormUploader.php new file mode 100644 index 0000000..d68654d --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Storage/FormUploader.php @@ -0,0 +1,165 @@ + "", + * "key" => "" + * ] + */ + public static function put( + $upToken, + $key, + $data, + $config, + $params, + $mime, + $fname, + $reqOpt = null + ) { + if ($reqOpt == null) { + $reqOpt = new RequestOptions(); + } + $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); + } + + list($upHost, $err) = $config->getUpHostV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + + $response = Client::multipartPost( + $upHost, + $fields, + 'file', + $fname, + $data, + $mime, + array(), + $reqOpt + ); + 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 Config $config 上传配置 + * @param string $params 自定义变量,规格参考 + * https://developer.qiniu.com/kodo/manual/1235/vars#xvar + * @param string $mime 上传数据的mimeType + * + * @return array 包含已上传文件的信息,类似: + * [ + * "hash" => "", + * "key" => "" + * ] + */ + public static function putFile( + $upToken, + $key, + $filePath, + $config, + $params, + $mime, + $reqOpt = null + ) { + if ($reqOpt == null) { + $reqOpt = new RequestOptions(); + } + + $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); + } + + list($upHost, $err) = $config->getUpHostV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + return array(null, $err); + } + + $response = Client::post($upHost, $fields, $headers, $reqOpt); + 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; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Storage/ResumeUploader.php b/vendor/qiniu/php-sdk/src/Qiniu/Storage/ResumeUploader.php new file mode 100644 index 0000000..00e88ef --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Storage/ResumeUploader.php @@ -0,0 +1,580 @@ + $params 自定义变量 + * @param string $mime 上传数据的mimeType + * @param Config $config + * @param string $resumeRecordFile 断点续传的已上传的部分信息记录文件 + * @param string $version 分片上传版本 目前支持v1/v2版本 默认v1 + * @param int $partSize 分片上传v2字段 默认大小为4MB 分片大小范围为1 MB - 1 GB + * @param RequestOptions $reqOpt 分片上传v2字段 默认大小为4MB 分片大小范围为1 MB - 1 GB + * @throws \Exception + * + * @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, + $reqOpt = null + ) { + + $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->partSize = $partSize ? $partSize : config::BLOCK_SIZE; + + if ($reqOpt === null) { + $reqOpt = new RequestOptions(); + } + $this->reqOpt = $reqOpt; + + try { + $this->version = SplitUploadVersion::from($version ? $version : 'v1'); + } catch (\Exception $e) { + throw new \Exception("only support v1/v2 now!", 0, $e); + } + + list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken); + $this->bucket = $bucket; + if ($err != null) { + return array(null, $err); + } + + list($upHost, $err) = $config->getUpHostV2($accessKey, $bucket, $reqOpt); + if ($err != null) { + throw new \Exception($err->message(), 1); + } + $this->host = $upHost; + } + + /** + * 上传操作 + * @param $fname string 文件名 + * + * @throws \Exception + */ + public function upload($fname) + { + $blkputRets = null; + // get upload record from resumeRecordFile + if ($this->resumeRecordFile != 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 ($this->version == SplitUploadVersion::V1) { + return $this->uploadV1($fname, $blkputRets); + } elseif ($this->version == SplitUploadVersion::V2) { + return $this->uploadV2($fname, $blkputRets); + } else { + throw new \Exception("only support v1/v2 now!"); + } + } + + /** + * @param string $fname 文件名 + * @param null|array $blkputRets + * + * @throws \Exception + */ + private function uploadV1($fname, $blkputRets = null) + { + // 尝试恢复恢复已上传的数据 + $isResumeUpload = $blkputRets !== null; + $this->contexts = array(); + + if ($blkputRets) { + if (isset($blkputRets['contexts']) && isset($blkputRets['uploaded']) && + is_array($blkputRets['contexts']) && is_int($blkputRets['uploaded']) + ) { + $this->contexts = array_map(function ($ctx) { + if (is_array($ctx)) { + return $ctx; + } else { + // 兼容旧版本(旧版本没有存储 expireAt) + return array( + "ctx" => $ctx, + "expiredAt" => 0, + ); + } + }, $blkputRets['contexts']); + } + } + + // 上传分片 + $uploaded = 0; + while ($uploaded < $this->size) { + $blockSize = $this->blockSize($uploaded); + $blockIndex = $uploaded / $this->partSize; + if (!is_int($blockIndex)) { + throw new \Exception("v1 part size changed"); + } + // 如果已上传该分片且没有过期 + if (isset($this->contexts[$blockIndex]) && $this->contexts[$blockIndex]["expiredAt"] >= time()) { + $uploaded += $blockSize; + fseek($this->inputStream, $blockSize, SEEK_CUR); + continue; + } + $data = fread($this->inputStream, $blockSize); + if ($data === false) { + throw new \Exception("file read failed", 1); + } + $crc = \Qiniu\crc32_data($data); + $response = $this->makeBlock($data, $blockSize); + + + $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); + } + list($upHostBackup, $err) = $this->config->getUpBackupHostV2($accessKey, $bucket, $this->reqOpt); + if ($err != null) { + return array(null, $err); + } + $this->host = $upHostBackup; + } + + 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)); + } + + // 如果可以在已上传取到说明是过期分片直接修改已上传信息,否则是新的片添加到已上传分片尾部 + if (isset($this->contexts[$blockIndex])) { + $this->contexts[$blockIndex] = array( + 'ctx' => $ret['ctx'], + 'expiredAt' => $ret['expired_at'], + ); + } else { + array_push($this->contexts, array( + 'ctx' => $ret['ctx'], + 'expiredAt' => $ret['expired_at'], + )); + } + $uploaded += $blockSize; + + // 记录断点 + if ($this->resumeRecordFile !== null) { + $recordData = array( + 'contexts' => $this->contexts, + 'uploaded' => $uploaded + ); + $recordData = json_encode($recordData); + + if ($recordData) { + $isWritten = file_put_contents($this->resumeRecordFile, $recordData); + if ($isWritten === false) { + error_log("write resumeRecordFile failed"); + } + } else { + error_log('resumeRecordData encode failed'); + } + } + } + + // 完成上传 + list($ret, $err) = $this->makeFile($fname); + if ($err !== null) { + $response = $err->getResponse(); + if ($isResumeUpload && $response->statusCode === 701) { + fseek($this->inputStream, 0); + return $this->uploadV1($fname); + } + } + return array($ret, $err); + } + + /** + * @param string $fname 文件名 + * @param null|array $blkputRets + * + * @throws \Exception + */ + private function uploadV2($fname, $blkputRets = null) + { + $uploaded = 0; + $partNumber = 1; + $encodedObjectName = $this->key ? \Qiniu\base64_urlSafeEncode($this->key) : '~'; + $isResumeUpload = $blkputRets !== null; + + // 初始化 upload id + $err = null; + if ($blkputRets) { + 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 { + $err = $this->makeInitReq($encodedObjectName); + } + } else { + $err = $this->makeInitReq($encodedObjectName); + } + if ($err != null) { + return array(null, $err); + } + + // 上传分片 + fseek($this->inputStream, $uploaded); + while ($uploaded < $this->size) { + $blockSize = $this->blockSize($uploaded); + $data = fread($this->inputStream, $blockSize); + if ($data === false) { + throw new \Exception("file read failed", 1); + } + $md5 = md5($data); + $response = $this->uploadPart( + $data, + $partNumber, + $this->finishedEtags["uploadId"], + $encodedObjectName, + $md5 + ); + + $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); + } + list($upHostBackup, $err) = $this->config->getUpBackupHostV2($accessKey, $bucket, $this->reqOpt); + if ($err != null) { + return array(null, $err); + } + $this->host = $upHostBackup; + } + + if ($response->needRetry() || !isset($ret['md5']) || $md5 != $ret['md5']) { + $response = $this->uploadPart( + $data, + $partNumber, + $this->finishedEtags["uploadId"], + $encodedObjectName, + $md5 + ); + $ret = $response->json(); + } + if ($isResumeUpload && $response->statusCode === 612) { + return $this->uploadV2($fname); + } + 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; + $this->finishedEtags['uploaded'] = $uploaded; + + if ($this->resumeRecordFile !== null) { + $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'); + } + } + } + + list($ret, $err) = $this->completeParts($fname, $this->finishedEtags['uploadId'], $encodedObjectName); + if ($err !== null) { + $response = $err->getResponse(); + if ($isResumeUpload && $response->statusCode === 612) { + return $this->uploadV2($fname); + } + } + return array($ret, $err); + } + + /** + * 创建块 + */ + 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; + } + + /** + * 创建文件 + * + * @param string $fname 文件名 + * @return array{array | null, Error | null} + */ + private function makeFile($fname) + { + $url = $this->fileUrl($fname); + $body = implode(',', array_map(function ($ctx) { + return $ctx['ctx']; + }, $this->contexts)); + $response = $this->post($url, $body); + if ($response->needRetry()) { + $response = $this->post($url, $body); + } + if ($response->statusCode === 200 || $response->statusCode === 701) { + if ($this->resumeRecordFile !== null) { + @unlink($this->resumeRecordFile); + } + } + 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, $this->reqOpt); + } + + private function blockSize($uploaded) + { + if ($this->size < $uploaded + $this->partSize) { + return $this->size - $uploaded; + } + return $this->partSize; + } + + private function makeInitReq($encodedObjectName) + { + list($ret, $err) = $this->initReq($encodedObjectName); + + if ($ret == null) { + return $err; + } + + $this->finishedEtags["uploadId"] = $ret['uploadId']; + $this->finishedEtags["expiredAt"] = $ret['expireAt']; + return $err; + } + + /** + * 初始化上传任务 + */ + 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); + $ret = $response->json(); + if ($response->ok() && $ret != null) { + return array($ret, null); + } + + return array(null, new Error($url, $response)); + } + + /** + * 分块上传v2 + */ + private function uploadPart($block, $partNumber, $uploadId, $encodedObjectName, $md5) + { + $headers = array( + 'Authorization' => 'UpToken ' . $this->upToken, + 'Content-Type' => 'application/octet-stream', + 'Content-MD5' => $md5 + ); + $url = $this->host . '/buckets/' . $this->bucket . '/objects/' . $encodedObjectName . + '/uploads/' . $uploadId . '/' . $partNumber; + $response = $this->put($url, $block, $headers); + if ($response->statusCode === 612) { + if ($this->resumeRecordFile !== null) { + @unlink($this->resumeRecordFile); + } + } + return $response; + } + + /** + * 完成分片上传V2 + * + * @param string $fname 文件名 + * @param int $uploadId 由 {@see initReq} 获取 + * @param string $encodedObjectName 经过编码的存储路径 + * @return array{array | null, Error | null} + */ + 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'); + $metadata = array(); + $customVars = array(); + if ($this->params) { + foreach ($this->params as $k => $v) { + if (strpos($k, 'x:') === 0) { + $customVars[$k] = $v; + } elseif (strpos($k, 'x-qn-meta-') === 0) { + $metadata[$k] = $v; + } + } + } + if (empty($metadata)) { + $metadata = null; + } + if (empty($customVars)) { + $customVars = null; + } + $body = array( + 'fname' => $fname, + 'mimeType' => $this->mime, + 'metadata' => $metadata, + 'customVars' => $customVars, + '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->statusCode === 200 || $response->statusCode === 612) { + if ($this->resumeRecordFile !== null) { + @unlink($this->resumeRecordFile); + } + } + 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, $this->reqOpt); + } + + private function postWithHeaders($url, $data, $headers) + { + $this->currentUrl = $url; + return Client::post($url, $data, $headers, $this->reqOpt); + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Storage/UploadManager.php b/vendor/qiniu/php-sdk/src/Qiniu/Storage/UploadManager.php new file mode 100644 index 0000000..fcd11fa --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Storage/UploadManager.php @@ -0,0 +1,176 @@ +config = $config; + + if ($reqOpt === null) { + $reqOpt = new RequestOptions(); + } + + $this->reqOpt = $reqOpt; + } + + /** + * 上传二进制流到七牛 + * + * @param string $upToken 上传凭证 + * @param string $key 上传文件名 + * @param string $data 上传二进制流 + * @param array $params 自定义变量,规格参考 + * http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar + * @param string $mime 上传数据的mimeType + * @param string $fname + * @param RequestOptions $reqOpt + * @return array 包含已上传文件的信息,类似: + * [ + * "hash" => "", + * "key" => "" + * ] + */ + public function put( + $upToken, + $key, + $data, + $params = null, + $mime = 'application/octet-stream', + $fname = "default_filename", + $reqOpt = null + ) { + $reqOpt = $reqOpt === null ? $this->reqOpt : $reqOpt; + + $params = self::trimParams($params); + return FormUploader::put( + $upToken, + $key, + $data, + $this->config, + $params, + $mime, + $fname, + $reqOpt + ); + } + + + /** + * 上传文件到七牛 + * + * @param string $upToken 上传凭证 + * @param string $key 上传文件名 + * @param string $filePath 上传文件的路径 + * @param array $params 定义变量,规格参考 + * http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar + * @param boolean $mime 上传数据的mimeType + * @param string $checkCrc 是否校验crc32 + * @param string $resumeRecordFile 断点续传文件路径 默认为null + * @param string $version 分片上传版本 目前支持v1/v2版本 默认v1 + * @param int $partSize 分片上传v2字段 默认大小为4MB 分片大小范围为1 MB - 1 GB + * + * @return array 包含已上传文件的信息,类似: + * [ + * "hash" => "", + * "key" => "" + * ] + * @throws \Exception + */ + public function putFile( + $upToken, + $key, + $filePath, + $params = null, + $mime = 'application/octet-stream', + $checkCrc = false, + $resumeRecordFile = null, + $version = 'v1', + $partSize = config::BLOCK_SIZE, + $reqOpt = null + ) { + $reqOpt = $reqOpt === null ? $this->reqOpt : $reqOpt; + + $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), + $reqOpt + ); + } + + $up = new ResumeUploader( + $upToken, + $key, + $file, + $size, + $params, + $mime, + $this->config, + $resumeRecordFile, + $version, + $partSize, + $reqOpt + ); + $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; + } +} diff --git a/vendor/qiniu/php-sdk/src/Qiniu/Zone.php b/vendor/qiniu/php-sdk/src/Qiniu/Zone.php new file mode 100644 index 0000000..50d60c6 --- /dev/null +++ b/vendor/qiniu/php-sdk/src/Qiniu/Zone.php @@ -0,0 +1,58 @@ + $v) { + $keysValue[$k] = $v[$key]; + } + array_multisort($keysValue, $sort, $array); + return $array; + } + + /** + * Wrapper for JSON decode that implements error detection with helpful + * error messages. + * + * @param string $json JSON data to parse + * @param bool $assoc When true, returned objects will be converted + * into associative arrays. + * @param int $depth User specified recursion depth. + * + * @return mixed + * @throws \InvalidArgumentException if the JSON cannot be parsed. + * @link http://www.php.net/manual/en/function.json-decode.php + */ + function json_decode($json, $assoc = false, $depth = 512) + { + static $jsonErrors = array( + JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded', + JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch', + JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found', + JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON', + JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded' + ); + + if (empty($json)) { + return null; + } + $data = \json_decode($json, $assoc, $depth); + + if (JSON_ERROR_NONE !== json_last_error()) { + $last = json_last_error(); + throw new \InvalidArgumentException( + 'Unable to parse JSON data: ' + . (isset($jsonErrors[$last]) + ? $jsonErrors[$last] + : 'Unknown error') + ); + } + + return $data; + } + + /** + * 计算七牛API中的数据格式 + * + * @param string $bucket 待操作的空间名 + * @param string $key 待操作的文件名 + * + * @return string 符合七牛API规格的数据格式 + * @link https://developer.qiniu.com/kodo/api/data-format + */ + function entry($bucket, $key = null) + { + $en = $bucket; + if ($key !== null) { + $en = $bucket . ':' . $key; + } + return base64_urlSafeEncode($en); + } + + function decodeEntry($entry) + { + $en = base64_urlSafeDecode($entry); + $en = explode(':', $en); + if (count($en) == 1) { + return array($en[0], null); + } + return array($en[0], $en[1]); + } + + /** + * array 辅助方法,无值时不set + * + * @param array $array 待操作array + * @param string $key key + * @param string $value value 为null时 不设置 + * + * @return array 原来的array,便于连续操作 + */ + function setWithoutEmpty(&$array, $key, $value) + { + if (!empty($value)) { + $array[$key] = $value; + } + return $array; + } + + /** + * 缩略图链接拼接 + * + * @param string $url 图片链接 + * @param int $mode 缩略模式 + * @param int $width 宽度 + * @param int $height 长度 + * @param string $format 输出类型 + * @param int $quality 图片质量 + * @param int $interlace 是否支持渐进显示 + * @param int $ignoreError 忽略结果 + * @return string + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/imageview2.html + * @author Sherlock Ren + */ + function thumbnail( + $url, + $mode, + $width, + $height, + $format = null, + $quality = null, + $interlace = null, + $ignoreError = 1 + ) { + + static $imageUrlBuilder = null; + if (is_null($imageUrlBuilder)) { + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder; + } + + return call_user_func_array(array($imageUrlBuilder, 'thumbnail'), func_get_args()); + } + + /** + * 图片水印 + * + * @param string $url 图片链接 + * @param string $image 水印图片链接 + * @param numeric $dissolve 透明度 + * @param string $gravity 水印位置 + * @param numeric $dx 横轴边距 + * @param numeric $dy 纵轴边距 + * @param numeric $watermarkScale 自适应原图的短边比例 + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html + * @return string + * @author Sherlock Ren + */ + function waterImg( + $url, + $image, + $dissolve = 100, + $gravity = 'SouthEast', + $dx = null, + $dy = null, + $watermarkScale = null + ) { + + static $imageUrlBuilder = null; + if (is_null($imageUrlBuilder)) { + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder; + } + + return call_user_func_array(array($imageUrlBuilder, 'waterImg'), func_get_args()); + } + + /** + * 文字水印 + * + * @param string $url 图片链接 + * @param string $text 文字 + * @param string $font 文字字体 + * @param string $fontSize 文字字号 + * @param string $fontColor 文字颜色 + * @param numeric $dissolve 透明度 + * @param string $gravity 水印位置 + * @param numeric $dx 横轴边距 + * @param numeric $dy 纵轴边距 + * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html#text-watermark + * @return string + * @author Sherlock Ren + */ + function waterText( + $url, + $text, + $font = '黑体', + $fontSize = 0, + $fontColor = null, + $dissolve = 100, + $gravity = 'SouthEast', + $dx = null, + $dy = null + ) { + + static $imageUrlBuilder = null; + if (is_null($imageUrlBuilder)) { + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder; + } + + return call_user_func_array(array($imageUrlBuilder, 'waterText'), func_get_args()); + } + + /** + * 从uptoken解析accessKey和bucket + * + * @param $upToken + * @return array(ak,bucket,err=null) + */ + function explodeUpToken($upToken) + { + $items = explode(':', $upToken); + if (count($items) != 3) { + return array(null, null, "invalid uptoken"); + } + $accessKey = $items[0]; + $putPolicy = json_decode(base64_urlSafeDecode($items[2])); + $scope = $putPolicy->scope; + $scopeItems = explode(':', $scope); + $bucket = $scopeItems[0]; + return array($accessKey, $bucket, null); + } + + // polyfill ucwords for `php version < 5.4.32` or `5.5.0 <= php version < 5.5.16` + if (version_compare(phpversion(), "5.4.32") < 0 || + ( + version_compare(phpversion(), "5.5.0") >= 0 && + version_compare(phpversion(), "5.5.16") < 0 + ) + ) { + function ucwords($str, $delimiters = " \t\r\n\f\v") + { + $delims = preg_split('//u', $delimiters, -1, PREG_SPLIT_NO_EMPTY); + + foreach ($delims as $delim) { + $str = implode($delim, array_map('ucfirst', explode($delim, $str))); + } + + return $str; + } + } else { + function ucwords($str, $delimiters) + { + return \ucwords($str, $delimiters); + } + } + + /** + * 将 parse_url 的结果转换回字符串 + * TODO: add unit test + * + * @param $parsed_url - parse_url 的结果 + * @return string + */ + function unparse_url($parsed_url) + { + + $scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : ''; + + $host = isset($parsed_url['host']) ? $parsed_url['host'] : ''; + + $port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : ''; + + $user = isset($parsed_url['user']) ? $parsed_url['user'] : ''; + + $pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : ''; + + $pass = ($user || $pass) ? "$pass@" : ''; + + $path = isset($parsed_url['path']) ? $parsed_url['path'] : ''; + + $query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : ''; + + $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : ''; + + return "$scheme$user$pass$host$port$path$query$fragment"; + } +} diff --git a/vendor/qiniu/php-sdk/test-env.sh b/vendor/qiniu/php-sdk/test-env.sh new file mode 100644 index 0000000..eedf6b5 --- /dev/null +++ b/vendor/qiniu/php-sdk/test-env.sh @@ -0,0 +1,4 @@ +export QINIU_ACCESS_KEY=xxx +export QINIU_SECRET_KEY=xxx +export QINIU_TEST_BUCKET=phpsdk +export QINIU_TEST_DOMAIN=phpsdk.qiniudn.com \ No newline at end of file diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/AuthTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/AuthTest.php new file mode 100644 index 0000000..99aec85 --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/AuthTest.php @@ -0,0 +1,296 @@ +sign('test'); + $this->assertEquals('abcdefghklmnopq:mSNBTR7uS2crJsyFr2Amwv1LaYg=', $token); + } + + public function testSignWithData() + { + global $dummyAuth; + $token = $dummyAuth->signWithData('test'); + $this->assertEquals('abcdefghklmnopq:-jP8eEV9v48MkYiBGs81aDxl60E=:dGVzdA==', $token); + } + + public function testSignRequest() + { + global $dummyAuth; + $token = $dummyAuth->signRequest('http://www.qiniu.com?go=1', 'test', ''); + $this->assertEquals('abcdefghklmnopq:cFyRVoWrE3IugPIMP5YJFTO-O-Y=', $token); + $ctype = 'application/x-www-form-urlencoded'; + $token = $dummyAuth->signRequest('http://www.qiniu.com?go=1', 'test', $ctype); + $this->assertEquals($token, 'abcdefghklmnopq:svWRNcacOE-YMsc70nuIYdaa1e4='); + } + + public function testPrivateDownloadUrl() + { + global $dummyAuth; + $_SERVER['override_qiniu_auth_time'] = true; + $url = $dummyAuth->privateDownloadUrl('http://www.qiniu.com?go=1'); + $expect = 'http://www.qiniu.com?go=1&e=1234571490&token=abcdefghklmnopq:8vzBeLZ9W3E4kbBLFLW0Xe0u7v4='; + $this->assertEquals($expect, $url); + unset($_SERVER['override_qiniu_auth_time']); + } + + public function testUploadToken() + { + global $dummyAuth; + $_SERVER['override_qiniu_auth_time'] = true; + $token = $dummyAuth->uploadToken('1', '2', 3600, array('endUser' => 'y')); + // @codingStandardsIgnoreStart + $exp = 'abcdefghklmnopq:yyeexeUkPOROoTGvwBjJ0F0VLEo=:eyJlbmRVc2VyIjoieSIsInNjb3BlIjoiMToyIiwiZGVhZGxpbmUiOjEyMzQ1NzE0OTB9'; + // @codingStandardsIgnoreEnd + $this->assertEquals($exp, $token); + unset($_SERVER['override_qiniu_auth_time']); + } + + public function testSignQiniuAuthorization() + { + $auth = new Auth("ak", "sk"); + + $testCases = array( + array( + "url" => "", + "method" => "", + "headers" => array( + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + "Content-Type" => array("application/x-www-form-urlencoded") + ), + "body" => "{\"name\": \"test\"}", + "expectedToken" => "ak:0i1vKClRDWFyNkcTFzwcE7PzX74=" + ), + array( + "url" => "", + "method" => "", + "headers" => array( + "Content-Type" => array("application/json") + ), + "body" => "{\"name\": \"test\"}", + "expectedToken" => "ak:K1DI0goT05yhGizDFE5FiPJxAj4=" + ), + array( + "url" => "", + "method" => "GET", + "headers" => array( + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + "Content-Type" => array("application/x-www-form-urlencoded"), + ), + "body" => "{\"name\": \"test\"}", + "expectedToken" => "ak:0i1vKClRDWFyNkcTFzwcE7PzX74=" + ), + array( + "url" => "", + "method" => "POST", + "headers" => array( + "Content-Type" => array("application/json"), + "X-Qiniu" => array("b"), + ), + "body" => "{\"name\": \"test\"}", + "expectedToken" => "ak:0ujEjW_vLRZxebsveBgqa3JyQ-w=" + ), + array( + "url" => "http://upload.qiniup.com", + "method" => "", + "headers" => array( + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + "Content-Type" => array("application/x-www-form-urlencoded"), + ), + "body" => "{\"name\": \"test\"}", + "expectedToken" => "ak:GShw5NitGmd5TLoo38nDkGUofRw=" + ), + array( + "url" => "http://upload.qiniup.com", + "method" => "", + "headers" => array( + "Content-Type" => array("application/json"), + "X-Qiniu-Bbb" => array("BBB", "AAA"), + "X-Qiniu-Aaa" => array("DDD", "CCC"), + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + ), + "body" => "{\"name\": \"test\"}", + "expectedToken" => "ak:DhNA1UCaBqSHCsQjMOLRfVn63GQ=" + ), + array( + "url" => "http://upload.qiniup.com", + "method" => "", + "headers" => array( + "Content-Type" => array("application/x-www-form-urlencoded"), + "X-Qiniu-Bbb" => array("BBB", "AAA"), + "X-Qiniu-Aaa" => array("DDD", "CCC"), + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + ), + "body" => "name=test&language=go", + "expectedToken" => "ak:KUAhrYh32P9bv0COD8ugZjDCmII=" + ), + array( + "url" => "http://upload.qiniup.com", + "method" => "", + "headers" => array( + "Content-Type" => array("application/x-www"), + "Content-Type" => array("application/x-www-form-urlencoded"), + "X-Qiniu-Bbb" => array("BBB", "AAA"), + "X-Qiniu-Aaa" => array("DDD", "CCC"), + ), + "body" => "name=test&language=go", + "expectedToken" => "ak:KUAhrYh32P9bv0COD8ugZjDCmII=" + ), + array( + "url" => "http://upload.qiniup.com/mkfile/sdf.jpg", + "method" => "", + "headers" => array( + "Content-Type" => array("application/x-www-form-urlencoded"), + "X-Qiniu-Bbb" => array("BBB", "AAA"), + "X-Qiniu-Aaa" => array("DDD", "CCC"), + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + ), + "body" => "name=test&language=go", + "expectedToken" => "ak:fkRck5_LeyfwdkyyLk-hyNwGKac=" + ), + array( + "url" => "http://upload.qiniup.com/mkfile/sdf.jpg?s=er3&df", + "method" => "", + "headers" => array( + "Content-Type" => array("application/x-www-form-urlencoded"), + "X-Qiniu-Bbb" => array("BBB", "AAA"), + "X-Qiniu-Aaa" => array("DDD", "CCC"), + "X-Qiniu-" => array("a"), + "X-Qiniu" => array("b"), + ), + "body" => "name=test&language=go", + "expectedToken" => "ak:PUFPWsEUIpk_dzUvvxTTmwhp3p4=" + ) + ); + + foreach ($testCases as $testCase) { + list($sign, $err) = $auth->signQiniuAuthorization( + $testCase["url"], + $testCase["method"], + $testCase["body"], + new Header($testCase["headers"]) + ); + + $this->assertNull($err); + $this->assertEquals($testCase["expectedToken"], $sign); + } + } + + public function testDisableQiniuTimestampSignatureDefault() + { + $auth = new Auth("ak", "sk"); + $authedHeaders = $auth->authorizationV2("https://example.com", "GET"); + $this->assertArrayHasKey("X-Qiniu-Date", $authedHeaders); + } + + public function testDisableQiniuTimestampSignature() + { + $auth = new Auth("ak", "sk", array( + "disableQiniuTimestampSignature" => true + )); + $authedHeaders = $auth->authorizationV2("https://example.com", "GET"); + $this->assertArrayNotHasKey("X-Qiniu-Date", $authedHeaders); + } + public function testDisableQiniuTimestampSignatureEnv() + { + putenv("DISABLE_QINIU_TIMESTAMP_SIGNATURE=true"); + $auth = new Auth("ak", "sk"); + $authedHeaders = $auth->authorizationV2("https://example.com", "GET"); + $this->assertArrayNotHasKey("X-Qiniu-Date", $authedHeaders); + putenv('DISABLE_QINIU_TIMESTAMP_SIGNATURE'); + } + public function testDisableQiniuTimestampSignatureEnvBeIgnored() + { + putenv("DISABLE_QINIU_TIMESTAMP_SIGNATURE=true"); + $auth = new Auth("ak", "sk", array( + "disableQiniuTimestampSignature" => false + )); + $authedHeaders = $auth->authorizationV2("https://example.com", "GET"); + $this->assertArrayHasKey("X-Qiniu-Date", $authedHeaders); + putenv('DISABLE_QINIU_TIMESTAMP_SIGNATURE'); + } + public function testQboxVerifyCallbackShouldOkWithRequiredOptions() + { + $auth = new Auth('abcdefghklmnopq', '1234567890'); + $ok = $auth->verifyCallback( + 'application/x-www-form-urlencoded', + 'QBox abcdefghklmnopq:T7F-SjxX7X2zI4Fc1vANiNt1AUE=', + 'https://test.qiniu.com/callback', + 'name=sunflower.jpg&hash=Fn6qeQi4VDLQ347NiRm-RlQx_4O2&location=Shanghai&price=1500.00&uid=123' + ); + $this->assertTrue($ok); + } + public function testQboxVerifyCallbackShouldOkWithOmitOptions() + { + $auth = new Auth('abcdefghklmnopq', '1234567890'); + $ok = $auth->verifyCallback( + 'application/x-www-form-urlencoded', + 'QBox abcdefghklmnopq:T7F-SjxX7X2zI4Fc1vANiNt1AUE=', + 'https://test.qiniu.com/callback', + 'name=sunflower.jpg&hash=Fn6qeQi4VDLQ347NiRm-RlQx_4O2&location=Shanghai&price=1500.00&uid=123', + 'POST', // this should be omit + array( + 'X-Qiniu-Bbb' => 'BBB' + ) // this should be omit + ); + $this->assertTrue($ok); + } + public function testQiniuVerifyCallbackShouldOk() + { + $auth = new Auth('abcdefghklmnopq', '1234567890'); + $ok = $auth->verifyCallback( + 'application/x-www-form-urlencoded', + 'Qiniu abcdefghklmnopq:ZqS7EZuAKrhZaEIxqNGxDJi41IQ=', + 'https://test.qiniu.com/callback', + 'name=sunflower.jpg&hash=Fn6qeQi4VDLQ347NiRm-RlQx_4O2&location=Shanghai&price=1500.00&uid=123', + 'GET', + array( + 'X-Qiniu-Bbb' => 'BBB' + ) + ); + $this->assertTrue($ok); + } + public function testQiniuVerifyCallbackShouldFailed() + { + $auth = new Auth('abcdefghklmnopq', '1234567890'); + $ok = $auth->verifyCallback( + 'application/x-www-form-urlencoded', + 'Qiniu abcdefghklmnopq:ZqS7EZuAKrhZaEIxqNGxDJi41IQ=', + 'https://test.qiniu.com/callback', + 'name=sunflower.jpg&hash=Fn6qeQi4VDLQ347NiRm-RlQx_4O2&location=Shanghai&price=1500.00&uid=123', + 'POST', + array( + 'X-Qiniu-Bbb' => 'BBB' + ) + ); + $this->assertFalse($ok); + } + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/Base64Test.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/Base64Test.php new file mode 100644 index 0000000..fed3da0 --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/Base64Test.php @@ -0,0 +1,16 @@ +assertEquals($a, \Qiniu\base64_urlSafeDecode($b)); + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/BucketTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/BucketTest.php new file mode 100644 index 0000000..0467698 --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/BucketTest.php @@ -0,0 +1,733 @@ +batch($ops); + } + + private static function getObjectKey($key) + { + $result = $key . rand(); + + self::$bucketManager->copy( + self::$bucketName, + $key, + self::$bucketName, + $result + ); + + self::$keysToCleanup[] = $result; + + return $result; + } + + public function testBuckets() + { + + list($list, $error) = self::$bucketManager->buckets(); + $this->assertNull($error); + $this->assertTrue(in_array(self::$bucketName, $list)); + + list($list2, $error) = self::$dummyBucketManager->buckets(); + $this->assertEquals(401, $error->code()); + $this->assertNotNull($error->message()); + $this->assertNotNull($error->getResponse()); + $this->assertNull($list2); + } + + public function testListBuckets() + { + list($ret, $error) = self::$bucketManager->listbuckets('z0'); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testCreateBucket() + { + list($ret, $error) = self::$bucketManager->createBucket(self::$bucketToCreate); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testDeleteBucket() + { + list($ret, $error) = self::$bucketManager->deleteBucket(self::$bucketToCreate); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testDomains() + { + list($ret, $error) = self::$bucketManager->domains(self::$bucketName); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testBucketInfo() + { + list($ret, $error) = self::$bucketManager->bucketInfo(self::$bucketName); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testBucketInfos() + { + list($ret, $error) = self::$bucketManager->bucketInfos('z0'); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testList() + { + list($ret, $error) = self::$bucketManager->listFiles(self::$bucketName, null, null, 10); + $this->assertNull($error); + $this->assertNotNull($ret['items'][0]); + $this->assertNotNull($ret['marker']); + } + + public function testListFilesv2() + { + list($ret, $error) = self::$bucketManager->listFilesv2(self::$bucketName, null, null, 10); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testBucketLifecycleRule() + { + // delete + self::$bucketManager->deleteBucketLifecycleRule(self::$bucketName, self::$bucketLifeRuleName); + + // add + list($ret, $error) = self::$bucketManager->bucketLifecycleRule( + self::$bucketName, + self::$bucketLifeRuleName, + self::$bucketLifeRulePrefix, + 80, + 70, + 72, + 74, + 71 + ); + $this->assertNull($error); + $this->assertNotNull($ret); + + // get + list($ret, $error) = self::$bucketManager->getBucketLifecycleRules(self::$bucketName); + $this->assertNull($error); + $this->assertNotNull($ret); + $rule = null; + foreach ($ret as $r) { + if ($r["name"] === self::$bucketLifeRuleName) { + $rule = $r; + break; + } + } + $this->assertNotNull($rule); + $this->assertEquals(self::$bucketLifeRulePrefix, $rule["prefix"]); + $this->assertEquals(80, $rule["delete_after_days"]); + $this->assertEquals(70, $rule["to_line_after_days"]); + $this->assertEquals(71, $rule["to_archive_ir_after_days"]); + $this->assertEquals(72, $rule["to_archive_after_days"]); + $this->assertEquals(74, $rule["to_deep_archive_after_days"]); + + // update + list($ret, $error) = self::$bucketManager->updateBucketLifecycleRule( + self::$bucketName, + self::$bucketLifeRuleName, + 'update-' . self::$bucketLifeRulePrefix, + 90, + 75, + 80, + 85, + 78 + ); + $this->assertNull($error); + $this->assertNotNull($ret); + + // get + list($ret, $error) = self::$bucketManager->getBucketLifecycleRules(self::$bucketName); + $this->assertNull($error); + $this->assertNotNull($ret); + $rule = null; + foreach ($ret as $r) { + if ($r["name"] === self::$bucketLifeRuleName) { + $rule = $r; + break; + } + } + $this->assertNotNull($rule); + $this->assertEquals('update-' . self::$bucketLifeRulePrefix, $rule["prefix"]); + $this->assertEquals(90, $rule["delete_after_days"]); + $this->assertEquals(75, $rule["to_line_after_days"]); + $this->assertEquals(78, $rule["to_archive_ir_after_days"]); + $this->assertEquals(80, $rule["to_archive_after_days"]); + $this->assertEquals(85, $rule["to_deep_archive_after_days"]); + + // delete + list($ret, $error) = self::$bucketManager->deleteBucketLifecycleRule( + self::$bucketName, + self::$bucketLifeRuleName + ); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testPutBucketEvent() + { + list($ret, $error) = self::$bucketManager->putBucketEvent( + self::$bucketName, + self::$bucketEventName, + self::$bucketEventPrefix, + 'img', + array('copy'), + self::$customCallbackURL + ); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testUpdateBucketEvent() + { + list($ret, $error) = self::$bucketManager->updateBucketEvent( + self::$bucketName, + self::$bucketEventName, + self::$bucketEventPrefix, + 'video', + array('copy'), + self::$customCallbackURL + ); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testGetBucketEvents() + { + list($ret, $error) = self::$bucketManager->getBucketEvents(self::$bucketName); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testDeleteBucketEvent() + { + list($ret, $error) = self::$bucketManager->deleteBucketEvent(self::$bucketName, self::$bucketEventName); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testStat() + { + list($stat, $error) = self::$bucketManager->stat(self::$bucketName, self::$key); + $this->assertNull($error); + $this->assertNotNull($stat); + $this->assertNotNull($stat['hash']); + + list($stat, $error) = self::$bucketManager->stat(self::$bucketName, 'nofile'); + $this->assertEquals(612, $error->code()); + $this->assertNotNull($error->message()); + $this->assertNull($stat); + + list($stat, $error) = self::$bucketManager->stat('nobucket', 'nofile'); + $this->assertEquals(631, $error->code()); + $this->assertNotNull($error->message()); + $this->assertNull($stat); + } + + public function testDelete() + { + $fileToDel = self::getObjectKey(self::$key); + list(, $error) = self::$bucketManager->delete(self::$bucketName, $fileToDel); + $this->assertNull($error); + } + + + public function testRename() + { + $fileToRename = self::getObjectKey(self::$key); + $fileRenamed = $fileToRename . 'new'; + list(, $error) = self::$bucketManager->rename(self::$bucketName, $fileToRename, $fileRenamed); + $this->assertNull($error); + self::$keysToCleanup[] = $fileRenamed; + } + + + public function testCopy() + { + $fileToCopy = self::getObjectKey(self::$key2); + $fileCopied = $fileToCopy . 'copied'; + + //test force copy + list(, $error) = self::$bucketManager->copy( + self::$bucketName, + $fileToCopy, + self::$bucketName, + $fileCopied, + true + ); + $this->assertNull($error); + + list($fileToCopyStat,) = self::$bucketManager->stat(self::$bucketName, $fileToCopy); + list($fileCopiedStat,) = self::$bucketManager->stat(self::$bucketName, $fileCopied); + + $this->assertEquals($fileToCopyStat['hash'], $fileCopiedStat['hash']); + + self::$keysToCleanup[] = $fileCopied; + } + + + public function testChangeMime() + { + $fileToChange = self::getObjectKey('php-sdk.html'); + list(, $error) = self::$bucketManager->changeMime( + self::$bucketName, + $fileToChange, + 'text/plain' + ); + $this->assertNull($error); + + list($ret, $error) = self::$bucketManager->stat( + self::$bucketName, + $fileToChange + ); + $this->assertNull($error); + $this->assertEquals('text/plain', $ret['mimeType']); + } + + public function testPrefetch() + { + list($ret, $error) = self::$bucketManager->prefetch( + self::$bucketName, + 'php-sdk.html' + ); + $this->assertNull($error); + $this->assertNotNull($ret); + } + + public function testPrefetchFailed() + { + list($ret, $error) = self::$bucketManager->prefetch( + 'fakebucket', + 'php-sdk.html' + ); + $this->assertNotNull($error); + $this->assertNull($ret); + } + + public function testFetch() + { + list($ret, $error) = self::$bucketManager->fetch( + 'http://developer.qiniu.com/docs/v6/sdk/php-sdk.html', + self::$bucketName, + 'fetch.html' + ); + $this->assertNull($error); + $this->assertArrayHasKey('hash', $ret); + + list($ret, $error) = self::$bucketManager->fetch( + 'http://developer.qiniu.com/docs/v6/sdk/php-sdk.html', + self::$bucketName, + '' + ); + $this->assertNull($error); + $this->assertArrayHasKey('key', $ret); + + list($ret, $error) = self::$bucketManager->fetch( + 'http://developer.qiniu.com/docs/v6/sdk/php-sdk.html', + self::$bucketName + ); + $this->assertNull($error); + $this->assertArrayHasKey('key', $ret); + } + + public function testFetchFailed() + { + list($ret, $error) = self::$bucketManager->fetch( + 'http://developer.qiniu.com/docs/v6/sdk/php-sdk.html', + 'fakebucket' + ); + $this->assertNotNull($error); + $this->assertNull($ret); + } + + public function testAsynchFetch() + { + list($ret, $error) = self::$bucketManager->asynchFetch( + 'http://devtools.qiniu.com/qiniu.png', + self::$bucketName, + null, + 'qiniu.png' + ); + $this->assertNull($error); + $this->assertArrayHasKey('id', $ret); + + list($ret, $error) = self::$bucketManager->asynchFetch( + 'http://devtools.qiniu.com/qiniu.png', + self::$bucketName, + null, + '' + ); + $this->assertNull($error); + $this->assertArrayHasKey('id', $ret); + + list($ret, $error) = self::$bucketManager->asynchFetch( + 'http://devtools.qiniu.com/qiniu.png', + self::$bucketName + ); + $this->assertNull($error); + $this->assertArrayHasKey('id', $ret); + } + + public function testAsynchFetchFailed() + { + list($ret, $error) = self::$bucketManager->asynchFetch( + 'http://devtools.qiniu.com/qiniu.png', + 'fakebucket' + ); + $this->assertNotNull($error); + $this->assertNull($ret); + } + + + public function testBatchCopy() + { + $key = 'copyto' . rand(); + $ops = BucketManager::buildBatchCopy( + self::$bucketName, + array(self::$key => $key), + self::$bucketName, + true + ); + list($ret, $error) = self::$bucketManager->batch($ops); + $this->assertNull($error); + $this->assertEquals(200, $ret[0]['code']); + + self::$keysToCleanup[] = $key; + } + + public function testBatchMove() + { + $fileToMove = self::getObjectKey(self::$key); + $fileMoved = $fileToMove . 'to'; + $ops = BucketManager::buildBatchMove( + self::$bucketName, + array($fileToMove => $fileMoved), + self::$bucketName, + true + ); + list($ret, $error) = self::$bucketManager->batch($ops); + $this->assertNull($error); + $this->assertEquals(200, $ret[0]['code']); + self::$keysToCleanup[] = $fileMoved; + } + + public function testBatchRename() + { + $fileToRename = self::getObjectKey(self::$key); + $fileRenamed = $fileToRename . 'to'; + + $ops = BucketManager::buildBatchRename( + self::$bucketName, + array($fileToRename => $fileRenamed), + true + ); + list($ret, $error) = self::$bucketManager->batch($ops); + $this->assertNull($error); + $this->assertEquals(200, $ret[0]['code']); + + self::$keysToCleanup[] = $fileRenamed; + } + + public function testBatchStat() + { + $ops = BucketManager::buildBatchStat(self::$bucketName, array('php-sdk.html')); + list($ret, $error) = self::$bucketManager->batch($ops); + $this->assertNull($error); + $this->assertEquals(200, $ret[0]['code']); + } + + public function testBatchChangeTypeAndBatchRestoreAr() + { + $key = self::getObjectKey(self::$key); + + $ops = BucketManager::buildBatchChangeType(self::$bucketName, array($key => 2)); // 2 Archive + list($ret, $error) = self::$bucketManager->batch($ops); + $this->assertNull($error); + $this->assertEquals(200, $ret[0]['code']); + + $ops = BucketManager::buildBatchRestoreAr(self::$bucketName, array($key => 1)); // 1 day + list($ret, $error) = self::$bucketManager->batch($ops); + $this->assertNull($error); + $this->assertEquals(200, $ret[0]['code']); + } + + public function testDeleteAfterDays() + { + $key = "noexist" . rand(); + list($ret, $error) = self::$bucketManager->deleteAfterDays(self::$bucketName, $key, 1); + $this->assertNotNull($error); + $this->assertNull($ret); + + $key = self::getObjectKey(self::$key); + list(, $error) = self::$bucketManager->deleteAfterDays(self::$bucketName, $key, 1); + $this->assertNull($error); + + list($ret, $error) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($error); + $this->assertGreaterThan(23 * 3600, $ret['expiration'] - time()); + $this->assertLessThan(48 * 3600, $ret['expiration'] - time()); + } + + public function testSetObjectLifecycle() + { + $key = self::getObjectKey(self::$key); + + list(, $err) = self::$bucketManager->setObjectLifecycle( + self::$bucketName, + $key, + 10, + 20, + 30, + 40, + 15 + ); + $this->assertNull($err); + + list($ret, $error) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($error); + $this->assertNotNull($ret['transitionToIA']); + $this->assertNotNull($ret['transitionToArchiveIR']); + $this->assertNotNull($ret['transitionToARCHIVE']); + $this->assertNotNull($ret['transitionToDeepArchive']); + $this->assertNotNull($ret['expiration']); + } + + public function testSetObjectLifecycleWithCond() + { + $key = self::getObjectKey(self::$key); + + list($ret, $err) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($err); + $key_hash = $ret['hash']; + $key_fsize = $ret['fsize']; + + list(, $err) = self::$bucketManager->setObjectLifecycleWithCond( + self::$bucketName, + $key, + array( + 'hash' => $key_hash, + 'fsize' => $key_fsize + ), + 10, + 20, + 30, + 40, + 15 + ); + $this->assertNull($err); + + list($ret, $error) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($error); + $this->assertNotNull($ret['transitionToIA']); + $this->assertNotNull($ret['transitionToArchiveIR']); + $this->assertNotNull($ret['transitionToARCHIVE']); + $this->assertNotNull($ret['transitionToDeepArchive']); + $this->assertNotNull($ret['expiration']); + } + + public function testBatchSetObjectLifecycle() + { + $key = self::getObjectKey(self::$key); + + $ops = BucketManager::buildBatchSetObjectLifecycle( + self::$bucketName, + array($key), + 10, + 20, + 30, + 40, + 15 + ); + list($ret, $err) = self::$bucketManager->batch($ops); + $this->assertNull($err); + $this->assertEquals(200, $ret[0]['code']); + } + + public function testGetCorsRules() + { + list(, $err) = self::$bucketManager->getCorsRules(self::$bucketName); + $this->assertNull($err); + } + + public function testPutBucketAccessStyleMode() + { + list(, $err) = self::$bucketManager->putBucketAccessStyleMode(self::$bucketName, 0); + $this->assertNull($err); + } + + public function testPutBucketAccessMode() + { + list(, $err) = self::$bucketManager->putBucketAccessMode(self::$bucketName, 0); + $this->assertNull($err); + } + + public function testPutReferAntiLeech() + { + list(, $err) = self::$bucketManager->putReferAntiLeech(self::$bucketName, 0, "1", "*"); + $this->assertNull($err); + } + + public function testPutBucketMaxAge() + { + list(, $err) = self::$bucketManager->putBucketMaxAge(self::$bucketName, 31536000); + $this->assertNull($err); + } + + public function testPutBucketQuota() + { + list(, $err) = self::$bucketManager->putBucketQuota(self::$bucketName, -1, -1); + $this->assertNull($err); + } + + public function testGetBucketQuota() + { + list(, $err) = self::$bucketManager->getBucketQuota(self::$bucketName); + $this->assertNull($err); + } + + public function testChangeType() + { + $fileToChange = self::getObjectKey(self::$key); + + list(, $err) = self::$bucketManager->changeType(self::$bucketName, $fileToChange, 0); + $this->assertNull($err); + + list(, $err) = self::$bucketManager->changeType(self::$bucketName, $fileToChange, 1); + $this->assertNull($err); + } + + public function testArchiveRestoreAr() + { + $key = self::getObjectKey(self::$key); + + self::$bucketManager->changeType(self::$bucketName, $key, 2); + + list(, $err) = self::$bucketManager->restoreAr(self::$bucketName, $key, 2); + $this->assertNull($err); + + list($ret, $err) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($err); + + $this->assertEquals(2, $ret["type"]); + + // restoreStatus + // null means frozen; + // 1 means be unfreezing; + // 2 means be unfrozen; + $this->assertNotNull($ret["restoreStatus"]); + $this->assertContains($ret["restoreStatus"], array(1, 2)); + } + + public function testDeepArchiveRestoreAr() + { + $key = self::getObjectKey(self::$key); + + self::$bucketManager->changeType(self::$bucketName, $key, 3); + + list(, $err) = self::$bucketManager->restoreAr(self::$bucketName, $key, 1); + $this->assertNull($err); + list($ret, $err) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($err); + + $this->assertEquals(3, $ret["type"]); + + // restoreStatus + // null means frozen; + // 1 means be unfreezing; + // 2 means be unfrozen; + $this->assertNotNull($ret["restoreStatus"]); + $this->assertContains($ret["restoreStatus"], array(1, 2)); + } + + public function testChangeStatus() + { + $key = self::getObjectKey(self::$key); + + list(, $err) = self::$bucketManager->changeStatus(self::$bucketName, $key, 1); + $this->assertNull($err); + list($ret, $err) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($err); + $this->assertEquals(1, $ret['status']); + + list(, $err) = self::$bucketManager->changeStatus(self::$bucketName, $key, 0); + $this->assertNull($err); + list($ret, $err) = self::$bucketManager->stat(self::$bucketName, $key); + $this->assertNull($err); + $this->assertArrayNotHasKey('status', $ret); + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/CdnManagerTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/CdnManagerTest.php new file mode 100644 index 0000000..baa9486 --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/CdnManagerTest.php @@ -0,0 +1,151 @@ +cdnManager = new CdnManager($testAuth); + + global $timestampAntiLeechEncryptKey; + $this->encryptKey = $timestampAntiLeechEncryptKey; + + global $testStartDate; + $this->testStartDate = $testStartDate; + + global $testEndDate; + $this->testEndDate = $testEndDate; + + global $testGranularity; + $this->testGranularity = $testGranularity; + + global $testLogDate; + $this->testLogDate = $testLogDate; + + global $customDomain; + $this->refreshUrl = $customDomain . '/sdktest.png'; + $this->refreshDirs = $customDomain; + $this->customDomain = $customDomain; + + global $customDomain2; + $this->customDomain2 = $customDomain2; + } + + public function testRefreshUrls() + { + list($ret, $err) = $this->cdnManager->refreshUrls(array($this->refreshUrl)); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testRefreshDirs() + { + list($ret, $err) = $this->cdnManager->refreshDirs(array($this->refreshDirs)); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testRefreshUrlsAndDirs() + { + list($ret, $err) = $this->cdnManager->refreshUrlsAndDirs(array($this->refreshUrl), array($this->refreshDirs)); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testGetCdnRefreshList() + { + list($ret, $err) = $this->cdnManager->getCdnRefreshList(null, null, null, 'success'); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testPrefetchUrls() + { + list($ret, $err) = $this->cdnManager->prefetchUrls(array($this->refreshUrl)); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testGetCdnPrefetchList() + { + list($ret, $err) = $this->cdnManager->getCdnPrefetchList(null, null, 'success'); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testGetBandwidthData() + { + list($ret, $err) = $this->cdnManager->getBandwidthData( + array($this->customDomain2), + $this->testStartDate, + $this->testEndDate, + $this->testGranularity + ); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testGetFluxData() + { + list($ret, $err) = $this->cdnManager->getFluxData( + array($this->customDomain2), + $this->testStartDate, + $this->testEndDate, + $this->testGranularity + ); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testGetCdnLogList() + { + $domain = getenv('QINIU_TEST_DOMAIN'); + list($ret, $err) = $this->cdnManager->getCdnLogList(array($domain), $this->testLogDate); + $this->assertNull($err); + $this->assertNotNull($ret); + } + + public function testCreateTimestampAntiLeechUrl() + { + $signUrl = $this->cdnManager->createTimestampAntiLeechUrl($this->refreshUrl, $this->encryptKey, 3600); + $response = Client::get($signUrl); + $this->assertNull($response->error); + $this->assertEquals($response->statusCode, 200); + + $signUrl = $this->cdnManager->createTimestampAntiLeechUrl( + $this->refreshUrl . '?qiniu', + $this->encryptKey, + 3600 + ); + $response = Client::get($signUrl); + $this->assertNull($response->error); + $this->assertEquals($response->statusCode, 200); + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/ConfigTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/ConfigTest.php new file mode 100644 index 0000000..3c39a5c --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/ConfigTest.php @@ -0,0 +1,118 @@ +accessKey = $accessKey; + global $bucketName; + $this->bucketName = $bucketName; + } + + public function testGetApiHost() + { + $conf = new Config(); + $hasException = false; + $apiHost = ''; + try { + $apiHost = $conf->getApiHost($this->accessKey, $this->bucketName); + } catch (\Exception $e) { + $hasException = true; + } + $this->assertFalse($hasException); + } + + public function testGetApiHostErrored() + { + $conf = new Config(); + $hasException = false; + try { + $conf->getApiHost($this->accessKey, "fakebucket"); + } catch (\Exception $e) { + $hasException = true; + } + $this->assertTrue($hasException); + } + + public function testGetApiHostV2() + { + $conf = new Config(); + list($apiHost, $err) = $conf->getApiHostV2($this->accessKey, $this->bucketName); + $this->assertNull($err); + } + + public function testGetApiHostV2Errored() + { + $conf = new Config(); + list($apiHost, $err) = $conf->getApiHostV2($this->accessKey, "fakebucket"); + $this->assertNotNull($err->code()); + $this->assertEquals(631, $err->code()); + $this->assertNull($apiHost); + } + + public function testSetUcHost() + { + $conf = new Config(); + $this->assertEquals('http://' . Config::UC_HOST, $conf->getUcHost()); + $conf->setUcHost("uc.example.com"); + $this->assertEquals("http://uc.example.com", $conf->getUcHost()); + + $conf = new Config(); + $conf->useHTTPS = true; + $this->assertEquals('https://' . Config::UC_HOST, $conf->getUcHost()); + $conf->setUcHost("uc.example.com"); + $this->assertEquals("https://uc.example.com", $conf->getUcHost()); + } + + public function testGetRegionWithCustomDomain() + { + $conf = new Config(); + $conf->setQueryRegionHost( + "uc.qbox.me" + ); + list(, $err) = $conf->getRsHostV2($this->accessKey, $this->bucketName); + $this->assertNull($err); + } + + public function testGetRegionWithBackupDomains() + { + $conf = new Config(); + $conf->setQueryRegionHost( + "fake-uc.phpsdk.qiniu.com", + array( + "unavailable-uc.phpsdk.qiniu.com", + Config::UC_HOST // real uc + ) + ); + list(, $err) = $conf->getRsHostV2($this->accessKey, $this->bucketName); + $this->assertNull($err); + } + + public function testGetRegionWithUcAndBackupDomains() + { + $conf = new Config(); + $conf->setUcHost("fake-uc.phpsdk.qiniu.com"); + $conf->setBackupQueryRegionHosts( + array( + "unavailable-uc.phpsdk.qiniu.com", + Config::UC_HOST // real uc + ) + ); + list(, $err) = $conf->getRsHostV2($this->accessKey, $this->bucketName); + $this->assertNull($err); + } + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/Crc32Test.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/Crc32Test.php new file mode 100644 index 0000000..63e24fd --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/Crc32Test.php @@ -0,0 +1,23 @@ +assertEquals('1352841281', $b); + } + + public function testFile() + { + $b = \Qiniu\crc32_file(__file__); + $c = \Qiniu\crc32_file(__file__); + $this->assertEquals($c, $b); + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/DownloadTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/DownloadTest.php new file mode 100644 index 0000000..9b4b034 --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/DownloadTest.php @@ -0,0 +1,27 @@ +privateDownloadUrl($base_url); + $response = Client::get($private_url); + $this->assertEquals(200, $response->statusCode); + } + + public function testFop() + { + global $testAuth; + $base_url = 'http://sdk.peterpy.cn/gogopher.jpg?exif'; + $private_url = $testAuth->privateDownloadUrl($base_url); + $response = Client::get($private_url); + $this->assertEquals(200, $response->statusCode); + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/EntryTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/EntryTest.php new file mode 100644 index 0000000..73bfac4 --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/EntryTest.php @@ -0,0 +1,88 @@ +assertEquals('cWluaXVwaG90b3M6Z29nb3BoZXIuanBn', $encodeEntryURI); + } + + public function testKeyEmpty() + { + $bucket = 'qiniuphotos'; + $key = ''; + $encodeEntryURI = Qiniu\entry($bucket, $key); + $this->assertEquals('cWluaXVwaG90b3M6', $encodeEntryURI); + } + + public function testKeyNull() + { + $bucket = 'qiniuphotos'; + $key = null; + $encodeEntryURI = Qiniu\entry($bucket, $key); + $this->assertEquals('cWluaXVwaG90b3M=', $encodeEntryURI); + } + + public function testKeyNeedReplacePlusSymbol() + { + $bucket = 'qiniuphotos'; + $key = '012ts>a'; + $encodeEntryURI = Qiniu\entry($bucket, $key); + $this->assertEquals('cWluaXVwaG90b3M6MDEydHM-YQ==', $encodeEntryURI); + } + + public function testKeyNeedReplaceSlashSymbol() + { + $bucket = 'qiniuphotos'; + $key = '012ts?a'; + $encodeEntryURI = Qiniu\entry($bucket, $key); + $this->assertEquals('cWluaXVwaG90b3M6MDEydHM_YQ==', $encodeEntryURI); + } + public function testDecodeEntry() + { + $entry = 'cWluaXVwaG90b3M6Z29nb3BoZXIuanBn'; + list($bucket, $key) = Qiniu\decodeEntry($entry); + $this->assertEquals('qiniuphotos', $bucket); + $this->assertEquals('gogopher.jpg', $key); + } + + public function testDecodeEntryWithEmptyKey() + { + $entry = 'cWluaXVwaG90b3M6'; + list($bucket, $key) = Qiniu\decodeEntry($entry); + $this->assertEquals('qiniuphotos', $bucket); + $this->assertEquals('', $key); + } + + public function testDecodeEntryWithNullKey() + { + $entry = 'cWluaXVwaG90b3M='; + list($bucket, $key) = Qiniu\decodeEntry($entry); + $this->assertEquals('qiniuphotos', $bucket); + $this->assertNull($key); + } + + public function testDecodeEntryWithPlusSymbol() + { + $entry = 'cWluaXVwaG90b3M6MDEydHM-YQ=='; + list($bucket, $key) = Qiniu\decodeEntry($entry); + $this->assertEquals('qiniuphotos', $bucket); + $this->assertEquals('012ts>a', $key); + } + + public function testDecodeEntryWithSlashSymbol() + { + $entry = 'cWluaXVwaG90b3M6MDEydHM_YQ=='; + list($bucket, $key) = Qiniu\decodeEntry($entry); + $this->assertEquals('qiniuphotos', $bucket); + $this->assertEquals('012ts?a', $key); + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/EtagTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/EtagTest.php new file mode 100644 index 0000000..4e09a78 --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/EtagTest.php @@ -0,0 +1,54 @@ +assertEquals('Fto5o-5ea0sNMlW_75VgGJCv2AcJ', $r); + $this->assertNull($error); + } + + public function testLess4M() + { + $file = qiniuTempFile(3 * 1024 * 1024, false); + list($r, $error) = Etag::sum($file); + unlink($file); + $this->assertEquals('Fs5BpnAjRykYTg6o5E09cjuXrDkG', $r); + $this->assertNull($error); + } + + public function test4M() + { + $file = qiniuTempFile(4 * 1024 * 1024, false); + list($r, $error) = Etag::sum($file); + unlink($file); + $this->assertEquals('FiuKULnybewpEnrfTmxjsxc-3dWp', $r); + $this->assertNull($error); + } + + public function testMore4M() + { + $file = qiniuTempFile(5 * 1024 * 1024, false); + list($r, $error) = Etag::sum($file); + unlink($file); + $this->assertEquals('lhvyfIWMYFTq4s4alzlhXoAkqfVL', $r); + $this->assertNull($error); + } + + public function test8M() + { + $file = qiniuTempFile(8 * 1024 * 1024, false); + list($r, $error) = Etag::sum($file); + unlink($file); + $this->assertEquals('lmRm9ZfGZ86bnMys4wRTWtJj9ClG', $r); + $this->assertNull($error); + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/FopTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/FopTest.php new file mode 100644 index 0000000..42b7997 --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/FopTest.php @@ -0,0 +1,39 @@ +execute('gogopher.jpg', 'exif'); + $this->assertNull($error); + $this->assertNotNull($exif); + } + + public function testExifPrivate() + { + global $testAuth; + $fop = new Operation('private-res.qiniudn.com', $testAuth); + list($exif, $error) = $fop->execute('noexif.jpg', 'exif'); + $this->assertNotNull($error); + $this->assertNull($exif); + } + + public function testbuildUrl() + { + $fops = 'imageView2/2/h/200'; + $fop = new Operation('testres.qiniudn.com'); + $url = $fop->buildUrl('gogopher.jpg', $fops); + $this->assertEquals($url, 'http://testres.qiniudn.com/gogopher.jpg?imageView2/2/h/200'); + + $fops = array('imageView2/2/h/200', 'imageInfo'); + $url = $fop->buildUrl('gogopher.jpg', $fops); + $this->assertEquals($url, 'http://testres.qiniudn.com/gogopher.jpg?imageView2/2/h/200|imageInfo'); + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/FormUpTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/FormUpTest.php new file mode 100644 index 0000000..f75794e --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/FormUpTest.php @@ -0,0 +1,205 @@ +batch($ops); + } + + private static function getObjectKey($key) + { + $result = $key . rand(); + self::$keysToCleanup[] = $result; + return $result; + } + + public function testData() + { + $key = self::getObjectKey('formput'); + $token = self::$auth->uploadToken(self::$bucketName); + list($ret, $error) = FormUploader::put($token, $key, 'hello world', self::$cfg, null, 'text/plain', null); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testDataWithProxy() + { + $key = self::getObjectKey('formput'); + $token = self::$auth->uploadToken(self::$bucketName); + list($ret, $error) = FormUploader::put( + $token, + $key, + 'hello world', + self::$cfg, + null, + 'text/plain', + null, + $this->makeReqOpt() + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testData2() + { + $key = self::getObjectKey('formput'); + $upManager = new UploadManager(); + $token = self::$auth->uploadToken(self::$bucketName); + list($ret, $error) = $upManager->put($token, $key, 'hello world', null, 'text/plain', null); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testData2WithProxy() + { + $key = self::getObjectKey('formput'); + $upManager = new UploadManager(); + $token = self::$auth->uploadToken(self::$bucketName); + list($ret, $error) = $upManager->put( + $token, + $key, + 'hello world', + null, + 'text/plain', + null, + $this->makeReqOpt() + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testDataFailed() + { + $key = self::getObjectKey('formput'); + $token = self::$auth->uploadToken('fakebucket'); + list($ret, $error) = FormUploader::put( + $token, + $key, + 'hello world', + self::$cfg, + null, + 'text/plain', + null + ); + $this->assertNull($ret); + $this->assertNotNull($error); + } + + public function testFile() + { + $key = self::getObjectKey('formPutFile'); + $token = self::$auth->uploadToken(self::$bucketName, $key); + list($ret, $error) = FormUploader::putFile( + $token, + $key, + __file__, + self::$cfg, + null, + 'text/plain', + null + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testFileWithProxy() + { + $key = self::getObjectKey('formPutFile'); + $token = self::$auth->uploadToken(self::$bucketName, $key); + list($ret, $error) = FormUploader::putFile( + $token, + $key, + __file__, + self::$cfg, + null, + 'text/plain', + $this->makeReqOpt() + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testFile2() + { + $key = self::getObjectKey('formPutFile'); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $upManager = new UploadManager(); + list($ret, $error) = $upManager->putFile($token, $key, __file__, null, 'text/plain', null); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testFile2WithProxy() + { + $key = self::getObjectKey('formPutFile'); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $upManager = new UploadManager(); + list($ret, $error) = $upManager->putFile( + $token, + $key, + __file__, + null, + 'text/plain', + false, + null, + 'v1', + Config::BLOCK_SIZE, + $this->makeReqOpt() + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + } + + public function testFileFailed() + { + $key = self::getObjectKey('fakekey'); + $token = self::$auth->uploadToken('fakebucket', $key); + list($ret, $error) = FormUploader::putFile($token, $key, __file__, self::$cfg, null, 'text/plain', null); + $this->assertNull($ret); + $this->assertNotNull($error); + } + + private function makeReqOpt() + { + $reqOpt = new RequestOptions(); + $reqOpt->proxy = 'socks5://127.0.0.1:8080'; + $reqOpt->proxy_user_password = 'user:pass'; + return $reqOpt; + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/HeaderTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/HeaderTest.php new file mode 100644 index 0000000..28af5f3 --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/HeaderTest.php @@ -0,0 +1,184 @@ + array('200'), + ':x-test-1' => array('hello1'), + ':x-Test-2' => array('hello2'), + 'content-type' => array('application/json'), + 'CONTENT-LENGTH' => array(1234), + 'oRiGin' => array('https://www.qiniu.com'), + 'ReFer' => array('www.qiniu.com'), + 'Last-Modified' => array('Mon, 06 Sep 2021 06:44:52 GMT'), + 'acCePt-ChArsEt' => array('utf-8'), + 'x-test-3' => array('hello3'), + 'cache-control' => array('no-cache', 'no-store'), + ); + + public function testNormalizeKey() + { + $except = array( + ':status', + ':x-test-1', + ':x-Test-2', + 'Content-Type', + 'Content-Length', + 'Origin', + 'Refer', + 'Last-Modified', + 'Accept-Charset', + 'X-Test-3', + 'Cache-Control' + ); + $actual = array_map(function ($str) { + return Header::normalizeKey($str); + }, array_keys($this->heads)); + $this->assertEquals($actual, $except); + } + + + public function testInvalidKeyName() + { + $except = array( + 'a:x-test-1', + ); + + $actual = array_map(function ($str) { + return Header::normalizeKey($str); + }, $except); + + $this->assertEquals($except, $actual); + } + + public function testGetRawData() + { + $header = new Header($this->heads); + foreach ($this->heads as $k => $v) { + $rawHeader = $header->getRawData(); + $this->assertEquals($v, $rawHeader[Header::normalizeKey($k)]); + } + } + + public function testOffsetExists() + { + $header = new Header($this->heads); + foreach (array_keys($this->heads) as $k) { + $this->assertNotNull($header[$k]); + } + + $except = array( + ':status', + ':x-test-1', + ':x-Test-2', + 'Content-Type', + 'Content-Length', + 'Origin', + 'Refer', + 'Last-Modified', + 'Accept-Charset', + 'X-Test-3', + 'Cache-Control' + ); + foreach ($except as $k) { + $this->assertNotNull($header[$k], $k." is null"); + } + } + + public function testOffsetGet() + { + $header = new Header($this->heads); + foreach ($this->heads as $k => $v) { + $this->assertEquals($v[0], $header[$k]); + } + + $this->assertNull($header['no-exist']); + } + + public function testOffsetSet() + { + $header = new Header($this->heads); + $header["X-Test-3"] = "hello"; + $this->assertEquals("hello", $header["X-Test-3"]); + $header["x-test-3"] = "hello test3"; + $this->assertEquals("hello test3", $header["x-test-3"]); + $header[":x-Test-2"] = "hello"; + $this->assertEquals("hello", $header[":x-Test-2"]); + $header[":x-test-2"] = "hello test2"; + $this->assertEquals("hello", $header[":x-Test-2"]); + } + + public function testOffsetUnset() + { + $header = new Header($this->heads); + unset($header["X-Test-3"]); + $this->assertFalse(isset($header["X-Test-3"])); + + $header = new Header($this->heads); + unset($header["x-test-3"]); + $this->assertFalse(isset($header["x-test-3"])); + + $header = new Header($this->heads); + unset($header[":x-test-2"]); + $this->assertTrue(isset($header[":x-Test-2"])); + + $header = new Header($this->heads); + unset($header[":x-Test-2"]); + $this->assertFalse(isset($header[":x-Test-2"])); + } + + public function testGetIterator() + { + $header = new Header($this->heads); + + $hasException = false; + try { + foreach ($header as $k => $v) { + $hasException = !isset($header[$k]); + } + } catch (\Exception $e) { + $hasException = true; + } + $this->assertFalse($hasException); + } + + public function testEmptyHeaderIterator() + { + $emptyHeader = new Header(); + + $hasException = false; + try { + foreach ($emptyHeader as $k => $v) { + $hasException = !isset($header[$k]); + } + } catch (\Exception $e) { + $hasException = true; + } + $this->assertFalse($hasException); + } + + public function testCount() + { + $header = new Header($this->heads); + + $this->assertEquals(count($this->heads), count($header)); + } + + public function testFromRaw() + { + $lines = array(); + foreach ($this->heads as $k => $vs) { + foreach ($vs as $v) { + array_push($lines, $k . ": " . $v); + } + } + $raw = implode("\r\n", $lines); + $headerFromRaw = Header::fromRawText($raw); + $this->assertEquals(new Header($this->heads), $headerFromRaw); + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/HttpTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/HttpTest.php new file mode 100644 index 0000000..c122f8e --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/HttpTest.php @@ -0,0 +1,163 @@ +assertEquals(200, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNull($response->error); + } + + public function testGetQiniu() + { + $response = Client::get('upload.qiniu.com'); + $this->assertEquals(405, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNotNull($response->xReqId()); + $this->assertNotNull($response->xLog()); + $this->assertNotNull($response->error); + } + + public function testGetTimeout() + { + $reqOpt = new RequestOptions(); + $reqOpt->timeout = 1; + $response = Client::get('localhost:9000/timeout.php', array(), $reqOpt); + $this->assertEquals(-1, $response->statusCode); + } + + public function testGetRedirect() + { + $response = Client::get('localhost:9000/redirect.php'); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals('application/json;charset=UTF-8', $response->normalizedHeaders['Content-Type']); + $respData = $response->json(); + $this->assertEquals('ok', $respData['msg']); + } + + public function testDelete() + { + $response = Client::delete('uc.qbox.me/bucketTagging', array()); + $this->assertEquals(401, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNotNull($response->error); + } + + public function testDeleteQiniu() + { + $response = Client::delete('uc.qbox.me/bucketTagging', array()); + $this->assertEquals(401, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNotNull($response->xReqId()); + $this->assertNotNull($response->xLog()); + $this->assertNotNull($response->error); + } + + public function testDeleteTimeout() + { + $reqOpt = new RequestOptions(); + $reqOpt->timeout = 1; + $response = Client::delete('localhost:9000/timeout.php', array(), $reqOpt); + $this->assertEquals(-1, $response->statusCode); + } + + + public function testPost() + { + $response = Client::post('qiniu.com', null); + $this->assertEquals(200, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNull($response->error); + } + + public function testPostQiniu() + { + $response = Client::post('upload.qiniu.com', null); + $this->assertEquals(400, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNotNull($response->xReqId()); + $this->assertNotNull($response->xLog()); + $this->assertNotNull($response->error); + } + + public function testPostTimeout() + { + $reqOpt = new RequestOptions(); + $reqOpt->timeout = 1; + $response = Client::post('localhost:9000/timeout.php', null, array(), $reqOpt); + $this->assertEquals(-1, $response->statusCode); + } + + public function testSocks5Proxy() + { + $reqOpt = new RequestOptions(); + $reqOpt->proxy = 'socks5://localhost:8080'; + $response = Client::post('qiniu.com', null, array(), $reqOpt); + $this->assertEquals(-1, $response->statusCode); + + $reqOpt->proxy_user_password = 'user:pass'; + $response = Client::post('qiniu.com', null, array(), $reqOpt); + $this->assertEquals(200, $response->statusCode); + } + + public function testPut() + { + $response = Client::PUT('uc.qbox.me/bucketTagging', null); + $this->assertEquals(401, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNotNull($response->error); + } + + public function testPutQiniu() + { + $response = Client::put('uc.qbox.me/bucketTagging', null); + $this->assertEquals(401, $response->statusCode); + $this->assertNotNull($response->body); + $this->assertNotNull($response->xReqId()); + $this->assertNotNull($response->xLog()); + $this->assertNotNull($response->error); + } + + + public function testPutTimeout() + { + $reqOpt = new RequestOptions(); + $reqOpt->timeout = 1; + $response = Client::put('localhost:9000/timeout.php', null, array(), $reqOpt); + $this->assertEquals(-1, $response->statusCode); + } + + public function testNeedRetry() + { + $testCases = array_merge( + array(array(-1, true)), + array_map(function ($i) { + return array($i, false); + }, range(100, 499)), + array_map(function ($i) { + if (in_array($i, array( + 501, 509, 573, 579, 608, 612, 614, 616, 618, 630, 631, 632, 640, 701 + ))) { + return array($i, false); + } + return array($i, true); + }, range(500, 799)) + ); + $resp = new Response(-1, 222, array(), '{"msg": "mock"}', null); + foreach ($testCases as $testCase) { + list($code, $expectNeedRetry) = $testCase; + $resp->statusCode = $code; + $msg = $resp->statusCode . ' need' . ($expectNeedRetry ? '' : ' NOT') . ' retry'; + $this->assertEquals($expectNeedRetry, $resp->needRetry(), $msg); + } + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/ImageUrlBuilderTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/ImageUrlBuilderTest.php new file mode 100644 index 0000000..486323c --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/ImageUrlBuilderTest.php @@ -0,0 +1,263 @@ + + */ +class ImageUrlBuilderTest extends TestCase +{ + /** + * 缩略图测试 + * + * @test + * @return void + * @author Sherlock Ren + */ + public function testThumbutl() + { + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder(); + $url = 'http://78re52.com1.z0.glb.clouddn.com/resource/gogopher.jpg'; + $url2 = $url . '?watermark/1/gravity/SouthEast/dx/0/dy/0/image/' + . 'aHR0cDovL2Fkcy1jZG4uY2h1Y2h1amllLmNvbS9Ga1R6bnpIY2RLdmRBUFc5cHZZZ3pTc21UY0tB'; + // 异常测试 + $this->assertEquals($url, $imageUrlBuilder->thumbnail($url, 1, 0, 0)); + $this->assertEquals($url, \Qiniu\thumbnail($url, 1, 0, 0)); + + // 简单缩略测试 + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/ignore-error/1/', + $imageUrlBuilder->thumbnail($url, 1, 200, 200) + ); + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/ignore-error/1/', + \Qiniu\thumbnail($url, 1, 200, 200) + ); + + // 输出格式测试 + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/', + $imageUrlBuilder->thumbnail($url, 1, 200, 200, 'png') + ); + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/', + \Qiniu\thumbnail($url, 1, 200, 200, 'png') + ); + + // 渐进显示测试 + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/format/png/interlace/1/ignore-error/1/', + $imageUrlBuilder->thumbnail($url, 1, 200, 200, 'png', 1) + ); + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/', + \Qiniu\thumbnail($url, 1, 200, 200, 'png', 2) + ); + + // 图片质量测试 + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/format/png/interlace/1/q/80/ignore-error/1/', + $imageUrlBuilder->thumbnail($url, 1, 200, 200, 'png', 1, 80) + ); + $this->assertEquals( + $url . '?imageView2/1/w/200/h/200/format/png/interlace/1/ignore-error/1/', + \Qiniu\thumbnail($url, 1, 200, 200, 'png', 1, 101) + ); + + // 多参数测试 + $this->assertEquals( + $url2 . '|imageView2/1/w/200/h/200/ignore-error/1/', + $imageUrlBuilder->thumbnail($url2, 1, 200, 200) + ); + $this->assertEquals( + $url2 . '|imageView2/1/w/200/h/200/ignore-error/1/', + \Qiniu\thumbnail($url2, 1, 200, 200) + ); + } + + /** + * 图片水印测试 + * + * @test + * @param void + * @return void + * @author Sherlock Ren + */ + public function waterImgTest() + { + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder(); + $url = 'http://78re52.com1.z0.glb.clouddn.com/resource/gogopher.jpg'; + $url2 = $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/'; + $image = 'http://developer.qiniu.com/resource/logo-2.jpg'; + + // 水印简单测试 + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + $imageUrlBuilder->waterImg($url, $image) + ); + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/gravity/SouthEast/', + $imageUrlBuilder->waterImg($url, $image, 101) + ); + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==/', + $imageUrlBuilder->waterImg($url, $image, 101, 'sdfsd') + ); + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + \Qiniu\waterImg($url, $image) + ); + + // 横轴边距测试 + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/dx/10/', + $imageUrlBuilder->waterImg($url, $image, 100, 'SouthEast', 10) + ); + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + \Qiniu\waterImg($url, $image, 100, 'SouthEast', 'sad') + ); + + // 纵轴边距测试 + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/dx/10/dy/10/', + $imageUrlBuilder->waterImg($url, $image, 100, 'SouthEast', 10, 10) + ); + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + \Qiniu\waterImg($url, $image, 100, 'SouthEast', 'sad', 'asdf') + ); + + // 自适应原图的短边比例测试 + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/dx/10/dy/10/ws/0.5/', + $imageUrlBuilder->waterImg($url, $image, 100, 'SouthEast', 10, 10, 0.5) + ); + $this->assertEquals( + $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + \Qiniu\waterImg($url, $image, 100, 'SouthEast', 'sad', 'asdf', 2) + ); + + // 多参数测试 + $this->assertEquals( + $url2 . '|watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + $imageUrlBuilder->waterImg($url2, $image) + ); + $this->assertEquals( + $url2 . '|watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==' + . '/dissolve/100/gravity/SouthEast/', + \Qiniu\waterImg($url2, $image) + ); + } + + /** + * 文字水印测试 + * + * @test + * @param void + * @return void + * @author Sherlock Ren + */ + public function waterTextTest() + { + $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder(); + $url = 'http://78re52.com1.z0.glb.clouddn.com/resource/gogopher.jpg'; + $url2 = $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/'; + $text = '测试一下'; + $font = '微软雅黑'; + $fontColor = '#FF0000'; + + // 水印简单测试 + $this->assertEquals($url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/' + . 'fontsize/500/dissolve/100/gravity/SouthEast/', $imageUrlBuilder->waterText($url, $text, $font, 500)); + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/' + . 'dissolve/100/gravity/SouthEast/', + \Qiniu\waterText($url, $text, $font, 'sdf') + ); + + // 字体颜色测试 + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/' + . 'I0ZGMDAwMA==/dissolve/100/gravity/SouthEast/', + $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor) + ); + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA==' + . '/dissolve/100/gravity/SouthEast/', + \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor) + ); + + // 透明度测试 + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/I0ZGMDAwMA==' + . '/dissolve/80/gravity/SouthEast/', + $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor, 80) + ); + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA==' + . '/gravity/SouthEast/', + \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor, 101) + ); + + // 水印位置测试 + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/I0ZGMDAwMA==' + . '/dissolve/80/gravity/East/', + $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor, 80, 'East') + ); + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA==/', + \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor, 101, 'sdfsdf') + ); + + // 横轴距离测试 + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/I0ZGMDAwMA==' + . '/dissolve/80/gravity/East/dx/10/', + $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor, 80, 'East', 10) + ); + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA==/', + \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor, 101, 'sdfsdf', 'sdfs') + ); + + // 纵轴距离测试 + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/I0ZGMDAwMA==' + . '/dissolve/80/gravity/East/dx/10/dy/10/', + $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor, 80, 'East', 10, 10) + ); + $this->assertEquals( + $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA==/', + \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor, 101, 'sdfsdf', 'sdfs', 'ssdf') + ); + // 多参数测试 + $this->assertEquals( + $url2 . '|watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/' + . 'fontsize/500/dissolve/100/gravity/SouthEast/', + $imageUrlBuilder->waterText($url2, $text, $font, 500) + ); + $this->assertEquals( + $url2 . '|watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/' + . 'fontsize/500/dissolve/100/gravity/SouthEast/', + \Qiniu\waterText($url2, $text, $font, 500) + ); + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/MiddlewareTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/MiddlewareTest.php new file mode 100644 index 0000000..969cad4 --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/MiddlewareTest.php @@ -0,0 +1,160 @@ + + */ + private $orderRecorder; + + /** + * @var string + */ + private $label; + + public function __construct(&$orderRecorder, $label) + { + $this->orderRecorder =& $orderRecorder; + $this->label = $label; + } + + public function send($request, $next) + { + $this->orderRecorder[] = "bef_" . $this->label . count($this->orderRecorder); + $response = $next($request); + $this->orderRecorder[] = "aft_" . $this->label . count($this->orderRecorder); + return $response; + } +} + +class MiddlewareTest extends TestCase +{ + public function testSendWithMiddleware() + { + $orderRecorder = array(); + + $reqOpt = new RequestOptions(); + $reqOpt->middlewares = array( + new RecorderMiddleware($orderRecorder, "A"), + new RecorderMiddleware($orderRecorder, "B") + ); + + $request = new Request( + "GET", + "http://localhost:9000/ok.php", + array(), + null, + $reqOpt + ); + $response = Client::sendRequestWithMiddleware($request); + + $expectRecords = array( + "bef_A0", + "bef_B1", + "aft_B2", + "aft_A3" + ); + + $this->assertEquals($expectRecords, $orderRecorder); + $this->assertEquals(200, $response->statusCode); + } + + public function testSendWithRetryDomains() + { + $orderRecorder = array(); + + $reqOpt = new RequestOptions(); + $reqOpt->middlewares = array( + new Middleware\RetryDomainsMiddleware( + array( + "unavailable.phpsdk.qiniu.com", + "localhost:9000", + ), + 3 + ), + new RecorderMiddleware($orderRecorder, "rec") + ); + + $request = new Request( + "GET", + "http://fake.phpsdk.qiniu.com/ok.php", + array(), + null, + $reqOpt + ); + $response = Client::sendRequestWithMiddleware($request); + + $expectRecords = array( + // 'fake.phpsdk.qiniu.com' with retried 3 times + 'bef_rec0', + 'aft_rec1', + 'bef_rec2', + 'aft_rec3', + 'bef_rec4', + 'aft_rec5', + + // 'unavailable.pysdk.qiniu.com' with retried 3 times + 'bef_rec6', + 'aft_rec7', + 'bef_rec8', + 'aft_rec9', + 'bef_rec10', + 'aft_rec11', + + // 'qiniu.com' and it's success + 'bef_rec12', + 'aft_rec13' + ); + + $this->assertEquals($expectRecords, $orderRecorder); + $this->assertEquals(200, $response->statusCode); + } + + public function testSendFailFastWithRetryDomains() + { + $orderRecorder = array(); + + $reqOpt = new RequestOptions(); + $reqOpt->middlewares = array( + new Middleware\RetryDomainsMiddleware( + array( + "unavailable.phpsdk.qiniu.com", + "localhost:9000", + ), + 3, + function () { + return false; + } + ), + new RecorderMiddleware($orderRecorder, "rec") + ); + + $request = new Request( + "GET", + "http://fake.phpsdk.qiniu.com/ok.php", + array(), + null, + $reqOpt + ); + $response = Client::sendRequestWithMiddleware($request); + + $expectRecords = array( + // 'fake.phpsdk.qiniu.com' will fail fast + 'bef_rec0', + 'aft_rec1' + ); + $this->assertEquals($expectRecords, $orderRecorder); + $this->assertEquals(-1, $response->statusCode); + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/PfopTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/PfopTest.php new file mode 100644 index 0000000..77d06ec --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/PfopTest.php @@ -0,0 +1,304 @@ +execute($bucket, $key, $fops); + $this->assertNull($error); + list($status, $error) = $pfop->status($id); + $this->assertNotNull($status); + $this->assertNull($error); + } + + + public function testPfopExecuteAndStatusWithMultipleFops() + { + global $testAuth; + $bucket = 'testres'; + $key = 'sintel_trailer.mp4'; + $fops = array( + 'avthumb/m3u8/segtime/10/vcodec/libx264/s/320x240', + 'vframe/jpg/offset/7/w/480/h/360', + ); + $pfop = new PersistentFop($testAuth, self::getConfig()); + + list($id, $error) = $pfop->execute($bucket, $key, $fops); + $this->assertNull($error); + + list($status, $error) = $pfop->status($id); + $this->assertNotNull($status); + $this->assertNull($error); + } + + private function pfopOptionsTestData() + { + return array( + array( + 'type' => null + ), + array( + 'type' => -1 + ), + array( + 'type' => 0 + ), + array( + 'type' => 1 + ), + array( + 'type' => 2 + ), + array( + 'workflowTemplateID' => 'test-workflow' + ) + ); + } + + public function testPfopExecuteWithOptions() + { + $bucket = self::$bucketName; + $key = 'qiniu.png'; + $pfop = new PersistentFop(self::$testAuth, self::getConfig()); + + $testCases = $this->pfopOptionsTestData(); + + foreach ($testCases as $testCase) { + $workflowTemplateID = null; + $type = null; + + if (array_key_exists('workflowTemplateID', $testCase)) { + $workflowTemplateID = $testCase['workflowTemplateID']; + } + if (array_key_exists('type', $testCase)) { + $type = $testCase['type']; + } + + if ($workflowTemplateID) { + $fops = null; + } else { + $persistentEntry = \Qiniu\entry( + $bucket, + implode( + '_', + array( + 'test-pfop/test-pfop-by-api', + 'type', + $type + ) + ) + ); + $fops = 'avinfo|saveas/' . $persistentEntry; + } + list($id, $error) = $pfop->execute( + $bucket, + $key, + $fops, + null, + null, + false, + $type, + $workflowTemplateID + ); + + if (in_array($type, array(null, 0, 1))) { + $this->assertNull($error); + list($status, $error) = $pfop->status($id); + $this->assertNotNull($status); + $this->assertNull($error); + if ($type == 1) { + $this->assertEquals(1, $status['type']); + } + if ($workflowTemplateID) { + // assertStringContainsString when PHPUnit >= 8.0 + $this->assertTrue( + strpos( + $status['taskFrom'], + $workflowTemplateID + ) !== false + ); + } + $this->assertNotEmpty($status['creationDate']); + } else { + $this->assertNotNull($error); + } + } + } + + public function testPfopWithInvalidArgument() + { + $bucket = self::$bucketName; + $key = 'qiniu.png'; + $pfop = new PersistentFop(self::$testAuth, self::getConfig()); + $err = null; + try { + $pfop->execute( + $bucket, + $key + ); + } catch (\Exception $e) { + $err = $e; + } + + $this->assertNotEmpty($err); + $this->assertTrue( + strpos( + $err->getMessage(), + 'Must provide one of fops or template_id' + ) !== false + ); + } + + public function testPfopWithUploadPolicy() + { + $bucket = self::$bucketName; + $testAuth = self::$testAuth; + $key = 'test-pfop/upload-file'; + + $testCases = $this->pfopOptionsTestData(); + + foreach ($testCases as $testCase) { + $workflowTemplateID = null; + $type = null; + + if (array_key_exists('workflowTemplateID', $testCase)) { + $workflowTemplateID = $testCase['workflowTemplateID']; + } + if (array_key_exists('type', $testCase)) { + $type = $testCase['type']; + } + + $putPolicy = array( + 'persistentType' => $type + ); + if ($workflowTemplateID) { + $putPolicy['persistentWorkflowTemplateID'] = $workflowTemplateID; + } else { + $persistentEntry = \Qiniu\entry( + $bucket, + implode( + '_', + array( + 'test-pfop/test-pfop-by-upload', + 'type', + $type + ) + ) + ); + $putPolicy['persistentOps'] = 'avinfo|saveas/' . $persistentEntry; + } + + if ($type == null) { + unset($putPolicy['persistentType']); + } + + $token = $testAuth->uploadToken( + $bucket, + $key, + 3600, + $putPolicy + ); + $upManager = new UploadManager(self::getConfig()); + list($ret, $error) = $upManager->putFile( + $token, + $key, + __file__, + null, + 'text/plain', + true + ); + + if (in_array($type, array(null, 0, 1))) { + $this->assertNull($error); + $this->assertNotEmpty($ret['persistentId']); + $id = $ret['persistentId']; + } else { + $this->assertNotNull($error); + return; + } + + $pfop = new PersistentFop($testAuth, self::getConfig()); + list($status, $error) = $pfop->status($id); + + $this->assertNotNull($status); + $this->assertNull($error); + if ($type == 1) { + $this->assertEquals(1, $status['type']); + } + if ($workflowTemplateID) { + // assertStringContainsString when PHPUnit >= 8.0 + $this->assertTrue( + strpos( + $status['taskFrom'], + $workflowTemplateID + ) !== false + ); + } + $this->assertNotEmpty($status['creationDate']); + } + } + + public function testMkzip() + { + $bucket = self::$bucketName; + $key = 'php-logo.png'; + $pfop = new PersistentFop(self::$testAuth, null); + + $url1 = 'http://phpsdk.qiniudn.com/php-logo.png'; + $url2 = 'http://phpsdk.qiniudn.com/php-sdk.html'; + $zipKey = 'test.zip'; + + $fops = 'mkzip/2/url/' . \Qiniu\base64_urlSafeEncode($url1); + $fops .= '/url/' . \Qiniu\base64_urlSafeEncode($url2); + $fops .= '|saveas/' . \Qiniu\base64_urlSafeEncode("$bucket:$zipKey"); + + list($id, $error) = $pfop->execute($bucket, $key, $fops); + $this->assertNull($error); + + list($status, $error) = $pfop->status($id); + $this->assertNotNull($status); + $this->assertNull($error); + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/ResumeUpTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/ResumeUpTest.php new file mode 100644 index 0000000..6feee55 --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/ResumeUpTest.php @@ -0,0 +1,354 @@ +batch($ops); + } + + private static function getObjectKey($key) + { + $result = $key . rand(); + self::$keysToCleanup[] = $result; + return $result; + } + + public function test4ML() + { + $key = self::getObjectKey('resumePutFile4ML_'); + $upManager = new UploadManager(); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $tempFile = qiniuTempFile(4 * 1024 * 1024 + 10); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + list($ret, $error) = $upManager->putFile( + $token, + $key, + $tempFile, + null, + 'application/octet-stream', + false, + $resumeFile + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + + $domain = getenv('QINIU_TEST_DOMAIN'); + $response = Client::get("http://$domain/$key"); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals(md5_file($tempFile, true), md5($response->body(), true)); + unlink($tempFile); + } + + public function test4ML2() + { + $key = self::getObjectKey('resumePutFile4ML_'); + $cfg = new Config(); + $upManager = new UploadManager($cfg); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $tempFile = qiniuTempFile(4 * 1024 * 1024 + 10); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + list($ret, $error) = $upManager->putFile( + $token, + $key, + $tempFile, + null, + 'application/octet-stream', + false, + $resumeFile + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + + $domain = getenv('QINIU_TEST_DOMAIN'); + $response = Client::get("http://$domain/$key"); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals(md5_file($tempFile, true), md5($response->body(), true)); + unlink($tempFile); + } + + public function test4ML2WithProxy() + { + $key = self::getObjectKey('resumePutFile4ML_'); + $cfg = new Config(); + $upManager = new UploadManager($cfg); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $tempFile = qiniuTempFile(4 * 1024 * 1024 + 10); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + list($ret, $error) = $upManager->putFile( + $token, + $key, + $tempFile, + null, + 'application/octet-stream', + false, + $resumeFile, + 'v2', + Config::BLOCK_SIZE, + $this->makeReqOpt() + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + + $domain = getenv('QINIU_TEST_DOMAIN'); + $response = Client::get("http://$domain/$key"); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals(md5_file($tempFile, true), md5($response->body(), true)); + unlink($tempFile); + } + + // public function test8M() + // { + // $key = 'resumePutFile8M'; + // $upManager = new UploadManager(); + // $token = self::$auth->uploadToken(self::$bucketName, $key); + // $tempFile = qiniuTempFile(8*1024*1024+10); + // list($ret, $error) = $upManager->putFile($token, $key, $tempFile); + // $this->assertNull($error); + // $this->assertNotNull($ret['hash']); + // unlink($tempFile); + // } + + public function testFileWithFileType() + { + $config = new Config(); + $bucketManager = new BucketManager(self::$auth, $config); + + $testCases = array( + array( + "fileType" => 1, + "name" => "IA" + ), + array( + "fileType" => 2, + "name" => "Archive" + ), + array( + "fileType" => 3, + "name" => "DeepArchive" + ) + ); + + foreach ($testCases as $testCase) { + $key = self::getObjectKey('FileType' . $testCase["name"]); + $police = array( + "fileType" => $testCase["fileType"], + ); + $token = self::$auth->uploadToken(self::$bucketName, $key, 3600, $police); + $upManager = new UploadManager(); + list($ret, $error) = $upManager->putFile($token, $key, __file__, null, 'text/plain'); + $this->assertNull($error); + $this->assertNotNull($ret); + list($ret, $err) = $bucketManager->stat(self::$bucketName, $key); + $this->assertNull($err); + $this->assertEquals($testCase["fileType"], $ret["type"]); + } + } + + public function testResumeUploadWithParams() + { + $key = self::getObjectKey('resumePutFile4ML_'); + $upManager = new UploadManager(); + $policy = array('returnBody' => '{"hash":$(etag),"fname":$(fname),"var_1":$(x:var_1),"var_2":$(x:var_2)}'); + $token = self::$auth->uploadToken(self::$bucketName, $key, 3600, $policy); + $tempFile = qiniuTempFile(4 * 1024 * 1024 + 10); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + list($ret, $error) = $upManager->putFile( + $token, + $key, + $tempFile, + array("x:var_1" => "val_1", "x:var_2" => "val_2", "x-qn-meta-m1" => "val_1", "x-qn-meta-m2" => "val_2"), + 'application/octet-stream', + false, + $resumeFile + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + $this->assertEquals("val_1", $ret['var_1']); + $this->assertEquals("val_2", $ret['var_2']); + $this->assertEquals(basename($tempFile), $ret['fname']); + + $domain = getenv('QINIU_TEST_DOMAIN'); + $response = Client::get("http://$domain/$key"); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals(md5_file($tempFile, true), md5($response->body(), true)); + $headers = $response->headers(); + $this->assertEquals("val_1", $headers["X-Qn-Meta-M1"]); + $this->assertEquals("val_2", $headers["X-Qn-Meta-M2"]); + unlink($tempFile); + } + + public function testResumeUploadV2() + { + $cfg = new Config(); + $upManager = new UploadManager($cfg); + $testFileSize = array( + config::BLOCK_SIZE / 2, + config::BLOCK_SIZE, + config::BLOCK_SIZE + 10, + config::BLOCK_SIZE * 2, + config::BLOCK_SIZE * 2.5 + ); + $partSize = 5 * 1024 * 1024; + foreach ($testFileSize as $item) { + $key = self::getObjectKey('resumePutFile4ML_'); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $tempFile = qiniuTempFile($item); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + list($ret, $error) = $upManager->putFile( + $token, + $key, + $tempFile, + null, + 'application/octet-stream', + false, + $resumeFile, + 'v2', + $partSize + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + + $domain = getenv('QINIU_TEST_DOMAIN'); + $response = Client::get("http://$domain/$key"); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals(md5_file($tempFile, true), md5($response->body(), true)); + unlink($tempFile); + } + } + + public function testResumeUploadV2WithParams() + { + $key = self::getObjectKey('resumePutFile4ML_'); + $upManager = new UploadManager(); + $policy = array('returnBody' => '{"hash":$(etag),"fname":$(fname),"var_1":$(x:var_1),"var_2":$(x:var_2)}'); + $token = self::$auth->uploadToken(self::$bucketName, $key, 3600, $policy); + $tempFile = qiniuTempFile(4 * 1024 * 1024 + 10); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + list($ret, $error) = $upManager->putFile( + $token, + $key, + $tempFile, + array("x:var_1" => "val_1", "x:var_2" => "val_2", "x-qn-meta-m1" => "val_1", "x-qn-meta-m2" => "val_2"), + 'application/octet-stream', + false, + $resumeFile, + 'v2' + ); + $this->assertNull($error); + $this->assertNotNull($ret['hash']); + $this->assertEquals("val_1", $ret['var_1']); + $this->assertEquals("val_2", $ret['var_2']); + $this->assertEquals(basename($tempFile), $ret['fname']); + + $domain = getenv('QINIU_TEST_DOMAIN'); + $response = Client::get("http://$domain/$key"); + $this->assertEquals(200, $response->statusCode); + $this->assertEquals(md5_file($tempFile, true), md5($response->body(), true)); + $headers = $response->headers(); + $this->assertEquals("val_1", $headers["X-Qn-Meta-M1"]); + $this->assertEquals("val_2", $headers["X-Qn-Meta-M2"]); + unlink($tempFile); + } + + // valid versions are tested above + // Use PHPUnit's Data Provider to test multiple Exception is better, + // but not match the test style of this project + public function testResumeUploadWithInvalidVersion() + { + $cfg = new Config(); + $upManager = new UploadManager($cfg); + $testFileSize = config::BLOCK_SIZE * 2; + $partSize = 5 * 1024 * 1024; + $testInvalidVersions = array( + // High probability invalid versions + 'v', + '1', + '2' + ); + + $expectExceptionCount = 0; + foreach ($testInvalidVersions as $invalidVersion) { + $key = self::getObjectKey('resumePutFile4ML_'); + $token = self::$auth->uploadToken(self::$bucketName, $key); + $tempFile = qiniuTempFile($testFileSize); + $resumeFile = tempnam(sys_get_temp_dir(), 'resume_file'); + $this->assertNotFalse($resumeFile); + try { + $upManager->putFile( + $token, + $key, + $tempFile, + null, + 'application/octet-stream', + false, + $resumeFile, + $invalidVersion, + $partSize + ); + } catch (\Exception $e) { + $isRightException = false; + $expectExceptionCount++; + while ($e) { + $isRightException = $e instanceof \UnexpectedValueException; + if ($isRightException) { + break; + } + $e = $e->getPrevious(); + } + $this->assertTrue($isRightException); + } + + unlink($tempFile); + } + $this->assertEquals(count($testInvalidVersions), $expectExceptionCount); + } + + private function makeReqOpt() + { + $reqOpt = new RequestOptions(); + $reqOpt->proxy = 'socks5://127.0.0.1:8080'; + $reqOpt->proxy_user_password = 'user:pass'; + return $reqOpt; + } +} diff --git a/vendor/qiniu/php-sdk/tests/Qiniu/Tests/ZoneTest.php b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/ZoneTest.php new file mode 100644 index 0000000..fbab528 --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/Qiniu/Tests/ZoneTest.php @@ -0,0 +1,136 @@ +bucketName = $bucketName; + + global $bucketNameBC; + $this->bucketNameBC = $bucketNameBC; + + global $bucketNameNA; + $this->bucketNameNA = $bucketNameNA; + + global $bucketNameFS; + $this->bucketNameFS = $bucketNameFS; + + global $bucketNameAS; + $this->bucketNameAS = $bucketNameAS; + + global $accessKey; + $this->ak = $accessKey; + + $this->zone = new Zone(); + $this->zoneHttps = new Zone('https'); + } + + public function testUpHosts() + { + list($ret, $err) = Zone::queryZone($this->ak, 'fakebucket'); + $this->assertNull($ret); + $this->assertNotNull($err); + + $zone = Zone::queryZone($this->ak, $this->bucketName); + $this->assertContains('upload.qiniup.com', $zone->cdnUpHosts); + + $zone = Zone::queryZone($this->ak, $this->bucketNameBC); + $this->assertContains('upload-z1.qiniup.com', $zone->cdnUpHosts); + + $zone = Zone::queryZone($this->ak, $this->bucketNameFS); + $this->assertContains('upload-z2.qiniup.com', $zone->cdnUpHosts); + + $zone = Zone::queryZone($this->ak, $this->bucketNameNA); + $this->assertContains('upload-na0.qiniup.com', $zone->cdnUpHosts); + + $zone = Zone::queryZone($this->ak, $this->bucketNameAS); + $this->assertContains('upload-as0.qiniup.com', $zone->cdnUpHosts); + } + + public function testIoHosts() + { + $zone = Zone::queryZone($this->ak, $this->bucketName); + $this->assertEquals($zone->iovipHost, 'iovip.qbox.me'); + + $zone = Zone::queryZone($this->ak, $this->bucketNameBC); + $this->assertEquals($zone->iovipHost, 'iovip-z1.qbox.me'); + + $zone = Zone::queryZone($this->ak, $this->bucketNameFS); + $this->assertEquals($zone->iovipHost, 'iovip-z2.qbox.me'); + + $zone = Zone::queryZone($this->ak, $this->bucketNameNA); + $this->assertEquals($zone->iovipHost, 'iovip-na0.qbox.me'); + + $zone = Zone::queryZone($this->ak, $this->bucketNameAS); + $this->assertEquals($zone->iovipHost, 'iovip-as0.qbox.me'); + } + + public function testZonez0() + { + $zone = Zone::zonez0(); + $this->assertContains('upload.qiniup.com', $zone->cdnUpHosts); + } + + public function testZonez1() + { + $zone = Zone::zonez1(); + $this->assertContains('upload-z1.qiniup.com', $zone->cdnUpHosts); + } + + public function testZonez2() + { + $zone = Zone::zonez2(); + $this->assertContains('upload-z2.qiniup.com', $zone->cdnUpHosts); + } + + public function testZoneCnEast2() + { + $zone = Zone::zoneCnEast2(); + $this->assertContains('upload-cn-east-2.qiniup.com', $zone->cdnUpHosts); + } + + public function testZoneNa0() + { + $zone = Zone::zoneNa0(); + $this->assertContains('upload-na0.qiniup.com', $zone->cdnUpHosts); + } + + public function testZoneAs0() + { + $zone = Zone::zoneAs0(); + $this->assertContains('upload-as0.qiniup.com', $zone->cdnUpHosts); + } + + public function testQvmZonez0() + { + $zone = Zone::qvmZonez0(); + $this->assertContains('free-qvm-z0-xs.qiniup.com', $zone->srcUpHosts); + } + + public function testQvmZonez1() + { + $zone = Zone::qvmZonez1(); + $this->assertContains('free-qvm-z1-zz.qiniup.com', $zone->srcUpHosts); + } +} diff --git a/vendor/qiniu/php-sdk/tests/bootstrap.php b/vendor/qiniu/php-sdk/tests/bootstrap.php new file mode 100644 index 0000000..9859a81 --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/bootstrap.php @@ -0,0 +1,61 @@ + 0) { + $length = min($rest_size, 4 * 1024); + if (fwrite($file, random_bytes($length)) == false) { + return false; + } + $rest_size -= $length; + } + } else if ($size > 0) { + fseek($file, $size - 1); + fwrite($file, ' '); + } + fclose($file); + return $fileName; +} diff --git a/vendor/qiniu/php-sdk/tests/mock-server/ok.php b/vendor/qiniu/php-sdk/tests/mock-server/ok.php new file mode 100644 index 0000000..5b0a65d --- /dev/null +++ b/vendor/qiniu/php-sdk/tests/mock-server/ok.php @@ -0,0 +1,3 @@ +