From c08202d8cf30880a43b6d75b09d2425c5ffdc884 Mon Sep 17 00:00:00 2001 From: zhouyangyang Date: Tue, 14 Jun 2022 15:49:44 +0800 Subject: [PATCH] first commit --- .gitattributes | 2 + .github/workflows/release.yml | 25 ++++ .github/workflows/test.yml | 73 ++++++++++ .gitignore | 5 + .php-cs-fixer.php | 89 ++++++++++++ .phpstorm.meta.php | 6 + LICENSE | 21 +++ README.md | 5 + composer.json | 57 ++++++++ phpunit.xml | 15 ++ publish/mmds_oss.php | 7 + src/ConfigProvider.php | 40 ++++++ src/Exception/OssException.php | 10 ++ src/Oss.php | 230 +++++++++++++++++++++++++++++++ tests/Cases/AbstractTestCase.php | 21 +++ tests/Cases/ExampleTest.php | 24 ++++ tests/bootstrap.php | 12 ++ 17 files changed, 642 insertions(+) create mode 100644 .gitattributes create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/test.yml create mode 100644 .gitignore create mode 100644 .php-cs-fixer.php create mode 100644 .phpstorm.meta.php create mode 100644 LICENSE create mode 100644 README.md create mode 100644 composer.json create mode 100644 phpunit.xml create mode 100644 publish/mmds_oss.php create mode 100644 src/ConfigProvider.php create mode 100644 src/Exception/OssException.php create mode 100644 src/Oss.php create mode 100644 tests/Cases/AbstractTestCase.php create mode 100644 tests/Cases/ExampleTest.php create mode 100644 tests/bootstrap.php diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..27b765f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +/tests export-ignore +/.github export-ignore diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..0f7d23f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,25 @@ +on: + push: + # Sequence of patterns matched against refs/tags + tags: + - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + +name: Release + +jobs: + release: + name: Release + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + draft: false + prerelease: false diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..bb40773 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,73 @@ +name: PHPUnit + +on: [ push, pull_request ] + +env: + SWOOLE_VERSION: '4.8.10' + SWOW_VERSION: 'develop' + +jobs: + ci: + name: Test PHP ${{ matrix.php-version }} on ${{ matrix.engine }} + runs-on: "${{ matrix.os }}" + strategy: + matrix: + os: [ ubuntu-latest ] + php-version: [ '7.3', '7.4', '8.0' ] + engine: [ 'none', 'swoole', 'swow' ] + exclude: + - php-version: '7.3' + engine: 'swow' + - php-version: '7.4' + engine: 'swow' + max-parallel: 5 + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + tools: phpize + ini-values: opcache.enable_cli=0 + coverage: none + - name: Setup Swoole + if: ${{ matrix.engine == 'swoole' }} + run: | + cd /tmp + sudo apt-get update + sudo apt-get install libcurl4-openssl-dev + wget https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz -O swoole.tar.gz + mkdir -p swoole + tar -xf swoole.tar.gz -C swoole --strip-components=1 + rm swoole.tar.gz + cd swoole + phpize + ./configure --enable-openssl --enable-http2 --enable-swoole-curl --enable-swoole-json + make -j$(nproc) + sudo make install + sudo sh -c "echo extension=swoole > /etc/php/${{ matrix.php-version }}/cli/conf.d/swoole.ini" + php --ri swoole + - name: Setup Swow + if: ${{ matrix.engine == 'swow' }} + run: | + cd /tmp + wget https://github.com/swow/swow/archive/"${SWOW_VERSION}".tar.gz -O swow.tar.gz + mkdir -p swow + tar -xf swow.tar.gz -C swow --strip-components=1 + rm swow.tar.gz + cd swow/ext || exit + + phpize + ./configure --enable-debug + make -j "$(nproc)" + sudo make install + sudo sh -c "echo extension=swow > /etc/php/${{ matrix.php-version }}/cli/conf.d/swow.ini" + php --ri swow + - name: Setup Packages + run: composer update -o --no-scripts + - name: Run Test Cases + run: | + vendor/bin/php-cs-fixer fix --dry-run + composer analyse + composer test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..628a5fc --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/.idea +/vendor/ +composer.lock +*.cache +*.log \ No newline at end of file diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php new file mode 100644 index 0000000..b9a08df --- /dev/null +++ b/.php-cs-fixer.php @@ -0,0 +1,89 @@ +setRiskyAllowed(true) + ->setRules([ + '@PSR2' => true, + '@Symfony' => true, + '@DoctrineAnnotation' => true, + '@PhpCsFixer' => true, + 'header_comment' => [ + 'comment_type' => 'PHPDoc', + 'header' => $header, + 'separate' => 'none', + 'location' => 'after_declare_strict', + ], + 'array_syntax' => [ + 'syntax' => 'short' + ], + 'list_syntax' => [ + 'syntax' => 'short' + ], + 'concat_space' => [ + 'spacing' => 'one' + ], + 'blank_line_before_statement' => [ + 'statements' => [ + 'declare', + ], + ], + 'general_phpdoc_annotation_remove' => [ + 'annotations' => [ + 'author' + ], + ], + 'ordered_imports' => [ + 'imports_order' => [ + 'class', 'function', 'const', + ], + 'sort_algorithm' => 'alpha', + ], + 'single_line_comment_style' => [ + 'comment_types' => [ + ], + ], + 'yoda_style' => [ + 'always_move_variable' => false, + 'equal' => false, + 'identical' => false, + ], + 'phpdoc_align' => [ + 'align' => 'left', + ], + 'multiline_whitespace_before_semicolons' => [ + 'strategy' => 'no_multi_line', + ], + 'constant_case' => [ + 'case' => 'lower', + ], + 'class_attributes_separation' => true, + 'combine_consecutive_unsets' => true, + 'declare_strict_types' => true, + 'linebreak_after_opening_tag' => true, + 'lowercase_static_reference' => true, + 'no_useless_else' => true, + 'no_unused_imports' => true, + 'not_operator_with_successor_space' => true, + 'not_operator_with_space' => false, + 'ordered_class_elements' => true, + 'php_unit_strict' => false, + 'phpdoc_separation' => false, + 'single_quote' => true, + 'standardize_not_equals' => true, + 'multiline_comment_opening_closing' => true, + ]) + ->setFinder( + PhpCsFixer\Finder::create() + ->exclude('vendor') + ->in(__DIR__) + ) + ->setUsingCache(false); diff --git a/.phpstorm.meta.php b/.phpstorm.meta.php new file mode 100644 index 0000000..1014069 --- /dev/null +++ b/.phpstorm.meta.php @@ -0,0 +1,6 @@ +=7.4", + "ext-json": "*", + "ext-fileinfo": "*", + "hyperf/framework": "~2.2.0", + "hyperf/guzzle": "~2.2.0", + "hyperf/http-server": "~2.2.0", + "hyperf/json-rpc": "^2.2", + "hyperf/logger": "~2.2.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.0", + "mockery/mockery": "^1.0", + "phpstan/phpstan": "^1.0", + "phpunit/phpunit": ">=7.0", + "swoole/ide-helper": "^4.5" + }, + "suggest": { + "swow/swow": "Required to create swow components." + }, + "minimum-stability": "dev", + "prefer-stable": true, + "config": { + "optimize-autoloader": true, + "sort-packages": true + }, + "scripts": { + "test": "phpunit -c phpunit.xml --colors=always", + "analyse": "phpstan analyse --memory-limit 1024M -l 0 ./src", + "cs-fix": "php-cs-fixer fix $1" + }, + "extra": { + "hyperf": { + "config": "Zyimm\\MmdsOss\\ConfigProvider" + } + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..d2c615a --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,15 @@ + + + + ./tests/ + + \ No newline at end of file diff --git a/publish/mmds_oss.php b/publish/mmds_oss.php new file mode 100644 index 0000000..94b1f4b --- /dev/null +++ b/publish/mmds_oss.php @@ -0,0 +1,7 @@ + env('XY_OSS_SERVICE', 'mmds'), + 'xy_oss_group_name' => env('XY_OSS_GROUP', 'mmds-hoge'), + 'xy_oss_url' => env('XY_OSS_URL', 'https://static-mmds.aihoge.com'), + 'xy_oss_bucket_name' => env('XY_OOS_BUCKET_NAME', 'mmdsstatic') +]; \ No newline at end of file diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php new file mode 100644 index 0000000..f080b43 --- /dev/null +++ b/src/ConfigProvider.php @@ -0,0 +1,40 @@ + [ + ], + 'publish' => [ + [ + 'id' => 'MmdsOss', + 'description' => 'The config for oss.', + 'source' => __DIR__ . '/../publish/mmds_oss.php', + 'destination' => BASE_PATH . '/config/autoload/mmds_oss.php', + ], + ], + 'commands' => [ + ], + 'annotations' => [ + 'scan' => [ + 'paths' => [ + __DIR__, + ], + ], + ], + ]; + } +} diff --git a/src/Exception/OssException.php b/src/Exception/OssException.php new file mode 100644 index 0000000..0f066f4 --- /dev/null +++ b/src/Exception/OssException.php @@ -0,0 +1,10 @@ +request->file('file'); + $file_content = file_get_contents($file->getPathname()); + $fInfo = new finfo(FILEINFO_MIME_TYPE); + $mimeType = $fInfo->buffer($file_content); + $file_info = [ + 'name' => 'file', + 'contents' => fopen($file->getPathname(), 'r'), + 'filename' => Carbon::now()->getTimestampMs().uniqid().'.'.$file->getExtension(), + + ]; + $result = $this->getSecretKey()->bucket()->ossUpload($file_info); + return [ + 'url' => $result['file_url'] ?? '', + 'size' => $result['file_size'] ?? 0, + 'mime_type' => $mimeType + ]; + } + + /** + * getUploadAttr + * + * @return array + * @throws ContainerExceptionInterface + * @throws GuzzleException + * @throws NotFoundExceptionInterface + */ + public function getUploadAttr(): array + { + $this->getSecretKey()->bucket(); + return [ + 'timestamp' => time(), + 'filestorage-authorization' => $this->authorization, + 'bucket' => $this->getBucketName() + ]; + } + + /** + * ossUpload + * + * @param $file_info + * @return array + * @throws GuzzleException + */ + private function ossUpload($file_info): array + { + $client = $this->clientFactory->create([ + 'base_uri' => $this->getBaseUri(), + 'headers' => array_merge($this->request->getHeaders(), [ + 'filestorage-authorization' => $this->authorization, + 'timestamp' => time() + ]) + ]); + $path = 'backend/normalUpload'; + + $response = $client->request($this->request->getMethod(), $path, [ + 'multipart' => [ + $file_info, + [ + 'name' => 'object_key', + 'contents' => $file_info['filename'] + ], + [ + 'name' => 'bucket', + 'contents' => $this->getBucketName() + ] + ] + ]); + + $data = json_decode($response->getBody()->getContents(), true); + if (isset($data['error_code']) && (int) $data['error_code'] == 200) { + return $data['result'] ?? []; + } else { + throw new OssException($data['error_message'] ?? 'oss upload error', + $data['error_code'] ?? __LINE__); + } + } + + private function getBaseUri() + { + return $this->config->get('mmds_oss.xy_oss_url'); + } + + private function getBucketName() + { + return $this->config->get('mmds_oss.xy_oss_bucket_name'); + } + + /** + * getSecretKey + * + * @return Oss + * @throws ContainerExceptionInterface + * @throws GuzzleException + * @throws NotFoundExceptionInterface + */ + private function bucket(): Oss + { + $this->getSecretKey(); + $time = time(); + $this->authorization = $this->oss['access_key_id'].':'.base64_encode( + hash_hmac('sha1', + $this->oss['secret_key'], + (string) $time, true)); + $bucket = $this->getBucketName(); + $client = $this->clientFactory->create([ + 'base_uri' => $this->getBaseUri(), + 'headers' => [ + 'filestorage-authorization' => $this->authorization, + 'timestamp' => $time, + 'Content-Type' => 'application/json' + ] + ]); + $path = '/backend/bucket'; + $response = $client->request('POST', $path, [ + 'json' => [ + 'bucket_name' => $bucket + ], + ]); + $data = json_decode($response->getBody()->getContents(), true); + if (isset($data['error_code']) && (int) $data['error_code'] == 200) { + $this->logger()->info('oss', $data); + } else { + throw new OssException($data['error_message'] ?? 'oss upload error', + $data['error_code'] ?? __LINE__); + } + return $this; + } + + /** + * getSecretKey + * + * @throws GuzzleException + */ + private function getSecretKey(): Oss + { + + if (!$this->oss) { + $client = $this->clientFactory->create([ + 'base_uri' => $this->getBaseUri(), + 'headers' => $this->request->getHeaders() + ]); + $path = '/backend/secretKey?'.http_build_query([ + 'service_name' => $this->config->get('mmds_oss.xy_oss_service_name'), + 'group_name' => $this->config->get('mmds_oss.xy_oss_group_name'), + ]); + + $response = $client->request('GET', $path); + $data = json_decode($response->getBody()->getContents(), true); + if (isset($data['error_code']) && (int) $data['error_code'] == 200) { + $this->oss = [ + 'access_key_id' => $data['result']['accessKeyId'] ?? null, + 'secret_key' => $data['result']['secretKey'] ?? null + ]; + + } else { + throw new OssException($data['error_message'] ?? 'oss error', + $data['error_code'] ?? __LINE__); + } + } + return $this; + } + + + /** + * logger + * + * @return LoggerInterface + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function logger(): LoggerInterface + { + return ApplicationContext::getContainer()->get(LoggerFactory::class)->get('oss'); + } +} \ No newline at end of file diff --git a/tests/Cases/AbstractTestCase.php b/tests/Cases/AbstractTestCase.php new file mode 100644 index 0000000..2274c20 --- /dev/null +++ b/tests/Cases/AbstractTestCase.php @@ -0,0 +1,21 @@ +assertTrue(true); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..6ce15df --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,12 @@ +