, string): array)|null $transport */ public function __construct( ?callable $transport = null, ?CloudRequestSigner $signer = null ) { $this->transport = $transport ?? self::defaultTransport(); $this->signer = $signer ?? new CloudRequestSigner(); } /** * Verify license. * * @param CloudSettings $settings Cloud settings. * @param int $timestamp Unix timestamp. * @param string $nonce Nonce. * * @throws InvalidArgumentException When cloud settings are incomplete. * @throws RuntimeException When transport/response fails. */ public function verify( CloudSettings $settings, int $timestamp, string $nonce ): CloudLicenseVerificationResult { if ( ! $settings->isConfigured() ) { throw new InvalidArgumentException( 'affilun Cloud settings are not configured.' ); } $path = '/license/verify'; $payload = array( 'site_id' => $settings->siteId(), ); if ( function_exists( 'wp_json_encode' ) ) { $body = wp_json_encode( $payload ); } else { // phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode -- Pure-unit fallback when WordPress is unavailable. $body = json_encode( $payload ); } if ( ! is_string( $body ) ) { throw new RuntimeException( 'Failed to encode affilun Cloud verification request.' ); } $headers = $this->signer->sign( $settings->siteId(), $settings->apiKey(), 'POST', $path, $body, $timestamp, $nonce ); $headers['Content-Type'] = 'application/json'; $response = ( $this->transport )( $settings->endpoint() . $path, $headers, $body ); $status = isset( $response['status'] ) ? (int) $response['status'] : 0; $data = isset( $response['data'] ) && is_array( $response['data'] ) ? $response['data'] : null; if ( $status < 200 || $status >= 300 || $data === null ) { throw new RuntimeException( 'affilun Cloud license verification failed.' ); } return CloudLicenseVerificationResult::fromArray( $data ); } /** * Default WordPress HTTP transport. * * @return callable * * @phpstan-return callable(string, array, string): array */ private static function defaultTransport(): callable { return static function ( string $url, array $headers, string $body ): array { $response = CloudHttpOptions::safePost( $url, array( 'timeout' => 5, 'headers' => $headers, 'body' => $body, ) ); if ( is_wp_error( $response ) ) { throw new RuntimeException( 'affilun Cloud request failed.' ); } $code = (int) wp_remote_retrieve_response_code( $response ); $raw = (string) wp_remote_retrieve_body( $response ); $data = json_decode( $raw, true ); return array( 'status' => $code, 'data' => is_array( $data ) ? $data : null, ); }; } }