Actualización

This commit is contained in:
Xes
2025-04-10 12:24:57 +02:00
parent 8969cc929d
commit 45420b6f0d
39760 changed files with 4303286 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
<?php
// File generated from our OpenAPI spec
namespace Stripe\Util;
class ApiVersion
{
const CURRENT = '2024-09-30.acacia';
}

View File

@@ -0,0 +1,96 @@
<?php
namespace Stripe\Util;
/**
* CaseInsensitiveArray is an array-like class that ignores case for keys.
*
* It is used to store HTTP headers. Per RFC 2616, section 4.2:
* Each header field consists of a name followed by a colon (":") and the field value. Field names
* are case-insensitive.
*
* In the context of stripe-php, this is useful because the API will return headers with different
* case depending on whether HTTP/2 is used or not (with HTTP/2, headers are always in lowercase).
*/
class CaseInsensitiveArray implements \ArrayAccess, \Countable, \IteratorAggregate
{
private $container = [];
public function __construct($initial_array = [])
{
$this->container = \array_change_key_case($initial_array, \CASE_LOWER);
}
/**
* @return int
*/
#[\ReturnTypeWillChange]
public function count()
{
return \count($this->container);
}
/**
* @return \ArrayIterator
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return new \ArrayIterator($this->container);
}
/**
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
$offset = self::maybeLowercase($offset);
if (null === $offset) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
/**
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
$offset = self::maybeLowercase($offset);
return isset($this->container[$offset]);
}
/**
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
$offset = self::maybeLowercase($offset);
unset($this->container[$offset]);
}
/**
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
$offset = self::maybeLowercase($offset);
return isset($this->container[$offset]) ? $this->container[$offset] : null;
}
private static function maybeLowercase($v)
{
if (\is_string($v)) {
return \strtolower($v);
}
return $v;
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Stripe\Util;
/**
* A very basic implementation of LoggerInterface that has just enough
* functionality that it can be the default for this library.
*/
class DefaultLogger implements LoggerInterface
{
/** @var int */
public $messageType = 0;
/** @var null|string */
public $destination;
public function error($message, array $context = [])
{
if (\count($context) > 0) {
throw new \Stripe\Exception\BadMethodCallException('DefaultLogger does not currently implement context. Please implement if you need it.');
}
if (null === $this->destination) {
\error_log($message, $this->messageType);
} else {
\error_log($message, $this->messageType, $this->destination);
}
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Stripe\Util;
class EventTypes
{
const thinEventMapping = [
// The beginning of the section generated from our OpenAPI spec
\Stripe\Events\V1BillingMeterErrorReportTriggeredEvent::LOOKUP_TYPE => \Stripe\Events\V1BillingMeterErrorReportTriggeredEvent::class,
\Stripe\Events\V1BillingMeterNoMeterFoundEvent::LOOKUP_TYPE => \Stripe\Events\V1BillingMeterNoMeterFoundEvent::class,
// The end of the section generated from our OpenAPI spec
];
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Stripe\Util;
/**
* Describes a logger instance.
*
* This is a subset of the interface of the same name in the PSR-3 logger
* interface. We guarantee to keep it compatible, but we'd redefined it here so
* that we don't have to pull in the extra dependencies for users who don't want
* it.
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
* for the full interface specification.
*
* The message MUST be a string or object implementing __toString().
*
* The message MAY contain placeholders in the form: {foo} where foo
* will be replaced by the context data in key "foo".
*
* The context array can contain arbitrary data, the only assumption that
* can be made by implementors is that if an Exception instance is given
* to produce a stack trace, it MUST be in a key named "exception".
*/
interface LoggerInterface
{
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
*/
public function error($message, array $context = []);
}

View File

@@ -0,0 +1,169 @@
<?php
namespace Stripe\Util;
class ObjectTypes
{
/**
* @var array Mapping from object types to resource classes
*/
const mapping =
[
\Stripe\Collection::OBJECT_NAME => \Stripe\Collection::class,
\Stripe\Issuing\CardDetails::OBJECT_NAME => \Stripe\Issuing\CardDetails::class,
\Stripe\SearchResult::OBJECT_NAME => \Stripe\SearchResult::class,
\Stripe\File::OBJECT_NAME_ALT => \Stripe\File::class,
// object classes: The beginning of the section generated from our OpenAPI spec
\Stripe\Account::OBJECT_NAME => \Stripe\Account::class,
\Stripe\AccountLink::OBJECT_NAME => \Stripe\AccountLink::class,
\Stripe\AccountSession::OBJECT_NAME => \Stripe\AccountSession::class,
\Stripe\ApplePayDomain::OBJECT_NAME => \Stripe\ApplePayDomain::class,
\Stripe\Application::OBJECT_NAME => \Stripe\Application::class,
\Stripe\ApplicationFee::OBJECT_NAME => \Stripe\ApplicationFee::class,
\Stripe\ApplicationFeeRefund::OBJECT_NAME => \Stripe\ApplicationFeeRefund::class,
\Stripe\Apps\Secret::OBJECT_NAME => \Stripe\Apps\Secret::class,
\Stripe\Balance::OBJECT_NAME => \Stripe\Balance::class,
\Stripe\BalanceTransaction::OBJECT_NAME => \Stripe\BalanceTransaction::class,
\Stripe\BankAccount::OBJECT_NAME => \Stripe\BankAccount::class,
\Stripe\Billing\Alert::OBJECT_NAME => \Stripe\Billing\Alert::class,
\Stripe\Billing\AlertTriggered::OBJECT_NAME => \Stripe\Billing\AlertTriggered::class,
\Stripe\Billing\CreditBalanceSummary::OBJECT_NAME => \Stripe\Billing\CreditBalanceSummary::class,
\Stripe\Billing\CreditBalanceTransaction::OBJECT_NAME => \Stripe\Billing\CreditBalanceTransaction::class,
\Stripe\Billing\CreditGrant::OBJECT_NAME => \Stripe\Billing\CreditGrant::class,
\Stripe\Billing\Meter::OBJECT_NAME => \Stripe\Billing\Meter::class,
\Stripe\Billing\MeterEvent::OBJECT_NAME => \Stripe\Billing\MeterEvent::class,
\Stripe\Billing\MeterEventAdjustment::OBJECT_NAME => \Stripe\Billing\MeterEventAdjustment::class,
\Stripe\Billing\MeterEventSummary::OBJECT_NAME => \Stripe\Billing\MeterEventSummary::class,
\Stripe\BillingPortal\Configuration::OBJECT_NAME => \Stripe\BillingPortal\Configuration::class,
\Stripe\BillingPortal\Session::OBJECT_NAME => \Stripe\BillingPortal\Session::class,
\Stripe\Capability::OBJECT_NAME => \Stripe\Capability::class,
\Stripe\Card::OBJECT_NAME => \Stripe\Card::class,
\Stripe\CashBalance::OBJECT_NAME => \Stripe\CashBalance::class,
\Stripe\Charge::OBJECT_NAME => \Stripe\Charge::class,
\Stripe\Checkout\Session::OBJECT_NAME => \Stripe\Checkout\Session::class,
\Stripe\Climate\Order::OBJECT_NAME => \Stripe\Climate\Order::class,
\Stripe\Climate\Product::OBJECT_NAME => \Stripe\Climate\Product::class,
\Stripe\Climate\Supplier::OBJECT_NAME => \Stripe\Climate\Supplier::class,
\Stripe\ConfirmationToken::OBJECT_NAME => \Stripe\ConfirmationToken::class,
\Stripe\ConnectCollectionTransfer::OBJECT_NAME => \Stripe\ConnectCollectionTransfer::class,
\Stripe\CountrySpec::OBJECT_NAME => \Stripe\CountrySpec::class,
\Stripe\Coupon::OBJECT_NAME => \Stripe\Coupon::class,
\Stripe\CreditNote::OBJECT_NAME => \Stripe\CreditNote::class,
\Stripe\CreditNoteLineItem::OBJECT_NAME => \Stripe\CreditNoteLineItem::class,
\Stripe\Customer::OBJECT_NAME => \Stripe\Customer::class,
\Stripe\CustomerBalanceTransaction::OBJECT_NAME => \Stripe\CustomerBalanceTransaction::class,
\Stripe\CustomerCashBalanceTransaction::OBJECT_NAME => \Stripe\CustomerCashBalanceTransaction::class,
\Stripe\CustomerSession::OBJECT_NAME => \Stripe\CustomerSession::class,
\Stripe\Discount::OBJECT_NAME => \Stripe\Discount::class,
\Stripe\Dispute::OBJECT_NAME => \Stripe\Dispute::class,
\Stripe\Entitlements\ActiveEntitlement::OBJECT_NAME => \Stripe\Entitlements\ActiveEntitlement::class,
\Stripe\Entitlements\ActiveEntitlementSummary::OBJECT_NAME => \Stripe\Entitlements\ActiveEntitlementSummary::class,
\Stripe\Entitlements\Feature::OBJECT_NAME => \Stripe\Entitlements\Feature::class,
\Stripe\EphemeralKey::OBJECT_NAME => \Stripe\EphemeralKey::class,
\Stripe\Event::OBJECT_NAME => \Stripe\Event::class,
\Stripe\ExchangeRate::OBJECT_NAME => \Stripe\ExchangeRate::class,
\Stripe\File::OBJECT_NAME => \Stripe\File::class,
\Stripe\FileLink::OBJECT_NAME => \Stripe\FileLink::class,
\Stripe\FinancialConnections\Account::OBJECT_NAME => \Stripe\FinancialConnections\Account::class,
\Stripe\FinancialConnections\AccountOwner::OBJECT_NAME => \Stripe\FinancialConnections\AccountOwner::class,
\Stripe\FinancialConnections\AccountOwnership::OBJECT_NAME => \Stripe\FinancialConnections\AccountOwnership::class,
\Stripe\FinancialConnections\Session::OBJECT_NAME => \Stripe\FinancialConnections\Session::class,
\Stripe\FinancialConnections\Transaction::OBJECT_NAME => \Stripe\FinancialConnections\Transaction::class,
\Stripe\Forwarding\Request::OBJECT_NAME => \Stripe\Forwarding\Request::class,
\Stripe\FundingInstructions::OBJECT_NAME => \Stripe\FundingInstructions::class,
\Stripe\Identity\VerificationReport::OBJECT_NAME => \Stripe\Identity\VerificationReport::class,
\Stripe\Identity\VerificationSession::OBJECT_NAME => \Stripe\Identity\VerificationSession::class,
\Stripe\Invoice::OBJECT_NAME => \Stripe\Invoice::class,
\Stripe\InvoiceItem::OBJECT_NAME => \Stripe\InvoiceItem::class,
\Stripe\InvoiceLineItem::OBJECT_NAME => \Stripe\InvoiceLineItem::class,
\Stripe\InvoiceRenderingTemplate::OBJECT_NAME => \Stripe\InvoiceRenderingTemplate::class,
\Stripe\Issuing\Authorization::OBJECT_NAME => \Stripe\Issuing\Authorization::class,
\Stripe\Issuing\Card::OBJECT_NAME => \Stripe\Issuing\Card::class,
\Stripe\Issuing\Cardholder::OBJECT_NAME => \Stripe\Issuing\Cardholder::class,
\Stripe\Issuing\Dispute::OBJECT_NAME => \Stripe\Issuing\Dispute::class,
\Stripe\Issuing\PersonalizationDesign::OBJECT_NAME => \Stripe\Issuing\PersonalizationDesign::class,
\Stripe\Issuing\PhysicalBundle::OBJECT_NAME => \Stripe\Issuing\PhysicalBundle::class,
\Stripe\Issuing\Token::OBJECT_NAME => \Stripe\Issuing\Token::class,
\Stripe\Issuing\Transaction::OBJECT_NAME => \Stripe\Issuing\Transaction::class,
\Stripe\LineItem::OBJECT_NAME => \Stripe\LineItem::class,
\Stripe\LoginLink::OBJECT_NAME => \Stripe\LoginLink::class,
\Stripe\Mandate::OBJECT_NAME => \Stripe\Mandate::class,
\Stripe\PaymentIntent::OBJECT_NAME => \Stripe\PaymentIntent::class,
\Stripe\PaymentLink::OBJECT_NAME => \Stripe\PaymentLink::class,
\Stripe\PaymentMethod::OBJECT_NAME => \Stripe\PaymentMethod::class,
\Stripe\PaymentMethodConfiguration::OBJECT_NAME => \Stripe\PaymentMethodConfiguration::class,
\Stripe\PaymentMethodDomain::OBJECT_NAME => \Stripe\PaymentMethodDomain::class,
\Stripe\Payout::OBJECT_NAME => \Stripe\Payout::class,
\Stripe\Person::OBJECT_NAME => \Stripe\Person::class,
\Stripe\Plan::OBJECT_NAME => \Stripe\Plan::class,
\Stripe\Price::OBJECT_NAME => \Stripe\Price::class,
\Stripe\Product::OBJECT_NAME => \Stripe\Product::class,
\Stripe\ProductFeature::OBJECT_NAME => \Stripe\ProductFeature::class,
\Stripe\PromotionCode::OBJECT_NAME => \Stripe\PromotionCode::class,
\Stripe\Quote::OBJECT_NAME => \Stripe\Quote::class,
\Stripe\Radar\EarlyFraudWarning::OBJECT_NAME => \Stripe\Radar\EarlyFraudWarning::class,
\Stripe\Radar\ValueList::OBJECT_NAME => \Stripe\Radar\ValueList::class,
\Stripe\Radar\ValueListItem::OBJECT_NAME => \Stripe\Radar\ValueListItem::class,
\Stripe\Refund::OBJECT_NAME => \Stripe\Refund::class,
\Stripe\Reporting\ReportRun::OBJECT_NAME => \Stripe\Reporting\ReportRun::class,
\Stripe\Reporting\ReportType::OBJECT_NAME => \Stripe\Reporting\ReportType::class,
\Stripe\ReserveTransaction::OBJECT_NAME => \Stripe\ReserveTransaction::class,
\Stripe\Review::OBJECT_NAME => \Stripe\Review::class,
\Stripe\SetupAttempt::OBJECT_NAME => \Stripe\SetupAttempt::class,
\Stripe\SetupIntent::OBJECT_NAME => \Stripe\SetupIntent::class,
\Stripe\ShippingRate::OBJECT_NAME => \Stripe\ShippingRate::class,
\Stripe\Sigma\ScheduledQueryRun::OBJECT_NAME => \Stripe\Sigma\ScheduledQueryRun::class,
\Stripe\Source::OBJECT_NAME => \Stripe\Source::class,
\Stripe\SourceMandateNotification::OBJECT_NAME => \Stripe\SourceMandateNotification::class,
\Stripe\SourceTransaction::OBJECT_NAME => \Stripe\SourceTransaction::class,
\Stripe\Subscription::OBJECT_NAME => \Stripe\Subscription::class,
\Stripe\SubscriptionItem::OBJECT_NAME => \Stripe\SubscriptionItem::class,
\Stripe\SubscriptionSchedule::OBJECT_NAME => \Stripe\SubscriptionSchedule::class,
\Stripe\Tax\Calculation::OBJECT_NAME => \Stripe\Tax\Calculation::class,
\Stripe\Tax\CalculationLineItem::OBJECT_NAME => \Stripe\Tax\CalculationLineItem::class,
\Stripe\Tax\Registration::OBJECT_NAME => \Stripe\Tax\Registration::class,
\Stripe\Tax\Settings::OBJECT_NAME => \Stripe\Tax\Settings::class,
\Stripe\Tax\Transaction::OBJECT_NAME => \Stripe\Tax\Transaction::class,
\Stripe\Tax\TransactionLineItem::OBJECT_NAME => \Stripe\Tax\TransactionLineItem::class,
\Stripe\TaxCode::OBJECT_NAME => \Stripe\TaxCode::class,
\Stripe\TaxDeductedAtSource::OBJECT_NAME => \Stripe\TaxDeductedAtSource::class,
\Stripe\TaxId::OBJECT_NAME => \Stripe\TaxId::class,
\Stripe\TaxRate::OBJECT_NAME => \Stripe\TaxRate::class,
\Stripe\Terminal\Configuration::OBJECT_NAME => \Stripe\Terminal\Configuration::class,
\Stripe\Terminal\ConnectionToken::OBJECT_NAME => \Stripe\Terminal\ConnectionToken::class,
\Stripe\Terminal\Location::OBJECT_NAME => \Stripe\Terminal\Location::class,
\Stripe\Terminal\Reader::OBJECT_NAME => \Stripe\Terminal\Reader::class,
\Stripe\TestHelpers\TestClock::OBJECT_NAME => \Stripe\TestHelpers\TestClock::class,
\Stripe\Token::OBJECT_NAME => \Stripe\Token::class,
\Stripe\Topup::OBJECT_NAME => \Stripe\Topup::class,
\Stripe\Transfer::OBJECT_NAME => \Stripe\Transfer::class,
\Stripe\TransferReversal::OBJECT_NAME => \Stripe\TransferReversal::class,
\Stripe\Treasury\CreditReversal::OBJECT_NAME => \Stripe\Treasury\CreditReversal::class,
\Stripe\Treasury\DebitReversal::OBJECT_NAME => \Stripe\Treasury\DebitReversal::class,
\Stripe\Treasury\FinancialAccount::OBJECT_NAME => \Stripe\Treasury\FinancialAccount::class,
\Stripe\Treasury\FinancialAccountFeatures::OBJECT_NAME => \Stripe\Treasury\FinancialAccountFeatures::class,
\Stripe\Treasury\InboundTransfer::OBJECT_NAME => \Stripe\Treasury\InboundTransfer::class,
\Stripe\Treasury\OutboundPayment::OBJECT_NAME => \Stripe\Treasury\OutboundPayment::class,
\Stripe\Treasury\OutboundTransfer::OBJECT_NAME => \Stripe\Treasury\OutboundTransfer::class,
\Stripe\Treasury\ReceivedCredit::OBJECT_NAME => \Stripe\Treasury\ReceivedCredit::class,
\Stripe\Treasury\ReceivedDebit::OBJECT_NAME => \Stripe\Treasury\ReceivedDebit::class,
\Stripe\Treasury\Transaction::OBJECT_NAME => \Stripe\Treasury\Transaction::class,
\Stripe\Treasury\TransactionEntry::OBJECT_NAME => \Stripe\Treasury\TransactionEntry::class,
\Stripe\UsageRecord::OBJECT_NAME => \Stripe\UsageRecord::class,
\Stripe\UsageRecordSummary::OBJECT_NAME => \Stripe\UsageRecordSummary::class,
\Stripe\WebhookEndpoint::OBJECT_NAME => \Stripe\WebhookEndpoint::class,
// object classes: The end of the section generated from our OpenAPI spec
];
/**
* @var array Mapping from v2 object types to resource classes
*/
const v2Mapping = [
// v2 object classes: The beginning of the section generated from our OpenAPI spec
\Stripe\V2\Billing\MeterEvent::OBJECT_NAME => \Stripe\V2\Billing\MeterEvent::class,
\Stripe\V2\Billing\MeterEventAdjustment::OBJECT_NAME => \Stripe\V2\Billing\MeterEventAdjustment::class,
\Stripe\V2\Billing\MeterEventSession::OBJECT_NAME => \Stripe\V2\Billing\MeterEventSession::class,
\Stripe\V2\Event::OBJECT_NAME => \Stripe\V2\Event::class,
// v2 object classes: The end of the section generated from our OpenAPI spec
];
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Stripe\Util;
/**
* A basic random generator. This is in a separate class so we the generator
* can be injected as a dependency and replaced with a mock in tests.
*/
class RandomGenerator
{
/**
* Returns a random value between 0 and $max.
*
* @param float $max (optional)
*
* @return float
*/
public function randFloat($max = 1.0)
{
return \mt_rand() / \mt_getrandmax() * $max;
}
/**
* Returns a v4 UUID.
*
* @return string
*/
public function uuid()
{
$arr = \array_values(\unpack('N1a/n4b/N1c', \openssl_random_pseudo_bytes(16)));
$arr[2] = ($arr[2] & 0x0FFF) | 0x4000;
$arr[3] = ($arr[3] & 0x3FFF) | 0x8000;
return \vsprintf('%08x-%04x-%04x-%04x-%04x%08x', $arr);
}
}

View File

@@ -0,0 +1,187 @@
<?php
namespace Stripe\Util;
/**
* @phpstan-type RequestOptionsArray array{api_key?: string, idempotency_key?: string, stripe_account?: string, stripe_context?: string, stripe_version?: string, api_base?: string }
* @psalm-type RequestOptionsArray = array{api_key?: string, idempotency_key?: string, stripe_account?: string, stripe_context?: string, stripe_version?: string, api_base?: string }
*/
class RequestOptions
{
/**
* @var array<string> a list of headers that should be persisted across requests
*/
public static $HEADERS_TO_PERSIST = [
'Stripe-Account',
'Stripe-Version',
];
/** @var array<string, string> */
public $headers;
/** @var null|string */
public $apiKey;
/** @var null|string */
public $apiBase;
/**
* @param null|string $key
* @param array<string, string> $headers
* @param null|string $base
*/
public function __construct($key = null, $headers = [], $base = null)
{
$this->apiKey = $key;
$this->headers = $headers;
$this->apiBase = $base;
}
/**
* @return array<string, string>
*/
public function __debugInfo()
{
return [
'apiKey' => $this->redactedApiKey(),
'headers' => $this->headers,
'apiBase' => $this->apiBase,
];
}
/**
* Unpacks an options array and merges it into the existing RequestOptions
* object.
*
* @param null|array|RequestOptions|string $options a key => value array
* @param bool $strict when true, forbid string form and arbitrary keys in array form
*
* @return RequestOptions
*/
public function merge($options, $strict = false)
{
$other_options = self::parse($options, $strict);
if (null === $other_options->apiKey) {
$other_options->apiKey = $this->apiKey;
}
if (null === $other_options->apiBase) {
$other_options->apiBase = $this->apiBase;
}
$other_options->headers = \array_merge($this->headers, $other_options->headers);
return $other_options;
}
/**
* Discards all headers that we don't want to persist across requests.
*/
public function discardNonPersistentHeaders()
{
foreach ($this->headers as $k => $v) {
if (!\in_array($k, self::$HEADERS_TO_PERSIST, true)) {
unset($this->headers[$k]);
}
}
}
/**
* Unpacks an options array into an RequestOptions object.
*
* @param null|array|RequestOptions|string $options a key => value array
* @param bool $strict when true, forbid string form and arbitrary keys in array form
*
* @throws \Stripe\Exception\InvalidArgumentException
*
* @return RequestOptions
*/
public static function parse($options, $strict = false)
{
if ($options instanceof self) {
return clone $options;
}
if (null === $options) {
return new RequestOptions(null, [], null);
}
if (\is_string($options)) {
if ($strict) {
$message = 'Do not pass a string for request options. If you want to set the '
. 'API key, pass an array like ["api_key" => <apiKey>] instead.';
throw new \Stripe\Exception\InvalidArgumentException($message);
}
return new RequestOptions($options, [], null);
}
if (\is_array($options)) {
$headers = [];
$key = null;
$base = null;
if (\array_key_exists('api_key', $options)) {
$key = $options['api_key'];
unset($options['api_key']);
}
if (\array_key_exists('idempotency_key', $options)) {
$headers['Idempotency-Key'] = $options['idempotency_key'];
unset($options['idempotency_key']);
}
if (\array_key_exists('stripe_account', $options)) {
if (null !== $options['stripe_account']) {
$headers['Stripe-Account'] = $options['stripe_account'];
}
unset($options['stripe_account']);
}
if (\array_key_exists('stripe_context', $options)) {
if (null !== $options['stripe_context']) {
$headers['Stripe-Context'] = $options['stripe_context'];
}
unset($options['stripe_context']);
}
if (\array_key_exists('stripe_version', $options)) {
if (null !== $options['stripe_version']) {
$headers['Stripe-Version'] = $options['stripe_version'];
}
unset($options['stripe_version']);
}
if (\array_key_exists('api_base', $options)) {
$base = $options['api_base'];
unset($options['api_base']);
}
if ($strict && !empty($options)) {
$message = 'Got unexpected keys in options array: ' . \implode(', ', \array_keys($options));
throw new \Stripe\Exception\InvalidArgumentException($message);
}
return new RequestOptions($key, $headers, $base);
}
$message = 'The second argument to Stripe API method calls is an '
. 'optional per-request apiKey, which must be a string, or '
. 'per-request options, which must be an array. (HINT: you can set '
. 'a global apiKey by "Stripe::setApiKey(<apiKey>)")';
throw new \Stripe\Exception\InvalidArgumentException($message);
}
/** @return string */
private function redactedApiKey()
{
if (null === $this->apiKey) {
return '';
}
$pieces = \explode('_', $this->apiKey, 3);
$last = \array_pop($pieces);
$redactedLast = \strlen($last) > 4
? (\str_repeat('*', \strlen($last) - 4) . \substr($last, -4))
: $last;
$pieces[] = $redactedLast;
return \implode('_', $pieces);
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Stripe\Util;
use ArrayIterator;
use IteratorAggregate;
class Set implements IteratorAggregate
{
private $_elts;
public function __construct($members = [])
{
$this->_elts = [];
foreach ($members as $item) {
$this->_elts[$item] = true;
}
}
public function includes($elt)
{
return isset($this->_elts[$elt]);
}
public function add($elt)
{
$this->_elts[$elt] = true;
}
public function discard($elt)
{
unset($this->_elts[$elt]);
}
public function toArray()
{
return \array_keys($this->_elts);
}
/**
* @return ArrayIterator
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
return new ArrayIterator($this->toArray());
}
}

View File

@@ -0,0 +1,362 @@
<?php
namespace Stripe\Util;
use Stripe\StripeObject;
abstract class Util
{
private static $isMbstringAvailable = null;
private static $isHashEqualsAvailable = null;
/**
* Whether the provided array (or other) is a list rather than a dictionary.
* A list is defined as an array for which all the keys are consecutive
* integers starting at 0. Empty arrays are considered to be lists.
*
* @param array|mixed $array
*
* @return bool true if the given object is a list
*/
public static function isList($array)
{
if (!\is_array($array)) {
return false;
}
if ([] === $array) {
return true;
}
if (\array_keys($array) !== \range(0, \count($array) - 1)) {
return false;
}
return true;
}
/**
* Converts a response from the Stripe API to the corresponding PHP object.
*
* @param array $resp the response from the Stripe API
* @param array|RequestOptions $opts
* @param 'v1'|'v2' $apiMode whether the response is from a v1 or v2 API
*
* @return array|StripeObject
*/
public static function convertToStripeObject($resp, $opts, $apiMode = 'v1')
{
$types = 'v1' === $apiMode ? \Stripe\Util\ObjectTypes::mapping
: \Stripe\Util\ObjectTypes::v2Mapping;
if (self::isList($resp)) {
$mapped = [];
foreach ($resp as $i) {
$mapped[] = self::convertToStripeObject($i, $opts, $apiMode);
}
return $mapped;
}
if (\is_array($resp)) {
if (isset($resp['object']) && \is_string($resp['object'])
&& isset($types[$resp['object']])
) {
$class = $types[$resp['object']];
if ('v2' === $apiMode && ('v2.core.event' === $resp['object'])) {
$eventTypes = \Stripe\Util\EventTypes::thinEventMapping;
if (\array_key_exists('type', $resp) && \array_key_exists($resp['type'], $eventTypes)) {
$class = $eventTypes[$resp['type']];
} else {
$class = \Stripe\StripeObject::class;
}
}
} elseif (\array_key_exists('data', $resp) && \array_key_exists('next_page_url', $resp)) {
// TODO: this is a horrible hack. The API needs
// to return something for `object` here.
$class = \Stripe\V2\Collection::class;
} else {
$class = \Stripe\StripeObject::class;
}
return $class::constructFrom($resp, $opts, $apiMode);
}
return $resp;
}
/**
* @param mixed $json
* @param mixed $class
*
* @throws \ReflectionException
*/
public static function json_decode_thin_event_object($json, $class)
{
$reflection = new \ReflectionClass($class);
$instance = $reflection->newInstanceWithoutConstructor();
$json = json_decode($json, true);
$properties = $reflection->getProperties();
foreach ($properties as $key => $property) {
if (\array_key_exists($property->getName(), $json)) {
if ('related_object' === $property->getName()) {
$related_object = new \Stripe\RelatedObject();
$related_object->id = $json['related_object']['id'];
$related_object->url = $json['related_object']['url'];
$related_object->type = $json['related_object']['type'];
$property->setValue($instance, $related_object);
} elseif ('reason' === $property->getName()) {
$reason = new \Stripe\Reason();
$reason->id = $json['reason']['id'];
$reason->idempotency_key = $json['reason']['idempotency_key'];
$property->setValue($instance, $reason);
} else {
$property->setAccessible(true);
$property->setValue($instance, $json[$property->getName()]);
}
}
}
return $instance;
}
/**
* @param mixed|string $value a string to UTF8-encode
*
* @return mixed|string the UTF8-encoded string, or the object passed in if
* it wasn't a string
*/
public static function utf8($value)
{
if (null === self::$isMbstringAvailable) {
self::$isMbstringAvailable = \function_exists('mb_detect_encoding')
&& \function_exists('mb_convert_encoding');
if (!self::$isMbstringAvailable) {
\trigger_error(
'It looks like the mbstring extension is not enabled. ' .
'UTF-8 strings will not properly be encoded. Ask your system '
.
'administrator to enable the mbstring extension, or write to '
.
'support@stripe.com if you have any questions.',
\E_USER_WARNING
);
}
}
if (\is_string($value) && self::$isMbstringAvailable
&& 'UTF-8' !== \mb_detect_encoding($value, 'UTF-8', true)
) {
return mb_convert_encoding($value, 'UTF-8', 'ISO-8859-1');
}
return $value;
}
/**
* Compares two strings for equality. The time taken is independent of the
* number of characters that match.
*
* @param string $a one of the strings to compare
* @param string $b the other string to compare
*
* @return bool true if the strings are equal, false otherwise
*/
public static function secureCompare($a, $b)
{
if (null === self::$isHashEqualsAvailable) {
self::$isHashEqualsAvailable = \function_exists('hash_equals');
}
if (self::$isHashEqualsAvailable) {
return \hash_equals($a, $b);
}
if (\strlen($a) !== \strlen($b)) {
return false;
}
$result = 0;
for ($i = 0; $i < \strlen($a); ++$i) {
$result |= \ord($a[$i]) ^ \ord($b[$i]);
}
return 0 === $result;
}
/**
* Recursively goes through an array of parameters. If a parameter is an instance of
* ApiResource, then it is replaced by the resource's ID.
* Also clears out null values.
*
* @param mixed $h
*
* @return mixed
*/
public static function objectsToIds($h)
{
if ($h instanceof \Stripe\ApiResource) {
return $h->id;
}
if (static::isList($h)) {
$results = [];
foreach ($h as $v) {
$results[] = static::objectsToIds($v);
}
return $results;
}
if (\is_array($h)) {
$results = [];
foreach ($h as $k => $v) {
if (null === $v) {
continue;
}
$results[$k] = static::objectsToIds($v);
}
return $results;
}
return $h;
}
/**
* @param array $params
* @param mixed $apiMode
*
* @return string
*/
public static function encodeParameters($params, $apiMode = 'v1')
{
$flattenedParams = self::flattenParams($params, null, $apiMode);
$pieces = [];
foreach ($flattenedParams as $param) {
list($k, $v) = $param;
$pieces[] = self::urlEncode($k) . '=' . self::urlEncode($v);
}
return \implode('&', $pieces);
}
/**
* @param array $params
* @param null|string $parentKey
* @param mixed $apiMode
*
* @return array
*/
public static function flattenParams(
$params,
$parentKey = null,
$apiMode = 'v1'
) {
$result = [];
foreach ($params as $key => $value) {
$calculatedKey = $parentKey ? "{$parentKey}[{$key}]" : $key;
if (self::isList($value)) {
$result = \array_merge(
$result,
self::flattenParamsList($value, $calculatedKey, $apiMode)
);
} elseif (\is_array($value)) {
$result = \array_merge(
$result,
self::flattenParams($value, $calculatedKey, $apiMode)
);
} else {
\array_push($result, [$calculatedKey, $value]);
}
}
return $result;
}
/**
* @param array $value
* @param string $calculatedKey
* @param mixed $apiMode
*
* @return array
*/
public static function flattenParamsList(
$value,
$calculatedKey,
$apiMode = 'v1'
) {
$result = [];
foreach ($value as $i => $elem) {
if (self::isList($elem)) {
$result = \array_merge(
$result,
self::flattenParamsList($elem, $calculatedKey)
);
} elseif (\is_array($elem)) {
$result = \array_merge(
$result,
self::flattenParams($elem, "{$calculatedKey}[{$i}]")
);
} else {
if ('v2' === $apiMode) {
\array_push($result, ["{$calculatedKey}", $elem]);
} else {
\array_push($result, ["{$calculatedKey}[{$i}]", $elem]);
}
}
}
return $result;
}
/**
* @param string $key a string to URL-encode
*
* @return string the URL-encoded string
*/
public static function urlEncode($key)
{
$s = \urlencode((string) $key);
// Don't use strict form encoding by changing the square bracket control
// characters back to their literals. This is fine by the server, and
// makes these parameter strings easier to read.
$s = \str_replace('%5B', '[', $s);
return \str_replace('%5D', ']', $s);
}
public static function normalizeId($id)
{
if (\is_array($id)) {
// see https://github.com/stripe/stripe-php/pull/1602
if (!isset($id['id'])) {
return [null, $id];
}
$params = $id;
$id = $params['id'];
unset($params['id']);
} else {
$params = [];
}
return [$id, $params];
}
/**
* Returns UNIX timestamp in milliseconds.
*
* @return int current time in millis
*/
public static function currentTimeMillis()
{
return (int) \round(\microtime(true) * 1000);
}
public static function getApiMode($path)
{
$apiMode = 'v1';
if ('/v2' === substr($path, 0, 3)) {
$apiMode = 'v2';
}
return $apiMode;
}
}