vendor/stripe/stripe-php/lib/Util/RequestOptions.php line 10

Open in your IDE?
  1. <?php
  2. namespace Stripe\Util;
  3. /**
  4. * @phpstan-type RequestOptionsArray array{api_key?: string, idempotency_key?: string, stripe_account?: string, stripe_context?: string|\Stripe\StripeContext, stripe_version?: string, api_base?: string, max_network_retries?: int }
  5. *
  6. * @psalm-type RequestOptionsArray = array{api_key?: string, idempotency_key?: string, stripe_account?: string, stripe_context?: string|\Stripe\StripeContext, stripe_version?: string, api_base?: string, max_network_retries?: int }
  7. */
  8. class RequestOptions
  9. {
  10. /**
  11. * @var array<string> a list of headers that should be persisted across requests
  12. */
  13. public static $HEADERS_TO_PERSIST = [
  14. 'Stripe-Account',
  15. 'Stripe-Context',
  16. 'Stripe-Version',
  17. ];
  18. /** @var array<string, string> */
  19. public $headers;
  20. /** @var null|string */
  21. public $apiKey;
  22. /** @var null|string */
  23. public $apiBase;
  24. /** @var null|int */
  25. public $maxNetworkRetries;
  26. /**
  27. * @param null|string $key
  28. * @param array<string, string> $headers
  29. * @param null|string $base
  30. * @param null|int $maxNetworkRetries
  31. */
  32. public function __construct($key = null, $headers = [], $base = null, $maxNetworkRetries = null)
  33. {
  34. $this->apiKey = $key;
  35. $this->headers = $headers;
  36. $this->apiBase = $base;
  37. $this->maxNetworkRetries = $maxNetworkRetries;
  38. }
  39. /**
  40. * @return array<string, string>
  41. */
  42. public function __debugInfo()
  43. {
  44. return [
  45. 'apiKey' => $this->redactedApiKey(),
  46. 'headers' => $this->headers,
  47. 'apiBase' => $this->apiBase,
  48. 'maxNetworkRetries' => $this->maxNetworkRetries,
  49. ];
  50. }
  51. /**
  52. * Unpacks an options array and merges it into the existing RequestOptions
  53. * object.
  54. *
  55. * @param null|array|RequestOptions|string $options a key => value array
  56. * @param bool $strict when true, forbid string form and arbitrary keys in array form
  57. *
  58. * @return RequestOptions
  59. */
  60. public function merge($options, $strict = false)
  61. {
  62. $other_options = self::parse($options, $strict);
  63. if (null === $other_options->apiKey) {
  64. $other_options->apiKey = $this->apiKey;
  65. }
  66. if (null === $other_options->apiBase) {
  67. $other_options->apiBase = $this->apiBase;
  68. }
  69. if (null === $other_options->maxNetworkRetries) {
  70. $other_options->maxNetworkRetries = $this->maxNetworkRetries;
  71. }
  72. $other_options->headers = \array_merge($this->headers, $other_options->headers);
  73. // special handling for stripe_context
  74. // if other sent an empty string, then we should unset
  75. if (\array_key_exists('Stripe-Context', $other_options->headers) && '' === $other_options->headers['Stripe-Context']) {
  76. unset($other_options->headers['Stripe-Context']);
  77. }
  78. return $other_options;
  79. }
  80. /**
  81. * Discards all headers that we don't want to persist across requests.
  82. */
  83. public function discardNonPersistentHeaders()
  84. {
  85. foreach ($this->headers as $k => $v) {
  86. if (!\in_array($k, self::$HEADERS_TO_PERSIST, true)) {
  87. unset($this->headers[$k]);
  88. }
  89. }
  90. }
  91. /**
  92. * Unpacks an options array into an RequestOptions object.
  93. *
  94. * @param null|array|RequestOptions|string $options a key => value array
  95. * @param bool $strict when true, forbid string form and arbitrary keys in array form
  96. *
  97. * @return RequestOptions
  98. *
  99. * @throws \Stripe\Exception\InvalidArgumentException
  100. */
  101. public static function parse($options, $strict = false)
  102. {
  103. if ($options instanceof self) {
  104. return clone $options;
  105. }
  106. if (null === $options) {
  107. return new RequestOptions(null, [], null);
  108. }
  109. if (\is_string($options)) {
  110. if ($strict) {
  111. $message = 'Do not pass a string for request options. If you want to set the '
  112. . 'API key, pass an array like ["api_key" => <apiKey>] instead.';
  113. throw new \Stripe\Exception\InvalidArgumentException($message);
  114. }
  115. return new RequestOptions($options, [], null);
  116. }
  117. if (\is_array($options)) {
  118. $headers = [];
  119. $key = null;
  120. $base = null;
  121. $maxNetworkRetries = null;
  122. if (\array_key_exists('api_key', $options)) {
  123. $key = $options['api_key'];
  124. unset($options['api_key']);
  125. }
  126. if (\array_key_exists('idempotency_key', $options)) {
  127. $headers['Idempotency-Key'] = $options['idempotency_key'];
  128. unset($options['idempotency_key']);
  129. }
  130. if (\array_key_exists('stripe_account', $options)) {
  131. if (null !== $options['stripe_account']) {
  132. $headers['Stripe-Account'] = $options['stripe_account'];
  133. }
  134. unset($options['stripe_account']);
  135. }
  136. if (\array_key_exists('stripe_context', $options)) {
  137. if (null !== $options['stripe_context']) {
  138. $headers['Stripe-Context'] = (string) $options['stripe_context'];
  139. }
  140. unset($options['stripe_context']);
  141. }
  142. if (\array_key_exists('stripe_version', $options)) {
  143. if (null !== $options['stripe_version']) {
  144. $headers['Stripe-Version'] = $options['stripe_version'];
  145. }
  146. unset($options['stripe_version']);
  147. }
  148. if (\array_key_exists('max_network_retries', $options)) {
  149. if (null !== $options['max_network_retries']) {
  150. $maxNetworkRetries = $options['max_network_retries'];
  151. }
  152. unset($options['max_network_retries']);
  153. }
  154. if (\array_key_exists('api_base', $options)) {
  155. $base = $options['api_base'];
  156. unset($options['api_base']);
  157. }
  158. if ($strict && !empty($options)) {
  159. $message = 'Got unexpected keys in options array: ' . \implode(', ', \array_keys($options));
  160. throw new \Stripe\Exception\InvalidArgumentException($message);
  161. }
  162. return new RequestOptions($key, $headers, $base, $maxNetworkRetries);
  163. }
  164. $message = 'The second argument to Stripe API method calls is an '
  165. . 'optional per-request apiKey, which must be a string, or '
  166. . 'per-request options, which must be an array. (HINT: you can set '
  167. . 'a global apiKey by "Stripe::setApiKey(<apiKey>)")';
  168. throw new \Stripe\Exception\InvalidArgumentException($message);
  169. }
  170. /** @return string */
  171. private function redactedApiKey()
  172. {
  173. if (null === $this->apiKey) {
  174. return '';
  175. }
  176. $pieces = \explode('_', $this->apiKey, 3);
  177. $last = \array_pop($pieces);
  178. $redactedLast = \strlen($last) > 4
  179. ? (\str_repeat('*', \strlen($last) - 4) . \substr($last, -4))
  180. : $last;
  181. $pieces[] = $redactedLast;
  182. return \implode('_', $pieces);
  183. }
  184. }