alibabacloud/green-20220302
Official Alibaba Cloud Green (content moderation) SDK for PHP, API version 20220302. Provides generated client classes for text, image, video, and audio moderation and risk detection, with Composer autoloading and PSR-friendly HTTP handling for Laravel/PHP applications.
This is a generated Alibaba Cloud SDK, not a Laravel package: no service provider, no config file, no facade. Treat it as a typed HTTP client and wrap it yourself.
composer require alibabacloud/green-20220302
Requirements: PHP >= 7.2 (fine on Laravel 10/11 on 8.1+), ext-curl, ext-json, ext-openssl. It pulls in alibabacloud/darabonba-openapi, alibabacloud/tea, and Guzzle via Composer — nothing to publish.
Where to look first
vendor/alibabacloud/green-20220302/src/Green.php — every callable API (textModeration, imageModeration, videoModeration, videoModerationResult, voiceModeration, fileModeration, describeUploadToken, *Feedback, plus *WithOptions variants).src/Models/*Request.php — the only accurate field reference; the SDK has no inline docs.service string values (nickname_detection, comment_detection, chat_detection, profile_detection, post_detection, ad_detection, …) — these are magic strings the SDK does not validate.README.md of the repo for the canonical bootstrap snippet (it is the entire documentation).Credential + endpoint setup (endpoint is mandatory and regional — there is no endpoint auto-resolution for Green):
// config/services.php
'green' => [
'access_key_id' => env('ALIYUN_ACCESS_KEY_ID'),
'access_key_secret' => env('ALIYUN_ACCESS_KEY_SECRET'),
'security_token' => env('ALIYUN_SECURITY_TOKEN'), // optional, for STS
'endpoint' => env('ALIYUN_GREEN_ENDPOINT', 'green-cip.cn-shanghai.aliyuncs.com'),
],
// AppServiceProvider::register()
$this->app->singleton(\AlibabaCloud\SDK\Green\V20220302\Green::class, function () {
$config = new \Darabonba\OpenApi\Models\Config([
'accessKeyId' => config('services.green.access_key_id'),
'accessKeySecret' => config('services.green.access_key_secret'),
'securityToken' => config('services.green.security_token') ?: null,
]);
$config->endpoint = config('services.green.endpoint');
return new \AlibabaCloud\SDK\Green\V20220302\Green($config);
});
First use case: moderate a comment body on create.
use AlibabaCloud\SDK\Green\V20220302\Models\TextModerationRequest;
$request = new TextModerationRequest([
'service' => 'comment_detection',
'serviceParameters' => json_encode(['content' => $comment], JSON_UNESCAPED_UNICODE),
]);
$response = app(Green::class)->textModeration($request);
// code 200 == "the API call worked", not "the content is clean"
$labels = $response->body->data->result ?? [];
Use the *WithOptions form as soon as you go live (timeouts + retries, see below); the plain methods use library defaults that are long enough to tie up PHP-FPM workers.
1. Wrap the client behind your own interface. The SDK returns deep Tea model objects; leaking them into controllers is painful and untestable.
interface Moderator {
public function text(string $content, string $service = 'comment_detection'): ModerationResult;
public function image(string $url, string $service = 'baselineCheck'): ModerationResult;
}
ModerationResult = small DTO (passed, label, confidence, action, raw). Map labels to actions in one place: porn|politics|terrorism|contraband → block, ad|abuse → review, nonLabel → allow.
2. Always call the *WithOptions variant.
use Darabonba\OpenApi\Models\RuntimeOptions;
$response = $client->textModerationWithOptions($request, new RuntimeOptions([
'connectTimeout' => 3000,
'readTimeout' => 8000,
'autoretry' => true,
'maxAttempts' => 2,
]));
3. Move moderation off the request path. Dispatch a job from an observer/event on model creation; store moderation_status (pending|approved|blocked|review) and a JSON moderation_labels column.
// CommentObserver::created()
ModerateComment::dispatch($comment)->onQueue('moderation');
4. Async APIs need a poller, not a sleep(). videoModeration / fileModeration / voiceModeration return a taskId; poll videoModerationResult in a queued job with backoff() and a hard attempt cap, or register the callback URL and expose a webhook route.
5. Dedupe/cache aggressively. Billing is per call and identical UGC (reposts, bots) is common:
$result = Cache::remember('green:text:'.sha1($service.$content), now()->addDay(),
fn () => $this->moderator->text($content, $service));
Only cache allow and high-confidence block results.
6. Custom validation rule for usernames/bios so the controller stays clean:
Validator::extend('moderated', fn ($attr, $value) => app(Moderator::class)
->text($value, 'nickname_detection')->passed);
7. Rate limiting per region. QPS quotas are per account/region; wrap calls with RateLimiter::for('green', fn () => Limit::perSecond(10)) if you fan out from queue workers.
8. Testing. Because the SDK speaks over its own Tea/Guzzle stack, Http::fake() does nothing. Bind a fake implementation of your Moderator interface in the container; unit-test the label→action mapping separately with hand-built ModerationResults.
9. Fail-open vs fail-closed explicitly. Moderation outages should not take down commenting. Return ModerationResult::pending() on transport errors, let content through, and reconcile later — except for high-risk surfaces (avatar/chat) where you should hold for review.
serviceParameters is a JSON string, not an array. Passing an array throws; double-json_encode-ing an already-encoded payload is the classic silent bug. Always json_encode([...], JSON_UNESCAPED_UNICODE) — escaped CJK makes logs useless and can subtly change what gets scanned.code === 200 ≠ clean content. The envelope says the call succeeded. Labels live at $response->body->data->result[] with label + confidence (0–100). data can be null — null-coalesce before iterating.porn, politics, terrorism, abuse, ad, contraband, flood, nonLabel. nonLabel means "no hit"; don't treat unknown labels as pass — default to review.green-cip.cn-shanghai.aliyuncs.com, ...cn-beijing..., ...ap-southeast-1.... A wrong region typically surfaces as an auth or InvalidRegionId error, not a clear "wrong endpoint" message.Tea\Exception\TeaError (getCode() gives InvalidParameter, Throttling, etc.; $e->data->Recommend often contains the fix). Transport/retry failures throw other exceptions. Catch \Throwable at the job boundary, log getCode() + getMessage() + getTraceAsString(), and keep the payload for replay.service strings are unvalidated. A typo produces a runtime business error, not a compile error. Put them in an enum or config constant.localhost/private-network URLs will fail.pending state, and expire stale tasks.connectTimeout/readTimeout and let autoretry handle blips.$config->httpProxy, $config->httpsProxy, $config->noProxy, $config->certConfig. Corporate proxies will otherwise fail with opaque connection errors.Green client in a queued job payload. It contains credentials and isn't serializable; store IDs/strings and resolve the singleton in handle().composer.lock is your friend, and read the diff before bumping.final, but subclassing buys you nothing; a thin Moderator wrapper lets you add caching, logging, metrics, and a fallback provider without touching call sites.How can I help you explore Laravel packages today?