vendor/aws/aws-sdk-php/src/ClientResolver.php line 400

Open in your IDE?
  1. <?php
  2. namespace Aws;
  3. use Aws\Api\ApiProvider;
  4. use Aws\Api\Service;
  5. use Aws\Api\Validator;
  6. use Aws\Auth\AuthResolver;
  7. use Aws\Auth\AuthSchemeResolver;
  8. use Aws\Auth\AuthSchemeResolverInterface;
  9. use Aws\ClientSideMonitoring\ApiCallAttemptMonitoringMiddleware;
  10. use Aws\ClientSideMonitoring\ApiCallMonitoringMiddleware;
  11. use Aws\ClientSideMonitoring\Configuration;
  12. use Aws\Configuration\ConfigurationResolver;
  13. use Aws\Credentials\CredentialProvider;
  14. use Aws\Credentials\Credentials;
  15. use Aws\Credentials\CredentialsInterface;
  16. use Aws\DefaultsMode\ConfigurationInterface as ConfigModeInterface;
  17. use Aws\DefaultsMode\ConfigurationProvider as ConfigModeProvider;
  18. use Aws\Endpoint\EndpointProvider;
  19. use Aws\Endpoint\PartitionEndpointProvider;
  20. use Aws\Endpoint\UseDualstackEndpoint\Configuration as UseDualStackEndpointConfiguration;
  21. use Aws\Endpoint\UseDualstackEndpoint\ConfigurationInterface as UseDualStackEndpointConfigurationInterface;
  22. use Aws\Endpoint\UseDualstackEndpoint\ConfigurationProvider as UseDualStackConfigProvider;
  23. use Aws\Endpoint\UseFipsEndpoint\Configuration as UseFipsEndpointConfiguration;
  24. use Aws\Endpoint\UseFipsEndpoint\ConfigurationInterface as UseFipsEndpointConfigurationInterface;
  25. use Aws\Endpoint\UseFipsEndpoint\ConfigurationProvider as UseFipsConfigProvider;
  26. use Aws\EndpointDiscovery\ConfigurationInterface;
  27. use Aws\EndpointDiscovery\ConfigurationProvider;
  28. use Aws\EndpointV2\EndpointDefinitionProvider;
  29. use Aws\Exception\AwsException;
  30. use Aws\Exception\InvalidRegionException;
  31. use Aws\Retry\ConfigurationInterface as RetryConfigInterface;
  32. use Aws\Retry\ConfigurationProvider as RetryConfigProvider;
  33. use Aws\Signature\SignatureProvider;
  34. use Aws\Token\Token;
  35. use Aws\Token\TokenInterface;
  36. use Aws\Token\TokenProvider;
  37. use GuzzleHttp\Promise\PromiseInterface;
  38. use InvalidArgumentException as IAE;
  39. use Psr\Http\Message\RequestInterface;
  40. /**
  41.  * @internal Resolves a hash of client arguments to construct a client.
  42.  */
  43. class ClientResolver
  44. {
  45.     /** @var array */
  46.     private $argDefinitions;
  47.     /**
  48.      * When using this option as default please make sure that, your config
  49.      * has at least one data type defined in `valid` otherwise it will be
  50.      * defaulted to `string`. Also, the default value will be the falsy value
  51.      * based on the resolved data type. For example, the default for `string`
  52.      * will be `''` and for bool will be `false`.
  53.      *
  54.      * @var string
  55.      */
  56.     const DEFAULT_FROM_ENV_INI = [
  57.         __CLASS__,
  58.         '_resolve_from_env_ini'
  59.     ];
  60.     /** @var array Map of types to a corresponding function */
  61.     private static $typeMap = [
  62.         'resource' => 'is_resource',
  63.         'callable' => 'is_callable',
  64.         'int'      => 'is_int',
  65.         'bool'     => 'is_bool',
  66.         'boolean'  => 'is_bool',
  67.         'string'   => 'is_string',
  68.         'object'   => 'is_object',
  69.         'array'    => 'is_array',
  70.     ];
  71.     private static $defaultArgs = [
  72.         'service' => [
  73.             'type'     => 'value',
  74.             'valid'    => ['string'],
  75.             'doc'      => 'Name of the service to utilize. This value will be supplied by default when using one of the SDK clients (e.g., Aws\\S3\\S3Client).',
  76.             'required' => true,
  77.             'internal' => true
  78.         ],
  79.         'exception_class' => [
  80.             'type'     => 'value',
  81.             'valid'    => ['string'],
  82.             'doc'      => 'Exception class to create when an error occurs.',
  83.             'default'  => AwsException::class,
  84.             'internal' => true
  85.         ],
  86.         'scheme' => [
  87.             'type'     => 'value',
  88.             'valid'    => ['string'],
  89.             'default'  => 'https',
  90.             'doc'      => 'URI scheme to use when connecting connect. The SDK will utilize "https" endpoints (i.e., utilize SSL/TLS connections) by default. You can attempt to connect to a service over an unencrypted "http" endpoint by setting ``scheme`` to "http".',
  91.         ],
  92.         'disable_host_prefix_injection' => [
  93.             'type'      => 'value',
  94.             'valid'     => ['bool'],
  95.             'doc'       => 'Set to true to disable host prefix injection logic for services that use it. This disables the entire prefix injection, including the portions supplied by user-defined parameters. Setting this flag will have no effect on services that do not use host prefix injection.',
  96.             'default'   => false,
  97.         ],
  98.         'ignore_configured_endpoint_urls' => [
  99.             'type'      => 'value',
  100.             'valid'     => ['bool'],
  101.             'doc'       => 'Set to true to disable endpoint urls configured using `AWS_ENDPOINT_URL` and `endpoint_url` shared config option.',
  102.             'fn'        => [__CLASS__'_apply_ignore_configured_endpoint_urls'],
  103.             'default'   => self::DEFAULT_FROM_ENV_INI,
  104.         ],
  105.         'endpoint' => [
  106.             'type'  => 'value',
  107.             'valid' => ['string'],
  108.             'doc'   => 'The full URI of the webservice. This is only required when connecting to a custom endpoint (e.g., a local version of S3).',
  109.             'fn'    => [__CLASS__'_apply_endpoint'],
  110.             'default'   => [__CLASS__'_default_endpoint']
  111.         ],
  112.         'region' => [
  113.             'type'     => 'value',
  114.             'valid'    => ['string'],
  115.             'doc'      => 'Region to connect to. See http://docs.aws.amazon.com/general/latest/gr/rande.html for a list of available regions.',
  116.             'fn'       => [__CLASS__'_apply_region'],
  117.             'default'  => self::DEFAULT_FROM_ENV_INI
  118.         ],
  119.         'version' => [
  120.             'type'     => 'value',
  121.             'valid'    => ['string'],
  122.             'doc'      => 'The version of the webservice to utilize (e.g., 2006-03-01).',
  123.             'default' => 'latest',
  124.         ],
  125.         'signature_provider' => [
  126.             'type'    => 'value',
  127.             'valid'   => ['callable'],
  128.             'doc'     => 'A callable that accepts a signature version name (e.g., "v4"), a service name, and region, and  returns a SignatureInterface object or null. This provider is used to create signers utilized by the client. See Aws\\Signature\\SignatureProvider for a list of built-in providers',
  129.             'default' => [__CLASS__'_default_signature_provider'],
  130.         ],
  131.         'api_provider' => [
  132.             'type'     => 'value',
  133.             'valid'    => ['callable'],
  134.             'doc'      => 'An optional PHP callable that accepts a type, service, and version argument, and returns an array of corresponding configuration data. The type value can be one of api, waiter, or paginator.',
  135.             'fn'       => [__CLASS__'_apply_api_provider'],
  136.             'default'  => [ApiProvider::class, 'defaultProvider'],
  137.         ],
  138.         'configuration_mode' => [
  139.             'type'    => 'value',
  140.             'valid'   => [ConfigModeInterface::class, CacheInterface::class, 'string''closure'],
  141.             'doc'     => "Sets the default configuration mode. Otherwise provide an instance of Aws\DefaultsMode\ConfigurationInterface, an instance of  Aws\CacheInterface, or a string containing a valid mode",
  142.             'fn'      => [__CLASS__'_apply_defaults'],
  143.             'default' => [ConfigModeProvider::class, 'defaultProvider']
  144.         ],
  145.         'use_fips_endpoint' => [
  146.             'type'      => 'value',
  147.             'valid'     => ['bool'UseFipsEndpointConfiguration::class, CacheInterface::class, 'callable'],
  148.             'doc'       => 'Set to true to enable the use of FIPS pseudo regions',
  149.             'fn'        => [__CLASS__'_apply_use_fips_endpoint'],
  150.             'default'   => [__CLASS__'_default_use_fips_endpoint'],
  151.         ],
  152.         'use_dual_stack_endpoint' => [
  153.             'type'      => 'value',
  154.             'valid'     => ['bool'UseDualStackEndpointConfiguration::class, CacheInterface::class, 'callable'],
  155.             'doc'       => 'Set to true to enable the use of dual-stack endpoints',
  156.             'fn'        => [__CLASS__'_apply_use_dual_stack_endpoint'],
  157.             'default'   => [__CLASS__'_default_use_dual_stack_endpoint'],
  158.         ],
  159.         'endpoint_provider' => [
  160.             'type'     => 'value',
  161.             'valid'    => ['callable'EndpointV2\EndpointProviderV2::class],
  162.             'fn'       => [__CLASS__'_apply_endpoint_provider'],
  163.             'doc'      => 'An optional PHP callable that accepts a hash of options including a "service" and "region" key and returns NULL or a hash of endpoint data, of which the "endpoint" key is required. See Aws\\Endpoint\\EndpointProvider for a list of built-in providers.',
  164.             'default'  => [__CLASS__'_default_endpoint_provider'],
  165.         ],
  166.         'serializer' => [
  167.             'default'   => [__CLASS__'_default_serializer'],
  168.             'fn'        => [__CLASS__'_apply_serializer'],
  169.             'internal'  => true,
  170.             'type'      => 'value',
  171.             'valid'     => ['callable'],
  172.         ],
  173.         'signature_version' => [
  174.             'type'    => 'config',
  175.             'valid'   => ['string'],
  176.             'doc'     => 'A string representing a custom signature version to use with a service (e.g., v4). Note that per/operation signature version MAY override this requested signature version.',
  177.             'default' => [__CLASS__'_default_signature_version'],
  178.         ],
  179.         'signing_name' => [
  180.             'type'    => 'config',
  181.             'valid'   => ['string'],
  182.             'doc'     => 'A string representing a custom service name to be used when calculating a request signature.',
  183.             'default' => [__CLASS__'_default_signing_name'],
  184.         ],
  185.         'signing_region' => [
  186.             'type'    => 'config',
  187.             'valid'   => ['string'],
  188.             'doc'     => 'A string representing a custom region name to be used when calculating a request signature.',
  189.             'default' => [__CLASS__'_default_signing_region'],
  190.         ],
  191.         'profile' => [
  192.             'type'  => 'config',
  193.             'valid' => ['string'],
  194.             'doc'   => 'Allows you to specify which profile to use when credentials are created from the AWS credentials file in your HOME directory. This setting overrides the AWS_PROFILE environment variable. Note: Specifying "profile" will cause the "credentials" and "use_aws_shared_config_files" keys to be ignored.',
  195.             'fn'    => [__CLASS__'_apply_profile'],
  196.         ],
  197.         'credentials' => [
  198.             'type'    => 'value',
  199.             'valid'   => [CredentialsInterface::class, CacheInterface::class, 'array''bool''callable'],
  200.             'doc'     => 'Specifies the credentials used to sign requests. Provide an Aws\Credentials\CredentialsInterface object, an associative array of "key", "secret", and an optional "token" key, `false` to use null credentials, or a callable credentials provider used to create credentials or return null. See Aws\\Credentials\\CredentialProvider for a list of built-in credentials providers. If no credentials are provided, the SDK will attempt to load them from the environment.',
  201.             'fn'      => [__CLASS__'_apply_credentials'],
  202.             'default' => [__CLASS__'_default_credential_provider'],
  203.         ],
  204.         'token' => [
  205.             'type'    => 'value',
  206.             'valid'   => [TokenInterface::class, CacheInterface::class, 'array''bool''callable'],
  207.             'doc'     => 'Specifies the token used to authorize requests. Provide an Aws\Token\TokenInterface object, an associative array of "token", and an optional "expiration" key, `false` to use a null token, or a callable token provider used to fetch a token or return null. See Aws\\Token\\TokenProvider for a list of built-in credentials providers. If no token is provided, the SDK will attempt to load one from the environment.',
  208.             'fn'      => [__CLASS__'_apply_token'],
  209.             'default' => [__CLASS__'_default_token_provider'],
  210.         ],
  211.         'auth_scheme_resolver' => [
  212.             'type'    => 'value',
  213.             'valid'   => [AuthSchemeResolverInterface::class],
  214.             'doc'     => 'An instance of Aws\Auth\AuthSchemeResolverInterface which selects a modeled auth scheme and returns a signature version',
  215.             'default' => [__CLASS__'_default_auth_scheme_resolver'],
  216.         ],
  217.         'endpoint_discovery' => [
  218.             'type'     => 'value',
  219.             'valid'    => [ConfigurationInterface::class, CacheInterface::class, 'array''callable'],
  220.             'doc'      => 'Specifies settings for endpoint discovery. Provide an instance of Aws\EndpointDiscovery\ConfigurationInterface, an instance Aws\CacheInterface, a callable that provides a promise for a Configuration object, or an associative array with the following keys: enabled: (bool) Set to true to enable endpoint discovery, false to explicitly disable it. Defaults to false; cache_limit: (int) The maximum number of keys in the endpoints cache. Defaults to 1000.',
  221.             'fn'       => [__CLASS__'_apply_endpoint_discovery'],
  222.             'default'  => [__CLASS__'_default_endpoint_discovery_provider']
  223.         ],
  224.         'stats' => [
  225.             'type'  => 'value',
  226.             'valid' => ['bool''array'],
  227.             'default' => false,
  228.             'doc'   => 'Set to true to gather transfer statistics on requests sent. Alternatively, you can provide an associative array with the following keys: retries: (bool) Set to false to disable reporting on retries attempted; http: (bool) Set to true to enable collecting statistics from lower level HTTP adapters (e.g., values returned in GuzzleHttp\TransferStats). HTTP handlers must support an http_stats_receiver option for this to have an effect; timer: (bool) Set to true to enable a command timer that reports the total wall clock time spent on an operation in seconds.',
  229.             'fn'    => [__CLASS__'_apply_stats'],
  230.         ],
  231.         'retries' => [
  232.             'type'    => 'value',
  233.             'valid'   => ['int'RetryConfigInterface::class, CacheInterface::class, 'callable''array'],
  234.             'doc'     => "Configures the retry mode and maximum number of allowed retries for a client (pass 0 to disable retries). Provide an integer for 'legacy' mode with the specified number of retries. Otherwise provide an instance of Aws\Retry\ConfigurationInterface, an instance of  Aws\CacheInterface, a callable function, or an array with the following keys: mode: (string) Set to 'legacy', 'standard' (uses retry quota management), or 'adapative' (an experimental mode that adds client-side rate limiting to standard mode); max_attempts: (int) The maximum number of attempts for a given request. ",
  235.             'fn'      => [__CLASS__'_apply_retries'],
  236.             'default' => [RetryConfigProvider::class, 'defaultProvider']
  237.         ],
  238.         'validate' => [
  239.             'type'    => 'value',
  240.             'valid'   => ['bool''array'],
  241.             'default' => true,
  242.             'doc'     => 'Set to false to disable client-side parameter validation. Set to true to utilize default validation constraints. Set to an associative array of validation options to enable specific validation constraints.',
  243.             'fn'      => [__CLASS__'_apply_validate'],
  244.         ],
  245.         'debug' => [
  246.             'type'  => 'value',
  247.             'valid' => ['bool''array'],
  248.             'doc'   => 'Set to true to display debug information when sending requests. Alternatively, you can provide an associative array with the following keys: logfn: (callable) Function that is invoked with log messages; stream_size: (int) When the size of a stream is greater than this number, the stream data will not be logged (set to "0" to not log any stream data); scrub_auth: (bool) Set to false to disable the scrubbing of auth data from the logged messages; http: (bool) Set to false to disable the "debug" feature of lower level HTTP adapters (e.g., verbose curl output).',
  249.             'fn'    => [__CLASS__'_apply_debug'],
  250.         ],
  251.         'disable_request_compression' => [
  252.             'type'      => 'value',
  253.             'valid'     => ['bool''callable'],
  254.             'doc'       => 'Set to true to disable request compression for supported operations',
  255.             'fn'        => [__CLASS__'_apply_disable_request_compression'],
  256.             'default'   => self::DEFAULT_FROM_ENV_INI,
  257.         ],
  258.         'request_min_compression_size_bytes' => [
  259.             'type'      => 'value',
  260.             'valid'     => ['int''callable'],
  261.             'doc'       => 'Set to a value between between 0 and 10485760 bytes, inclusive. This value will be ignored if `disable_request_compression` is set to `true`',
  262.             'fn'        => [__CLASS__'_apply_min_compression_size'],
  263.             'default'   => [__CLASS__'_default_min_compression_size'],
  264.         ],
  265.         'csm' => [
  266.             'type'     => 'value',
  267.             'valid'    => [\Aws\ClientSideMonitoring\ConfigurationInterface::class, 'callable''array''bool'],
  268.             'doc'      => 'CSM options for the client. Provides a callable wrapping a promise, a boolean "false", an instance of ConfigurationInterface, or an associative array of "enabled", "host", "port", and "client_id".',
  269.             'fn'       => [__CLASS__'_apply_csm'],
  270.             'default'  => [\Aws\ClientSideMonitoring\ConfigurationProvider::class, 'defaultProvider']
  271.         ],
  272.         'http' => [
  273.             'type'    => 'value',
  274.             'valid'   => ['array'],
  275.             'default' => [],
  276.             'doc'     => 'Set to an array of SDK request options to apply to each request (e.g., proxy, verify, etc.).',
  277.         ],
  278.         'http_handler' => [
  279.             'type'    => 'value',
  280.             'valid'   => ['callable'],
  281.             'doc'     => 'An HTTP handler is a function that accepts a PSR-7 request object and returns a promise that is fulfilled with a PSR-7 response object or rejected with an array of exception data. NOTE: This option supersedes any provided "handler" option.',
  282.             'fn'      => [__CLASS__'_apply_http_handler']
  283.         ],
  284.         'handler' => [
  285.             'type'     => 'value',
  286.             'valid'    => ['callable'],
  287.             'doc'      => 'A handler that accepts a command object, request object and returns a promise that is fulfilled with an Aws\ResultInterface object or rejected with an Aws\Exception\AwsException. A handler does not accept a next handler as it is terminal and expected to fulfill a command. If no handler is provided, a default Guzzle handler will be utilized.',
  288.             'fn'       => [__CLASS__'_apply_handler'],
  289.             'default'  => [__CLASS__'_default_handler']
  290.         ],
  291.         'app_id' => [
  292.             'type' => 'value',
  293.             'valid' => ['string'],
  294.             'doc' => 'app_id(AppId) is an optional application specific identifier that can be set. 
  295.              When set it will be appended to the User-Agent header of every request in the form of App/{AppId}. 
  296.              This value is also sourced from environment variable AWS_SDK_UA_APP_ID or the shared config profile attribute sdk_ua_app_id.',
  297.             'fn' => [__CLASS__'_apply_app_id'],
  298.             'default' => [__CLASS__'_default_app_id']
  299.         ],
  300.         'ua_append' => [
  301.             'type'     => 'value',
  302.             'valid'    => ['string''array'],
  303.             'doc'      => 'Provide a string or array of strings to send in the User-Agent header.',
  304.             'fn'       => [__CLASS__'_apply_user_agent'],
  305.             'default'  => [],
  306.         ],
  307.         'idempotency_auto_fill' => [
  308.             'type'      => 'value',
  309.             'valid'     => ['bool''callable'],
  310.             'doc'       => 'Set to false to disable SDK to populate parameters that enabled \'idempotencyToken\' trait with a random UUID v4 value on your behalf. Using default value \'true\' still allows parameter value to be overwritten when provided. Note: auto-fill only works when cryptographically secure random bytes generator functions(random_bytes, openssl_random_pseudo_bytes or mcrypt_create_iv) can be found. You may also provide a callable source of random bytes.',
  311.             'default'   => true,
  312.             'fn'        => [__CLASS__'_apply_idempotency_auto_fill']
  313.         ],
  314.         'use_aws_shared_config_files' => [
  315.             'type'      => 'value',
  316.             'valid'     => ['bool'],
  317.             'doc'       => 'Set to false to disable checking for shared aws config files usually located in \'~/.aws/config\' and \'~/.aws/credentials\'.  This will be ignored if you set the \'profile\' setting.',
  318.             'default'   => true,
  319.         ],
  320.         'suppress_php_deprecation_warning' => [
  321.             'type'      => 'value',
  322.             'valid'     => ['bool'],
  323.             'doc' => 'Set to true to suppress PHP runtime deprecation warnings. The current deprecation campaign is PHP versions 8.0.x and below, taking effect on 1/13/2025.',
  324.             'default' => false,
  325.             'fn' => [__CLASS__'_apply_suppress_php_deprecation_warning']
  326.         ],
  327.         'account_id_endpoint_mode' => [
  328.             'type'      => 'value',
  329.             'valid'     => ['string'],
  330.             'doc'       => 'Decides whether account_id must a be a required resolved credentials property. If this configuration is set to disabled, then account_id is not required. If set to preferred a warning will be logged when account_id is not resolved, and when set to required an exception will be thrown if account_id is not resolved.',
  331.             'default'  => [__CLASS__'_default_account_id_endpoint_mode'],
  332.             'fn'       => [__CLASS__'_apply_account_id_endpoint_mode']
  333.         ],
  334.         'sigv4a_signing_region_set' => [
  335.             'type' => 'value',
  336.             'valid' => ['string''array'],
  337.             'doc' => 'A comma-delimited list of supported regions sent in sigv4a requests.',
  338.             'fn' => [__CLASS__'_apply_sigv4a_signing_region_set'],
  339.             'default' => self::DEFAULT_FROM_ENV_INI
  340.         ]
  341.     ];
  342.     /**
  343.      * Gets an array of default client arguments, each argument containing a
  344.      * hash of the following:
  345.      *
  346.      * - type: (string, required) option type described as follows:
  347.      *   - value: The default option type.
  348.      *   - config: The provided value is made available in the client's
  349.      *     getConfig() method.
  350.      * - valid: (array, required) Valid PHP types or class names. Note: null
  351.      *   is not an allowed type.
  352.      * - required: (bool, callable) Whether or not the argument is required.
  353.      *   Provide a function that accepts an array of arguments and returns a
  354.      *   string to provide a custom error message.
  355.      * - default: (mixed) The default value of the argument if not provided. If
  356.      *   a function is provided, then it will be invoked to provide a default
  357.      *   value. The function is provided the array of options and is expected
  358.      *   to return the default value of the option. The default value can be a
  359.      *   closure and can not be a callable string that is not  part of the
  360.      *   defaultArgs array.
  361.      * - doc: (string) The argument documentation string.
  362.      * - fn: (callable) Function used to apply the argument. The function
  363.      *   accepts the provided value, array of arguments by reference, and an
  364.      *   event emitter.
  365.      *
  366.      * Note: Order is honored and important when applying arguments.
  367.      *
  368.      * @return array
  369.      */
  370.     public static function getDefaultArguments()
  371.     {
  372.         return self::$defaultArgs;
  373.     }
  374.     /**
  375.      * @param array $argDefinitions Client arguments.
  376.      */
  377.     public function __construct(array $argDefinitions)
  378.     {
  379.         $this->argDefinitions $argDefinitions;
  380.     }
  381.     /**
  382.      * Resolves client configuration options and attached event listeners.
  383.      * Check for missing keys in passed arguments
  384.      *
  385.      * @param array       $args Provided constructor arguments.
  386.      * @param HandlerList $list Handler list to augment.
  387.      *
  388.      * @return array Returns the array of provided options.
  389.      * @throws \InvalidArgumentException
  390.      * @see Aws\AwsClient::__construct for a list of available options.
  391.      */
  392.     public function resolve(array $argsHandlerList $list)
  393.     {
  394.         $args['config'] = [];
  395.         foreach ($this->argDefinitions as $key => $a) {
  396.             // Add defaults, validate required values, and skip if not set.
  397.             if (!isset($args[$key])) {
  398.                 if (isset($a['default'])) {
  399.                     // Merge defaults in when not present.
  400.                     if (is_callable($a['default'])
  401.                         && (
  402.                             is_array($a['default'])
  403.                             || $a['default'] instanceof \Closure
  404.                         )
  405.                     ) {
  406.                         if ($a['default'] === self::DEFAULT_FROM_ENV_INI) {
  407.                             $args[$key] = $a['default'](
  408.                                 $key,
  409.                                 $a['valid'][0] ?? 'string',
  410.                                 $args
  411.                             );
  412.                         } else {
  413.                             $args[$key] = $a['default']($args);
  414.                         }
  415.                     } else {
  416.                         $args[$key] = $a['default'];
  417.                     }
  418.                 } elseif (empty($a['required'])) {
  419.                     continue;
  420.                 } else {
  421.                     $this->throwRequired($args);
  422.                 }
  423.             }
  424.             // Validate the types against the provided value.
  425.             foreach ($a['valid'] as $check) {
  426.                 if (isset(self::$typeMap[$check])) {
  427.                     $fn self::$typeMap[$check];
  428.                     if ($fn($args[$key])) {
  429.                         goto is_valid;
  430.                     }
  431.                 } elseif ($args[$key] instanceof $check) {
  432.                     goto is_valid;
  433.                 }
  434.             }
  435.             $this->invalidType($key$args[$key]);
  436.             // Apply the value
  437.             is_valid:
  438.             if (isset($a['fn'])) {
  439.                 $a['fn']($args[$key], $args$list);
  440.             }
  441.             if ($a['type'] === 'config') {
  442.                 $args['config'][$key] = $args[$key];
  443.             }
  444.         }
  445.         $this->_apply_client_context_params($args);
  446.         return $args;
  447.     }
  448.     /**
  449.      * Creates a verbose error message for an invalid argument.
  450.      *
  451.      * @param string $name        Name of the argument that is missing.
  452.      * @param array  $args        Provided arguments
  453.      * @param bool   $useRequired Set to true to show the required fn text if
  454.      *                            available instead of the documentation.
  455.      * @return string
  456.      */
  457.     private function getArgMessage($name$args = [], $useRequired false)
  458.     {
  459.         $arg $this->argDefinitions[$name];
  460.         $msg '';
  461.         $modifiers = [];
  462.         if (isset($arg['valid'])) {
  463.             $modifiers[] = implode('|'$arg['valid']);
  464.         }
  465.         if (isset($arg['choice'])) {
  466.             $modifiers[] = 'One of ' implode(', '$arg['choice']);
  467.         }
  468.         if ($modifiers) {
  469.             $msg .= '(' implode('; '$modifiers) . ')';
  470.         }
  471.         $msg wordwrap("{$name}{$msg}"75"\n  ");
  472.         if ($useRequired && is_callable($arg['required'])) {
  473.             $msg .= "\n\n  ";
  474.             $msg .= str_replace("\n""\n  "call_user_func($arg['required'], $args));
  475.         } elseif (isset($arg['doc'])) {
  476.             $msg .= wordwrap("\n\n  {$arg['doc']}"75"\n  ");
  477.         }
  478.         return $msg;
  479.     }
  480.     /**
  481.      * Throw when an invalid type is encountered.
  482.      *
  483.      * @param string $name     Name of the value being validated.
  484.      * @param mixed  $provided The provided value.
  485.      * @throws \InvalidArgumentException
  486.      */
  487.     private function invalidType($name$provided)
  488.     {
  489.         $expected implode('|'$this->argDefinitions[$name]['valid']);
  490.         $msg "Invalid configuration value "
  491.             "provided for \"{$name}\". Expected {$expected}, but got "
  492.             describe_type($provided) . "\n\n"
  493.             $this->getArgMessage($name);
  494.         throw new IAE($msg);
  495.     }
  496.     /**
  497.      * Throws an exception for missing required arguments.
  498.      *
  499.      * @param array $args Passed in arguments.
  500.      * @throws \InvalidArgumentException
  501.      */
  502.     private function throwRequired(array $args)
  503.     {
  504.         $missing = [];
  505.         foreach ($this->argDefinitions as $k => $a) {
  506.             if (empty($a['required'])
  507.                 || isset($a['default'])
  508.                 || isset($args[$k])
  509.             ) {
  510.                 continue;
  511.             }
  512.             $missing[] = $this->getArgMessage($k$argstrue);
  513.         }
  514.         $msg "Missing required client configuration options: \n\n";
  515.         $msg .= implode("\n\n"$missing);
  516.         throw new IAE($msg);
  517.     }
  518.     public static function _apply_retries($value, array &$argsHandlerList $list)
  519.     {
  520.         // A value of 0 for the config option disables retries
  521.         if ($value) {
  522.             $config RetryConfigProvider::unwrap($value);
  523.             if ($config->getMode() === 'legacy') {
  524.                 // # of retries is 1 less than # of attempts
  525.                 $decider RetryMiddleware::createDefaultDecider(
  526.                     $config->getMaxAttempts() - 1
  527.                 );
  528.                 $list->appendSign(
  529.                     Middleware::retry($decidernull$args['stats']['retries']),
  530.                     'retry'
  531.                 );
  532.             } else {
  533.                 $list->appendSign(
  534.                     RetryMiddlewareV2::wrap(
  535.                         $config,
  536.                         ['collect_stats' => $args['stats']['retries']]
  537.                     ),
  538.                     'retry'
  539.                 );
  540.             }
  541.         }
  542.     }
  543.     public static function _apply_defaults($value, array &$argsHandlerList $list)
  544.     {
  545.         $config ConfigModeProvider::unwrap($value);
  546.         if ($config->getMode() !== 'legacy') {
  547.             if (!isset($args['retries']) && !is_null($config->getRetryMode())) {
  548.                 $args['retries'] = ['mode' => $config->getRetryMode()];
  549.             }
  550.             if (
  551.                 !isset($args['sts_regional_endpoints'])
  552.                 && !is_null($config->getStsRegionalEndpoints())
  553.             ) {
  554.                 $args['sts_regional_endpoints'] = ['mode' => $config->getStsRegionalEndpoints()];
  555.             }
  556.             if (
  557.                 !isset($args['s3_us_east_1_regional_endpoint'])
  558.                 && !is_null($config->getS3UsEast1RegionalEndpoints())
  559.             ) {
  560.                 $args['s3_us_east_1_regional_endpoint'] = ['mode' => $config->getS3UsEast1RegionalEndpoints()];
  561.             }
  562.             if (!isset($args['http'])) {
  563.                 $args['http'] = [];
  564.             }
  565.             if (
  566.                 !isset($args['http']['connect_timeout'])
  567.                 && !is_null($config->getConnectTimeoutInMillis())
  568.             ) {
  569.                 $args['http']['connect_timeout'] = $config->getConnectTimeoutInMillis() / 1000;
  570.             }
  571.             if (
  572.                 !isset($args['http']['timeout'])
  573.                 && !is_null($config->getHttpRequestTimeoutInMillis())
  574.             ) {
  575.                 $args['http']['timeout'] = $config->getHttpRequestTimeoutInMillis() / 1000;
  576.             }
  577.         }
  578.     }
  579.     public static function _apply_disable_request_compression($value, array &$args) {
  580.         if (is_callable($value)) {
  581.             $value $value();
  582.         }
  583.         if (!is_bool($value)) {
  584.             throw new IAE(
  585.                 "Invalid configuration value provided for 'disable_request_compression'."
  586.                 " value must be a bool."
  587.             );
  588.         }
  589.         $args['config']['disable_request_compression'] = $value;
  590.     }
  591.     public static function _apply_min_compression_size($value, array &$args) {
  592.         if (is_callable($value)) {
  593.             $value $value();
  594.         }
  595.         if (!is_int($value)
  596.             || (is_int($value)
  597.                 && ($value || $value 10485760))
  598.         ) {
  599.             throw new IAE(" Invalid configuration value provided for 'min_compression_size_bytes'."
  600.                 " value must be an integer between 0 and 10485760, inclusive.");
  601.         }
  602.         $args['config']['request_min_compression_size_bytes'] = $value;
  603.     }
  604.     public static function _default_min_compression_size(array &$args) {
  605.         return ConfigurationResolver::resolve(
  606.             'request_min_compression_size_bytes',
  607.             10240,
  608.             'int',
  609.             $args
  610.         );
  611.     }
  612.     public static function _apply_credentials($value, array &$args)
  613.     {
  614.         if (is_callable($value)) {
  615.             return;
  616.         }
  617.         if ($value instanceof CredentialsInterface) {
  618.             $args['credentials'] = CredentialProvider::fromCredentials($value);
  619.         } elseif (is_array($value)
  620.             && isset($value['key'])
  621.             && isset($value['secret'])
  622.         ) {
  623.             $args['credentials'] = CredentialProvider::fromCredentials(
  624.                 new Credentials(
  625.                     $value['key'],
  626.                     $value['secret'],
  627.                     $value['token'] ?? null,
  628.                     $value['expires'] ?? null,
  629.                     $value['accountId'] ?? null
  630.                 )
  631.             );
  632.         } elseif ($value === false) {
  633.             $args['credentials'] = CredentialProvider::fromCredentials(
  634.                 new Credentials('''')
  635.             );
  636.             $args['config']['signature_version'] = 'anonymous';
  637.             $args['config']['configured_signature_version'] = true;
  638.         } elseif ($value instanceof CacheInterface) {
  639.             $args['credentials'] = CredentialProvider::defaultProvider($args);
  640.         } else {
  641.             throw new IAE('Credentials must be an instance of '
  642.                 "'" CredentialsInterface::class . ', an associative '
  643.                 'array that contains "key", "secret", and an optional "token" '
  644.                 'key-value pairs, a credentials provider function, or false.');
  645.         }
  646.     }
  647.     public static function _default_credential_provider(array $args)
  648.     {
  649.         return CredentialProvider::defaultProvider($args);
  650.     }
  651.     public static function _apply_token($value, array &$args)
  652.     {
  653.         if (is_callable($value)) {
  654.             return;
  655.         }
  656.         if ($value instanceof Token) {
  657.             $args['token'] = TokenProvider::fromToken($value);
  658.         } elseif (is_array($value)
  659.             && isset($value['token'])
  660.         ) {
  661.             $args['token'] = TokenProvider::fromToken(
  662.                 new Token(
  663.                     $value['token'],
  664.                     $value['expires'] ?? null
  665.                 )
  666.             );
  667.         } elseif ($value instanceof CacheInterface) {
  668.             $args['token'] = TokenProvider::defaultProvider($args);
  669.         } else {
  670.             throw new IAE('Token must be an instance of '
  671.                 TokenInterface::class . ', an associative '
  672.                 'array that contains "token" and an optional "expires" '
  673.                 'key-value pairs, a token provider function, or false.');
  674.         }
  675.     }
  676.     public static function _default_token_provider(array $args)
  677.     {
  678.         return TokenProvider::defaultProvider($args);
  679.     }
  680.     public static function _apply_csm($value, array &$argsHandlerList $list)
  681.     {
  682.         if ($value === false) {
  683.             $value = new Configuration(
  684.                 false,
  685.                 \Aws\ClientSideMonitoring\ConfigurationProvider::DEFAULT_HOST,
  686.                 \Aws\ClientSideMonitoring\ConfigurationProvider::DEFAULT_PORT,
  687.                 \Aws\ClientSideMonitoring\ConfigurationProvider::DEFAULT_CLIENT_ID
  688.             );
  689.             $args['csm'] = $value;
  690.         }
  691.         $list->appendBuild(
  692.             ApiCallMonitoringMiddleware::wrap(
  693.                 $args['credentials'],
  694.                 $value,
  695.                 $args['region'],
  696.                 $args['api']->getServiceId()
  697.             ),
  698.             'ApiCallMonitoringMiddleware'
  699.         );
  700.         $list->appendAttempt(
  701.             ApiCallAttemptMonitoringMiddleware::wrap(
  702.                 $args['credentials'],
  703.                 $value,
  704.                 $args['region'],
  705.                 $args['api']->getServiceId()
  706.             ),
  707.             'ApiCallAttemptMonitoringMiddleware'
  708.         );
  709.     }
  710.     public static function _apply_api_provider(callable $value, array &$args)
  711.     {
  712.         $api = new Service(
  713.             ApiProvider::resolve(
  714.                 $value,
  715.                 'api',
  716.                 $args['service'],
  717.                 $args['version']
  718.             ),
  719.             $value
  720.         );
  721.         if (
  722.             empty($args['config']['signing_name'])
  723.             && isset($api['metadata']['signingName'])
  724.         ) {
  725.             $args['config']['signing_name'] = $api['metadata']['signingName'];
  726.         }
  727.         $args['api'] = $api;
  728.         $args['parser'] = Service::createParser($api);
  729.         $args['error_parser'] = Service::createErrorParser($api->getProtocol(), $api);
  730.     }
  731.     public static function _apply_endpoint_provider($value, array &$args)
  732.     {
  733.         if (!isset($args['endpoint'])) {
  734.             if ($value instanceof \Aws\EndpointV2\EndpointProviderV2) {
  735.                 $options self::getEndpointProviderOptions($args);
  736.                 $value PartitionEndpointProvider::defaultProvider($options)
  737.                     ->getPartition($args['region'], $args['service']);
  738.             }
  739.             $endpointPrefix $args['api']['metadata']['endpointPrefix'] ?? $args['service'];
  740.             // Check region is a valid host label when it is being used to
  741.             // generate an endpoint
  742.             if (!self::isValidRegion($args['region'])) {
  743.                 throw new InvalidRegionException('Region must be a valid RFC'
  744.                     ' host label.');
  745.             }
  746.             $serviceEndpoints =
  747.                 is_array($value) && isset($value['services'][$args['service']]['endpoints'])
  748.                     ? $value['services'][$args['service']]['endpoints']
  749.                     : null;
  750.             if (isset($serviceEndpoints[$args['region']]['deprecated'])) {
  751.                 trigger_error("The service " $args['service'] . "has "
  752.                     " deprecated the region " $args['region'] . ".",
  753.                     E_USER_WARNING
  754.                 );
  755.             }
  756.             $args['region'] = \Aws\strip_fips_pseudo_regions($args['region']);
  757.             // Invoke the endpoint provider and throw if it does not resolve.
  758.             $result EndpointProvider::resolve($value, [
  759.                 'service' => $endpointPrefix,
  760.                 'region'  => $args['region'],
  761.                 'scheme'  => $args['scheme'],
  762.                 'options' => self::getEndpointProviderOptions($args),
  763.             ]);
  764.             $args['endpoint'] = $result['endpoint'];
  765.             if (empty($args['config']['signature_version'])) {
  766.                 if (
  767.                     isset($args['api'])
  768.                     && $args['api']->getSignatureVersion() == 'bearer'
  769.                 ) {
  770.                     $args['config']['signature_version'] = 'bearer';
  771.                 } elseif (isset($result['signatureVersion'])) {
  772.                     $args['config']['signature_version'] = $result['signatureVersion'];
  773.                 }
  774.             }
  775.             if (
  776.                 empty($args['config']['signing_region'])
  777.                 && isset($result['signingRegion'])
  778.             ) {
  779.                 $args['config']['signing_region'] = $result['signingRegion'];
  780.             }
  781.             if (
  782.                 empty($args['config']['signing_name'])
  783.                 && isset($result['signingName'])
  784.             ) {
  785.                 $args['config']['signing_name'] = $result['signingName'];
  786.             }
  787.         }
  788.     }
  789.     public static function _apply_endpoint_discovery($value, array &$args) {
  790.         $args['endpoint_discovery'] = $value;
  791.     }
  792.     public static function _default_endpoint_discovery_provider(array $args)
  793.     {
  794.         return ConfigurationProvider::defaultProvider($args);
  795.     }
  796.     public static function _apply_use_fips_endpoint($value, array &$args) {
  797.         if ($value instanceof CacheInterface) {
  798.             $value UseFipsConfigProvider::defaultProvider($args);
  799.         }
  800.         if (is_callable($value)) {
  801.             $value $value();
  802.         }
  803.         if ($value instanceof PromiseInterface) {
  804.             $value $value->wait();
  805.         }
  806.         if ($value instanceof UseFipsEndpointConfigurationInterface) {
  807.             $args['config']['use_fips_endpoint'] = $value;
  808.         } else {
  809.             // The Configuration class itself will validate other inputs
  810.             $args['config']['use_fips_endpoint'] = new UseFipsEndpointConfiguration($value);
  811.         }
  812.     }
  813.     public static function _default_use_fips_endpoint(array &$args) {
  814.         return UseFipsConfigProvider::defaultProvider($args);
  815.     }
  816.     public static function _apply_use_dual_stack_endpoint($value, array &$args) {
  817.         if ($value instanceof CacheInterface) {
  818.             $value UseDualStackConfigProvider::defaultProvider($args);
  819.         }
  820.         if (is_callable($value)) {
  821.             $value $value();
  822.         }
  823.         if ($value instanceof PromiseInterface) {
  824.             $value $value->wait();
  825.         }
  826.         if ($value instanceof UseDualStackEndpointConfigurationInterface) {
  827.             $args['config']['use_dual_stack_endpoint'] = $value;
  828.         } else {
  829.             // The Configuration class itself will validate other inputs
  830.             $args['config']['use_dual_stack_endpoint'] =
  831.                 new UseDualStackEndpointConfiguration($value$args['region']);
  832.         }
  833.     }
  834.     public static function _default_use_dual_stack_endpoint(array &$args) {
  835.         return UseDualStackConfigProvider::defaultProvider($args);
  836.     }
  837.     public static function _apply_serializer($value, array &$argsHandlerList $list)
  838.     {
  839.         $list->prependBuild(Middleware::requestBuilder($value), 'builder');
  840.     }
  841.     public static function _apply_debug($value, array &$argsHandlerList $list)
  842.     {
  843.         if ($value !== false) {
  844.             $list->interpose(
  845.                 new TraceMiddleware(
  846.                     $value === true ? [] : $value,
  847.                     $args['api'])
  848.             );
  849.         }
  850.     }
  851.     public static function _apply_stats($value, array &$argsHandlerList $list)
  852.     {
  853.         // Create an array of stat collectors that are disabled (set to false)
  854.         // by default. If the user has passed in true, enable all stat
  855.         // collectors.
  856.         $defaults array_fill_keys(
  857.             ['http''retries''timer'],
  858.             $value === true
  859.         );
  860.         $args['stats'] = is_array($value)
  861.             ? array_replace($defaults$value)
  862.             : $defaults;
  863.         if ($args['stats']['timer']) {
  864.             $list->prependInit(Middleware::timer(), 'timer');
  865.         }
  866.     }
  867.     public static function _apply_profile($_, array &$args)
  868.     {
  869.         $args['credentials'] = CredentialProvider::ini($args['profile']);
  870.     }
  871.     public static function _apply_validate($value, array &$argsHandlerList $list)
  872.     {
  873.         if ($value === false) {
  874.             return;
  875.         }
  876.         $validator $value === true
  877.             ? new Validator()
  878.             : new Validator($value);
  879.         $list->appendValidate(
  880.             Middleware::validation($args['api'], $validator),
  881.             'validation'
  882.         );
  883.     }
  884.     public static function _apply_handler($value, array &$argsHandlerList $list)
  885.     {
  886.         $list->setHandler($value);
  887.     }
  888.     public static function _default_handler(array &$args)
  889.     {
  890.         return new WrappedHttpHandler(
  891.             default_http_handler(),
  892.             $args['parser'],
  893.             $args['error_parser'],
  894.             $args['exception_class'],
  895.             $args['stats']['http']
  896.         );
  897.     }
  898.     public static function _apply_http_handler($value, array &$argsHandlerList $list)
  899.     {
  900.         $args['handler'] = new WrappedHttpHandler(
  901.             $value,
  902.             $args['parser'],
  903.             $args['error_parser'],
  904.             $args['exception_class'],
  905.             $args['stats']['http']
  906.         );
  907.     }
  908.     public static function _apply_app_id($value, array &$args)
  909.     {
  910.         // AppId should not be longer than 50 chars
  911.         static $MAX_APP_ID_LENGTH 50;
  912.         if (strlen($value) > $MAX_APP_ID_LENGTH) {
  913.             trigger_error("The provided or configured value for `AppId`, "
  914.                 ."which is an user agent parameter, exceeds the maximum length of "
  915.             ."$MAX_APP_ID_LENGTH characters."E_USER_WARNING);
  916.         }
  917.         $args['app_id'] = $value;
  918.     }
  919.     public static function _default_app_id(array $args)
  920.     {
  921.         return ConfigurationResolver::resolve(
  922.             'sdk_ua_app_id',
  923.             '',
  924.             'string',
  925.             $args
  926.         );
  927.     }
  928.     public static function _apply_user_agent(
  929.         $inputUserAgent,
  930.         array &$args,
  931.         HandlerList $list
  932.     ): void
  933.     {
  934.         // Add endpoint discovery if set
  935.         $userAgent = [];
  936.         // Add the input to the end
  937.         if ($inputUserAgent){
  938.             if (!is_array($inputUserAgent)) {
  939.                 $inputUserAgent = [$inputUserAgent];
  940.             }
  941.             $inputUserAgent array_map('strval'$inputUserAgent);
  942.             $userAgent array_merge($userAgent$inputUserAgent);
  943.         }
  944.         $args['ua_append'] = $userAgent;
  945.         $list->appendBuild(
  946.             Middleware::mapRequest(function (RequestInterface $request) use ($userAgent) {
  947.                 return $request->withHeader(
  948.                     'X-Amz-User-Agent',
  949.                     implode(' 'array_merge(
  950.                         $userAgent,
  951.                         $request->getHeader('X-Amz-User-Agent')
  952.                     ))
  953.                 );
  954.             })
  955.         );
  956.     }
  957.     public static function _apply_endpoint($value, array &$argsHandlerList $list)
  958.     {
  959.         if (empty($value)) {
  960.             unset($args['endpoint']);
  961.             return;
  962.         }
  963.         $args['endpoint_override'] = true;
  964.         $args['endpoint'] = $value;
  965.     }
  966.     public static function _apply_idempotency_auto_fill(
  967.         $value,
  968.         array &$args,
  969.         HandlerList $list
  970.     ) {
  971.         $enabled false;
  972.         $generator null;
  973.         if (is_bool($value)) {
  974.             $enabled $value;
  975.         } elseif (is_callable($value)) {
  976.             $enabled true;
  977.             $generator $value;
  978.         }
  979.         if ($enabled) {
  980.             $list->prependInit(
  981.                 IdempotencyTokenMiddleware::wrap($args['api'], $generator),
  982.                 'idempotency_auto_fill'
  983.             );
  984.         }
  985.     }
  986.     public static function _default_account_id_endpoint_mode($args)
  987.     {
  988.         return ConfigurationResolver::resolve(
  989.             'account_id_endpoint_mode',
  990.             'preferred',
  991.             'string',
  992.             $args
  993.         );
  994.     }
  995.     public static function _apply_account_id_endpoint_mode($value, array &$args)
  996.     {
  997.         static $accountIdEndpointModes = ['disabled''required''preferred'];
  998.         if (!in_array($value$accountIdEndpointModes)) {
  999.             throw new IAE(
  1000.                 "The value provided for the config account_id_endpoint_mode is invalid."
  1001.                 ."Valid values are: " implode(", "$accountIdEndpointModes)
  1002.             );
  1003.         }
  1004.         $args['account_id_endpoint_mode'] = $value;
  1005.     }
  1006.     public static function _default_endpoint_provider(array $args)
  1007.     {
  1008.         $service $args['api'] ?? null;
  1009.         $serviceName = isset($service) ? $service->getServiceName() : null;
  1010.         $apiVersion = isset($service) ? $service->getApiVersion() : null;
  1011.         if (self::isValidService($serviceName)
  1012.             && self::isValidApiVersion($serviceName$apiVersion)
  1013.         ) {
  1014.             $ruleset EndpointDefinitionProvider::getEndpointRuleset(
  1015.                 $service->getServiceName(),
  1016.                 $service->getApiVersion()
  1017.             );
  1018.             return new \Aws\EndpointV2\EndpointProviderV2(
  1019.                 $ruleset,
  1020.                 EndpointDefinitionProvider::getPartitions()
  1021.             );
  1022.         }
  1023.         $options self::getEndpointProviderOptions($args);
  1024.         return PartitionEndpointProvider::defaultProvider($options)
  1025.             ->getPartition($args['region'], $args['service']);
  1026.     }
  1027.     public static function _default_serializer(array $args)
  1028.     {
  1029.         return Service::createSerializer(
  1030.             $args['api'],
  1031.             $args['endpoint']
  1032.         );
  1033.     }
  1034.     public static function _default_signature_provider()
  1035.     {
  1036.         return SignatureProvider::defaultProvider();
  1037.     }
  1038.     public static function _default_auth_scheme_resolver(array $args)
  1039.     {
  1040.         return new AuthSchemeResolver($args['credentials'], $args['token']);
  1041.     }
  1042.     public static function _default_signature_version(array &$args)
  1043.     {
  1044.         if (isset($args['config']['signature_version'])) {
  1045.             return $args['config']['signature_version'];
  1046.         }
  1047.         $args['__partition_result'] = isset($args['__partition_result'])
  1048.             ? isset($args['__partition_result'])
  1049.             : call_user_func(PartitionEndpointProvider::defaultProvider(), [
  1050.                 'service' => $args['service'],
  1051.                 'region' => $args['region'],
  1052.             ]);
  1053.         return isset($args['__partition_result']['signatureVersion'])
  1054.             ? $args['__partition_result']['signatureVersion']
  1055.             : $args['api']->getSignatureVersion();
  1056.     }
  1057.     public static function _default_signing_name(array &$args)
  1058.     {
  1059.         if (isset($args['config']['signing_name'])) {
  1060.             return $args['config']['signing_name'];
  1061.         }
  1062.         $args['__partition_result'] = isset($args['__partition_result'])
  1063.             ? isset($args['__partition_result'])
  1064.             : call_user_func(PartitionEndpointProvider::defaultProvider(), [
  1065.                 'service' => $args['service'],
  1066.                 'region' => $args['region'],
  1067.             ]);
  1068.         if (isset($args['__partition_result']['signingName'])) {
  1069.             return $args['__partition_result']['signingName'];
  1070.         }
  1071.         if ($signingName $args['api']->getSigningName()) {
  1072.             return $signingName;
  1073.         }
  1074.         return $args['service'];
  1075.     }
  1076.     public static function _default_signing_region(array &$args)
  1077.     {
  1078.         if (isset($args['config']['signing_region'])) {
  1079.             return $args['config']['signing_region'];
  1080.         }
  1081.         $args['__partition_result'] = isset($args['__partition_result'])
  1082.             ? isset($args['__partition_result'])
  1083.             : call_user_func(PartitionEndpointProvider::defaultProvider(), [
  1084.                 'service' => $args['service'],
  1085.                 'region' => $args['region'],
  1086.             ]);
  1087.         return $args['__partition_result']['signingRegion'] ?? $args['region'];
  1088.     }
  1089.     public static function _apply_ignore_configured_endpoint_urls($value, array &$args)
  1090.     {
  1091.         $args['config']['ignore_configured_endpoint_urls'] = $value;
  1092.     }
  1093.     public static function _apply_suppress_php_deprecation_warning($value, &$args)
  1094.     {
  1095.         if ($value)  {
  1096.             $args['suppress_php_deprecation_warning'] = true;
  1097.         } elseif (!empty(getenv("AWS_SUPPRESS_PHP_DEPRECATION_WARNING"))) {
  1098.             $args['suppress_php_deprecation_warning']
  1099.                 = \Aws\boolean_value(getenv("AWS_SUPPRESS_PHP_DEPRECATION_WARNING"));
  1100.         } elseif (!empty($_SERVER["AWS_SUPPRESS_PHP_DEPRECATION_WARNING"])) {
  1101.             $args['suppress_php_deprecation_warning'] =
  1102.                 \Aws\boolean_value($_SERVER["AWS_SUPPRESS_PHP_DEPRECATION_WARNING"]);
  1103.         } elseif (!empty($_ENV["AWS_SUPPRESS_PHP_DEPRECATION_WARNING"])) {
  1104.             $args['suppress_php_deprecation_warning'] =
  1105.                 \Aws\boolean_value($_ENV["AWS_SUPPRESS_PHP_DEPRECATION_WARNING"]);
  1106.         }
  1107.         if ($args['suppress_php_deprecation_warning'] === false
  1108.             && PHP_VERSION_ID 80100
  1109.         ) {
  1110.             self::emitDeprecationWarning();
  1111.         }
  1112.     }
  1113.     public static function _default_endpoint(array &$args)
  1114.     {
  1115.         if ($args['config']['ignore_configured_endpoint_urls']
  1116.             || !self::isValidService($args['service'])
  1117.         ) {
  1118.             return '';
  1119.         }
  1120.         $serviceIdentifier \Aws\manifest($args['service'])['serviceIdentifier'];
  1121.         $value =  ConfigurationResolver::resolve(
  1122.             'endpoint_url_' $serviceIdentifier,
  1123.             '',
  1124.             'string',
  1125.             $args + [
  1126.                 'ini_resolver_options' => [
  1127.                     'section' => 'services',
  1128.                     'subsection' => $serviceIdentifier,
  1129.                     'key' => 'endpoint_url'
  1130.                 ]
  1131.             ]
  1132.         );
  1133.         if (empty($value)) {
  1134.             $value ConfigurationResolver::resolve(
  1135.                 'endpoint_url',
  1136.                 '',
  1137.                 'string',
  1138.                 $args
  1139.             );
  1140.         }
  1141.         if (!empty($value)) {
  1142.             $args['config']['configured_endpoint_url'] = true;
  1143.         }
  1144.         return $value;
  1145.     }
  1146.     public static function _apply_sigv4a_signing_region_set($value, array &$args)
  1147.     {
  1148.         if (empty($value)) {
  1149.             $args['sigv4a_signing_region_set'] = null;
  1150.         } elseif (is_array($value)) {
  1151.             $args['sigv4a_signing_region_set'] = implode(', '$value);
  1152.         } else {
  1153.             $args['sigv4a_signing_region_set'] = $value;
  1154.         }
  1155.     }
  1156.     public static function _apply_region($value, array &$args)
  1157.     {
  1158.         if (empty($value)) {
  1159.             self::_missing_region($args);
  1160.         }
  1161.         $args['region'] = $value;
  1162.     }
  1163.     public static function _missing_region(array $args)
  1164.     {
  1165.         $service $args['service'] ?? '';
  1166.         $msg = <<<EOT
  1167. Missing required client configuration options:
  1168. region: (string)
  1169. A "region" configuration value is required for the "{$service}" service
  1170. (e.g., "us-west-2"). A list of available public regions and endpoints can be
  1171. found at http://docs.aws.amazon.com/general/latest/gr/rande.html.
  1172. EOT;
  1173.         throw new IAE($msg);
  1174.     }
  1175.     /**
  1176.      * Resolves a value from env or config.
  1177.      *
  1178.      * @param $key
  1179.      * @param $expectedType
  1180.      * @param $args
  1181.      *
  1182.      * @return mixed|string
  1183.      */
  1184.     private static function _resolve_from_env_ini(
  1185.         string $key,
  1186.         string $expectedType,
  1187.         array $args
  1188.     ) {
  1189.         static $typeDefaultMap = [
  1190.             'int' => 0,
  1191.             'bool' => false,
  1192.             'boolean' => false,
  1193.             'string' => '',
  1194.         ];
  1195.         return ConfigurationResolver::resolve(
  1196.             $key,
  1197.             $typeDefaultMap[$expectedType] ?? '',
  1198.             $expectedType,
  1199.             $args
  1200.         );
  1201.     }
  1202.     /**
  1203.      * Extracts client options for the endpoint provider to its own array
  1204.      *
  1205.      * @param array $args
  1206.      * @return array
  1207.      */
  1208.     private static function getEndpointProviderOptions(array $args)
  1209.     {
  1210.         $options = [];
  1211.         $optionKeys = [
  1212.             'sts_regional_endpoints',
  1213.             's3_us_east_1_regional_endpoint',
  1214.         ];
  1215.         $configKeys = [
  1216.             'use_dual_stack_endpoint',
  1217.             'use_fips_endpoint',
  1218.         ];
  1219.         foreach ($optionKeys as $key) {
  1220.             if (isset($args[$key])) {
  1221.                 $options[$key] = $args[$key];
  1222.             }
  1223.         }
  1224.         foreach ($configKeys as $key) {
  1225.             if (isset($args['config'][$key])) {
  1226.                 $options[$key] = $args['config'][$key];
  1227.             }
  1228.         }
  1229.         return $options;
  1230.     }
  1231.     /**
  1232.      * Validates a region to be used for endpoint construction
  1233.      *
  1234.      * @param $region
  1235.      * @return bool
  1236.      */
  1237.     private static function isValidRegion($region)
  1238.     {
  1239.         return is_valid_hostlabel($region);
  1240.     }
  1241.     private function _apply_client_context_params(array $args)
  1242.     {
  1243.         if (isset($args['api'])
  1244.             && !empty($args['api']->getClientContextParams()))
  1245.         {
  1246.             $clientContextParams $args['api']->getClientContextParams();
  1247.             foreach($clientContextParams as $paramName => $paramDefinition) {
  1248.                 $definition = [
  1249.                     'type' => 'value',
  1250.                     'valid' => [$paramDefinition['type']],
  1251.                     'doc' => $paramDefinition['documentation'] ?? null
  1252.                 ];
  1253.                 $this->argDefinitions[$paramName] = $definition;
  1254.                 if (isset($args[$paramName])) {
  1255.                     $fn self::$typeMap[$paramDefinition['type']];
  1256.                     if (!$fn($args[$paramName])) {
  1257.                         $this->invalidType($paramName$args[$paramName]);
  1258.                     }
  1259.                 }
  1260.             }
  1261.         }
  1262.     }
  1263.     private static function isValidService($service)
  1264.     {
  1265.         if (is_null($service)) {
  1266.             return false;
  1267.         }
  1268.         $services \Aws\manifest();
  1269.         return isset($services[$service]);
  1270.     }
  1271.     private static function isValidApiVersion($service$apiVersion)
  1272.     {
  1273.         if (is_null($apiVersion)) {
  1274.             return false;
  1275.         }
  1276.         return is_dir(
  1277.             __DIR__ "/data/{$service}/$apiVersion"
  1278.         );
  1279.     }
  1280.     private static function emitDeprecationWarning()
  1281.     {
  1282.         $phpVersionString phpversion();
  1283.         trigger_error(
  1284.             "This installation of the SDK is using PHP version"
  1285.             .  {$phpVersionString}, which will be deprecated on January"
  1286.             .  " 13th, 2025.\nPlease upgrade your PHP version to a minimum of"
  1287.             .  " 8.1.x to continue receiving updates for the AWS"
  1288.             .  " SDK for PHP.\nTo disable this warning, set"
  1289.             .  " suppress_php_deprecation_warning to true on the client constructor"
  1290.             .  " or set the environment variable AWS_SUPPRESS_PHP_DEPRECATION_WARNING"
  1291.             .  " to true.\nMore information can be found at: "
  1292.             .   "https://aws.amazon.com/blogs/developer/announcing-the-end-of-support-for-php-runtimes-8-0-x-and-below-in-the-aws-sdk-for-php/\n",
  1293.             E_USER_DEPRECATED
  1294.         );
  1295.     }
  1296. }