| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- <?php
- declare(strict_types=1);
- namespace AsyncAws\Core;
- use AsyncAws\Core\Credentials\IniFileLoader;
- use AsyncAws\Core\Exception\InvalidArgument;
- /**
- * Helper object that holds all configuration to the API.
- *
- * @author Tobias Nyholm <tobias.nyholm@gmail.com>
- * @author Jérémy Derussé <jeremy@derusse.com>
- */
- final class Configuration
- {
- public const DEFAULT_REGION = 'us-east-1';
- public const OPTION_REGION = 'region';
- public const OPTION_DEBUG = 'debug';
- public const OPTION_PROFILE = 'profile';
- public const OPTION_ACCESS_KEY_ID = 'accessKeyId';
- public const OPTION_SECRET_ACCESS_KEY = 'accessKeySecret';
- public const OPTION_SESSION_TOKEN = 'sessionToken';
- public const OPTION_SHARED_CREDENTIALS_FILE = 'sharedCredentialsFile';
- public const OPTION_SHARED_CONFIG_FILE = 'sharedConfigFile';
- public const OPTION_ENDPOINT = 'endpoint';
- public const OPTION_ROLE_ARN = 'roleArn';
- public const OPTION_WEB_IDENTITY_TOKEN_FILE = 'webIdentityTokenFile';
- public const OPTION_ROLE_SESSION_NAME = 'roleSessionName';
- public const OPTION_CONTAINER_CREDENTIALS_RELATIVE_URI = 'containerCredentialsRelativeUri';
- public const OPTION_ENDPOINT_DISCOVERY_ENABLED = 'endpointDiscoveryEnabled';
- // S3 specific option
- public const OPTION_PATH_STYLE_ENDPOINT = 'pathStyleEndpoint';
- public const OPTION_SEND_CHUNKED_BODY = 'sendChunkedBody';
- private const AVAILABLE_OPTIONS = [
- self::OPTION_REGION => true,
- self::OPTION_DEBUG => true,
- self::OPTION_PROFILE => true,
- self::OPTION_ACCESS_KEY_ID => true,
- self::OPTION_SECRET_ACCESS_KEY => true,
- self::OPTION_SESSION_TOKEN => true,
- self::OPTION_SHARED_CREDENTIALS_FILE => true,
- self::OPTION_SHARED_CONFIG_FILE => true,
- self::OPTION_ENDPOINT => true,
- self::OPTION_ROLE_ARN => true,
- self::OPTION_WEB_IDENTITY_TOKEN_FILE => true,
- self::OPTION_ROLE_SESSION_NAME => true,
- self::OPTION_CONTAINER_CREDENTIALS_RELATIVE_URI => true,
- self::OPTION_ENDPOINT_DISCOVERY_ENABLED => true,
- self::OPTION_PATH_STYLE_ENDPOINT => true,
- self::OPTION_SEND_CHUNKED_BODY => true,
- ];
- // Put fallback options into groups to avoid mixing of provided config and environment variables
- private const FALLBACK_OPTIONS = [
- [self::OPTION_REGION => ['AWS_REGION', 'AWS_DEFAULT_REGION']],
- [self::OPTION_PROFILE => ['AWS_PROFILE', 'AWS_DEFAULT_PROFILE']],
- [
- self::OPTION_ACCESS_KEY_ID => ['AWS_ACCESS_KEY_ID', 'AWS_ACCESS_KEY'],
- self::OPTION_SECRET_ACCESS_KEY => ['AWS_SECRET_ACCESS_KEY', 'AWS_SECRET_KEY'],
- self::OPTION_SESSION_TOKEN => 'AWS_SESSION_TOKEN',
- ],
- [self::OPTION_SHARED_CREDENTIALS_FILE => 'AWS_SHARED_CREDENTIALS_FILE'],
- [self::OPTION_SHARED_CONFIG_FILE => 'AWS_CONFIG_FILE'],
- [
- self::OPTION_ROLE_ARN => 'AWS_ROLE_ARN',
- self::OPTION_WEB_IDENTITY_TOKEN_FILE => 'AWS_WEB_IDENTITY_TOKEN_FILE',
- self::OPTION_ROLE_SESSION_NAME => 'AWS_ROLE_SESSION_NAME',
- ],
- [self::OPTION_CONTAINER_CREDENTIALS_RELATIVE_URI => 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'],
- [self::OPTION_ENDPOINT_DISCOVERY_ENABLED => ['AWS_ENDPOINT_DISCOVERY_ENABLED', 'AWS_ENABLE_ENDPOINT_DISCOVERY']],
- ];
- private const DEFAULT_OPTIONS = [
- self::OPTION_REGION => self::DEFAULT_REGION,
- self::OPTION_DEBUG => 'false',
- self::OPTION_PROFILE => 'default',
- self::OPTION_SHARED_CREDENTIALS_FILE => '~/.aws/credentials',
- self::OPTION_SHARED_CONFIG_FILE => '~/.aws/config',
- // https://docs.aws.amazon.com/general/latest/gr/rande.html
- self::OPTION_ENDPOINT => 'https://%service%.%region%.amazonaws.com',
- self::OPTION_PATH_STYLE_ENDPOINT => 'false',
- self::OPTION_SEND_CHUNKED_BODY => 'false',
- self::OPTION_ENDPOINT_DISCOVERY_ENABLED => 'false',
- ];
- private $data = [];
- private $userData = [];
- public static function create(array $options)
- {
- if (0 < \count($invalidOptions = array_diff_key($options, self::AVAILABLE_OPTIONS))) {
- throw new InvalidArgument(sprintf('Invalid option(s) "%s" passed to "%s::%s". ', implode('", "', array_keys($invalidOptions)), __CLASS__, __METHOD__));
- }
- // Force each option to be string or null
- $options = array_map(static function ($value) {
- return null !== $value ? (string) $value : $value;
- }, $options);
- $configuration = new self();
- $options = self::parseEnvironmentVariables($options);
- self::populateConfiguration($configuration, $options);
- $iniOptions = self::parseIniFiles($configuration);
- self::populateConfiguration($configuration, $iniOptions);
- return $configuration;
- }
- public static function optionExists(string $optionName): bool
- {
- return isset(self::AVAILABLE_OPTIONS[$optionName]);
- }
- /**
- * @psalm-return (
- * $name is
- * self::OPTION_REGION
- * |self::OPTION_DEBUG
- * |self::OPTION_PROFILE
- * |self::OPTION_SHARED_CREDENTIALS_FILE
- * |self::OPTION_SHARED_CONFIG_FILE
- * |self::OPTION_ENDPOINT
- * |self::OPTION_PATH_STYLE_ENDPOINT
- * |self::OPTION_SEND_CHUNKED_BODY
- * ? string
- * : ?string
- * )
- */
- public function get(string $name): ?string
- {
- if (!isset(self::AVAILABLE_OPTIONS[$name])) {
- throw new InvalidArgument(sprintf('Invalid option "%s" passed to "%s::%s". ', $name, __CLASS__, __METHOD__));
- }
- return $this->data[$name] ?? null;
- }
- public function has(string $name): bool
- {
- if (!isset(self::AVAILABLE_OPTIONS[$name])) {
- throw new InvalidArgument(sprintf('Invalid option "%s" passed to "%s::%s". ', $name, __CLASS__, __METHOD__));
- }
- return isset($this->data[$name]);
- }
- public function isDefault(string $name): bool
- {
- if (!isset(self::AVAILABLE_OPTIONS[$name])) {
- throw new InvalidArgument(sprintf('Invalid option "%s" passed to "%s::%s". ', $name, __CLASS__, __METHOD__));
- }
- return empty($this->userData[$name]);
- }
- private static function parseEnvironmentVariables(array $options): array
- {
- foreach (self::FALLBACK_OPTIONS as $fallbackGroup) {
- // prevent mixing env variables with config keys
- foreach ($fallbackGroup as $option => $envVariableNames) {
- if (isset($options[$option])) {
- continue 2;
- }
- }
- foreach ($fallbackGroup as $option => $envVariableNames) {
- // Read environment files
- $envVariableNames = (array) $envVariableNames;
- foreach ($envVariableNames as $envVariableName) {
- if (null !== $envVariableValue = EnvVar::get($envVariableName)) {
- $options[$option] = $envVariableValue;
- break;
- }
- }
- }
- }
- return $options;
- }
- /**
- * Look for "region" in the configured ini files.
- */
- private static function parseIniFiles(Configuration $configuration): array
- {
- $options = [];
- if (!$configuration->isDefault(self::OPTION_REGION)) {
- return $options;
- }
- $profilesData = (new IniFileLoader())->loadProfiles([
- $configuration->get(self::OPTION_SHARED_CREDENTIALS_FILE),
- $configuration->get(self::OPTION_SHARED_CONFIG_FILE),
- ]);
- if (empty($profilesData)) {
- return $options;
- }
- /** @var string $profile */
- $profile = $configuration->get(Configuration::OPTION_PROFILE);
- if (isset($profilesData[$profile]['region'])) {
- $options[self::OPTION_REGION] = $profilesData[$profile]['region'];
- }
- return $options;
- }
- /**
- * Add array options to the configuration object.
- */
- private static function populateConfiguration(Configuration $configuration, array $options): void
- {
- foreach ($options as $key => $value) {
- if (null !== $value) {
- $configuration->userData[$key] = true;
- }
- }
- // If we have not applied default before
- if (empty($configuration->data)) {
- foreach (self::DEFAULT_OPTIONS as $optionTrigger => $defaultValue) {
- if (isset($options[$optionTrigger])) {
- continue;
- }
- $options[$optionTrigger] = $defaultValue;
- }
- }
- $configuration->data = array_merge($configuration->data, $options);
- }
- }
|