putBucket(new Oss\Models\PutBucketRequest($bucketName)); } public static function tearDownAfterClass(): void { //clean access points if (version_compare(PHP_VERSION, '8.0.0', '>=')) { self::deleteAccessPoint(self::getDefaultClient(), self::$bucketName); } //clean buckets self::cleanBucket(self::getDefaultClient(), self::$bucketName); //clean temp dir self::deleteDir(self::$tempDir); } static function getDefaultClient() { if (self::$defaultClient != null) { return self::$defaultClient; } $cfg = Oss\Config::loadDefault(); $cfg->setCredentialsProvider(new Oss\Credentials\StaticCredentialsProvider( self::$ACCESS_ID, self::$ACCESS_KEY )); $cfg->setRegion(self::$REGION); $cfg->setEndpoint(self::$ENDPOINT); self::$defaultClient = new Oss\Client($cfg); return self::$defaultClient; } static function getClient(string $ak, $sk, $region, $endpoint) { $cfg = Oss\Config::loadDefault(); $cfg->setCredentialsProvider(new Oss\Credentials\StaticCredentialsProvider( $ak, $sk )); $cfg->setRegion($region); if (!empty($endpoint)) { $cfg->setEndpoint($endpoint); } return new Oss\Client($cfg); } static function getInvalidAkClient() { if (self::$invalidAkClient != null) { return self::$invalidAkClient; } $cfg = Oss\Config::loadDefault(); $cfg->setCredentialsProvider(new Oss\Credentials\StaticCredentialsProvider( 'invalid-ak', 'invalid' )); $cfg->setRegion(self::$REGION); $cfg->setEndpoint(self::$ENDPOINT); self::$invalidAkClient = new Oss\Client($cfg); return self::$invalidAkClient; } public static function getTempFileName() { return tempnam(self::$tempDir, 'test'); } /** * @return Oss\Client|null * @throws \Throwable */ public function getClientUseStsToken() { try { $resp = $this->stsAssumeRole(self::$ACCESS_ID, self::$ACCESS_KEY, self::$RAM_ROLE_ARN); $accessKeyId = $resp['Credentials']['AccessKeyId']; $accessKeySecret = $resp['Credentials']['AccessKeySecret']; $token = $resp['Credentials']['SecurityToken']; $cfg = Oss\Config::loadDefault(); $cfg->setCredentialsProvider(new Oss\Credentials\StaticCredentialsProvider( $accessKeyId, $accessKeySecret, $token )); $cfg->setRegion(self::$REGION); $cfg->setEndpoint(self::$ENDPOINT); return new Oss\Client($cfg); } catch (\Throwable $e) { throw $e; } } private function stsAssumeRole($accessKeyId, $accessKeySecret, $roleArn) { // Constants $StsSignVersion = "1.0"; $StsAPIVersion = "2015-04-01"; $StsHost = "https://sts.aliyuncs.com/"; $TimeFormat = "Y-m-d\TH:i:s\Z"; $RespBodyFormat = "JSON"; $PercentEncode = "%2F"; $HTTPGet = "GET"; $uuid = "Nonce-" . rand(1000, 9999); $currentTime = (new \DateTime('now', new \DateTimeZone('UTC')))->format($TimeFormat); $queryStr = http_build_query([ "SignatureVersion" => $StsSignVersion, "Format" => $RespBodyFormat, "Timestamp" => $currentTime, "RoleArn" => $roleArn, "RoleSessionName" => "oss_test_sess", "AccessKeyId" => $accessKeyId, "SignatureMethod" => "HMAC-SHA1", "Version" => $StsAPIVersion, "Action" => "AssumeRole", "SignatureNonce" => $uuid, "DurationSeconds" => 3600 ]); parse_str($queryStr, $queryParams); ksort($queryParams); $queryStr = http_build_query($queryParams); $strToSign = $HTTPGet . "&" . $PercentEncode . "&" . rawurlencode($queryStr); $signature = base64_encode(hash_hmac('sha1', $strToSign, $accessKeySecret . "&", true)); $assumeURL = $StsHost . "?" . $queryStr . "&Signature=" . urlencode($signature); $httpClient = new \GuzzleHttp\Client(); try { $resp = $httpClient->get($assumeURL); $result = json_decode($resp->getBody()->getContents(), true); if (json_last_error() !== JSON_ERROR_NONE) { throw new \Exception("Failed to decode JSON response"); } return $result; } catch (\Throwable $e) { throw $e; } } public static function randomBucketName() { return self::$BUCKETNAME_PREFIX . strval(rand(0, 100)) . '-' . strval(time()); } public static function randomObjectName() { return self::$OBJECTNAME_PREFIX . strval(rand(0, 100)) . '-' . strval(time()); } public static function randomLowStr() { self::$BUCKETNAME_PREFIX . strval(rand(0, 100)) . '-' . strval(time()); } public static function randomStr() { self::$BUCKETNAME_PREFIX . strval(rand(0, 100)) . '-' . strval(time()); } public static function waitFor(float $sec) { usleep((int)($sec * 1000000)); } public static function cleanBucket(Oss\Client $client, string $bucketName): void { //delete Objects $paginator = new Oss\Paginator\ListObjectsPaginator($client); $iter = $paginator->iterPage(new Oss\Models\ListObjectsRequest($bucketName)); foreach ($iter as $page) { $objects = []; foreach ($page->contents ?? [] as $content) { $objects[] = new Oss\Models\DeleteObject($content->key); } if (!empty($objects)) { $client->deleteMultipleObjects(new Oss\Models\DeleteMultipleObjectsRequest( $bucketName, $objects )); } } //delete uploadpart $paginator = new Oss\Paginator\ListMultipartUploadsPaginator($client); $iter = $paginator->iterPage(new Oss\Models\ListMultipartUploadsRequest($bucketName)); foreach ($iter as $page) { foreach ($page->uploads ?? [] as $upload) { $client->abortMultipartUpload(new Oss\Models\AbortMultipartUploadRequest( $bucketName, $upload->key, $upload->uploadId )); } } $client->deleteBucket(new Oss\Models\DeleteBucketRequest($bucketName)); } public static function deleteDir(string $dir): void { if (!is_dir($dir)) { return; } if ($handle = opendir($dir)) { while (($entry = readdir($handle)) !== false) { if ($entry == '.' || $entry == '..') { continue; } $file = $dir . DIRECTORY_SEPARATOR . $entry; if (is_dir($file)) { self::deleteDir($file); } else { unlink($file); } } closedir($handle); } rmdir($dir); } public static function getDataPath(): string { return dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'Data'; } public static function deleteAccessPoint(Oss\Client $client, string $bucketName): void { $listRequest = new Oss\Models\ListAccessPointsRequest(); $listRequest->bucket = $bucketName; while (true) { $listResult = $client->listAccessPoints($listRequest); if (isset($listResult->listAccessPoints->accessPoints->accessPoints) && count($listResult->listAccessPoints->accessPoints->accessPoints) > 0) { foreach ($listResult->listAccessPoints->accessPoints->accessPoints as $accessPoint) { switch ($accessPoint->status) { case 'creating': sleep(3); while (true) { $getResult = $client->getAccessPoint(new Oss\Models\GetAccessPointRequest( $bucketName, $accessPoint->accessPointName )); if ($getResult->getAccessPoint->status != 'creating') { break; } else { sleep(3); } } $client->deleteAccessPoint(new Oss\Models\DeleteAccessPointRequest( $bucketName, $accessPoint->accessPointName )); break; case 'deleting': sleep(5); break; default: $client->deleteAccessPoint(new Oss\Models\DeleteAccessPointRequest( $bucketName, $accessPoint->accessPointName )); break; } while (true) { try { $client->getAccessPoint(new Oss\Models\GetAccessPointRequest( $bucketName, $accessPoint->accessPointName )); } catch (Oss\Exception\OperationException $e) { $se = $e->getPrevious(); if ($se instanceof Oss\Exception\ServiceException) { if ($se->getErrorCode() == 'NoSuchAccessPoint' && $se->getStatusCode() == 404) { break; } } } sleep(3); } } if ($listResult->listAccessPoints->isTruncated == false) { break; } if ($listResult->listAccessPoints->nextContinuationToken != "") { $listRequest->continuationToken = $listResult->listAccessPoints->nextContinuationToken; } } else { break; } } } /** * @param $filename * @param $size */ public function generateFile($filename, $size) { if ( file_exists($filename) && $size == sprintf('%u', filesize($filename)) ) { return; } $part_size = 32; $fp = fopen($filename, "w"); $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $charactersLength = strlen($characters); if ($fp) { while ($size > 0) { if ($size < $part_size) { $write_size = $size; } else { $write_size = $part_size; } $size -= $write_size; $a = $characters[rand(0, $charactersLength - 1)]; $content = str_repeat($a, $write_size); $flag = fwrite($fp, $content); if (!$flag) { $this->assertTrue(false, "write to $filename failed."); break; } } } else { $this->assertTrue(false, "open $filename failed."); } fclose($fp); } public function object_get_contents($client, $bucket, $key): string { $result = $client->getObject(new Oss\Models\GetObjectRequest( self::$bucketName, $key, )); $this->assertEquals(200, $result->statusCode); $this->assertEquals('OK', $result->status); return $result->body->getContents(); } public function object_get_content_type($client, $bucket, $key): string { $result = $client->headObject(new Oss\Models\HeadObjectRequest( self::$bucketName, $key, )); $this->assertEquals(200, $result->statusCode); $this->assertEquals('OK', $result->status); return $result->contentType; } }