Файловый менеджер - Редактировать - /home/harasnat/www/labour/wp-content/plugins/woocommerce-payments/includes/core/server/class-request.php
Назад
<?php /** * Class file for WCPay\Core\Server\Request. * * @package WooCommerce Payments */ namespace WCPay\Core\Server; use DateTime; use WC_Payments; use WC_Payments_Http_Interface; use WC_Payments_API_Client; use WCPay\Core\Exceptions\Server\Request\Extend_Request_Exception; use WCPay\Core\Exceptions\Server\Request\Immutable_Parameter_Exception; use WCPay\Core\Exceptions\Server\Request\Invalid_Request_Parameter_Exception; use WCPay\Core\Server\Request\Get_Request; use WCPay\Exceptions\API_Exception; use WP_Error; /** * Base for requests to the WCPay server. */ abstract class Request { /** * Contains a set of params, which the class considers immutable by others. * * Overwrite this in your class for individual properties. * * @var string[] */ const IMMUTABLE_PARAMS = []; /** * Indicates which parameters are required (keys only). * * @var string[] */ const REQUIRED_PARAMS = []; /** * Contains default values for parameters, which are not set automatically. * * @var string[] */ const DEFAULT_PARAMS = []; /** * Holds the parameters of the request. * * @var [] */ private $params = []; /** * True when `->apply_filters()` is called to protect read-only props. * * In protected mode, if somebody tries to change an immutable param, * as declared in `IMMUTABLE_PARAMS`, an exception will be thrown. * * This way important params can be safe from modifications by extensions. * * @var bool */ private $protected_mode = false; /** * Stores the base class when `->apply_filters` is called. * This class will be checked when `::extend` is called. * * @var string */ private $base_class; /** * Holds the API client of WCPay. * * @var WC_Payments_API_Client */ protected $api_client; /** * Holds the HTTP interface of WCPay. * * @var WC_Payments_Http_Interface */ protected $http_interface; /** * Holds the ID of an item, which is included in the request URL. * * @var mixed (int|string) */ protected $id; /** * Specifies the WordPress hook name that will be triggered upon calling the send() method. * * @var string */ protected $hook = ''; /** * Used to set the arguments for the request class WordPress hook. Make sure to add hook name first. * * @var array */ protected $hook_args = []; /** * Creates a new request, loading dependencies in there. * * @param mixed $id The identifier for various update/get/delete requests. * * @indexof $this->routeList * * @return static */ /** * Route list. * * @var string[] */ private $route_list = [ WC_Payments_API_Client::ACCOUNTS_API => 'accounts', WC_Payments_API_Client::CAPABILITIES_API => 'accounts/capabilities', WC_Payments_API_Client::WOOPAY_ACCOUNTS_API => 'accounts/platform_checkout', WC_Payments_API_Client::WOOPAY_COMPATIBILITY_API => 'woopay/compatibility', WC_Payments_API_Client::DOMAIN_REGISTRATION_API => 'payment_method_domains', WC_Payments_API_Client::CHARGES_API => 'charges', WC_Payments_API_Client::CONN_TOKENS_API => 'terminal/connection_tokens', WC_Payments_API_Client::TERMINAL_LOCATIONS_API => 'terminal/locations', WC_Payments_API_Client::CUSTOMERS_API => 'customers', WC_Payments_API_Client::CURRENCY_API => 'currency', WC_Payments_API_Client::INTENTIONS_API => 'intentions', WC_Payments_API_Client::REFUNDS_API => 'refunds', WC_Payments_API_Client::DEPOSITS_API => 'deposits', WC_Payments_API_Client::TRANSACTIONS_API => 'transactions', WC_Payments_API_Client::DISPUTES_API => 'disputes', WC_Payments_API_Client::FILES_API => 'files', WC_Payments_API_Client::ONBOARDING_API => 'onboarding', WC_Payments_API_Client::TIMELINE_API => 'timeline', WC_Payments_API_Client::PAYMENT_METHODS_API => 'payment_methods', WC_Payments_API_Client::SETUP_INTENTS_API => 'setup_intents', WC_Payments_API_Client::TRACKING_API => 'tracking', WC_Payments_API_Client::PAYMENT_PROCESS_CONFIG_API => 'payment_process_config', WC_Payments_API_Client::PRODUCTS_API => 'products', WC_Payments_API_Client::PRICES_API => 'products/prices', WC_Payments_API_Client::INVOICES_API => 'invoices', WC_Payments_API_Client::SUBSCRIPTIONS_API => 'subscriptions', WC_Payments_API_Client::SUBSCRIPTION_ITEMS_API => 'subscriptions/items', WC_Payments_API_Client::READERS_CHARGE_SUMMARY => 'reader-charges/summary', WC_Payments_API_Client::TERMINAL_READERS_API => 'terminal/readers', WC_Payments_API_Client::MINIMUM_RECURRING_AMOUNT_API => 'subscriptions/minimum_amount', WC_Payments_API_Client::CAPITAL_API => 'capital', WC_Payments_API_Client::WEBHOOK_FETCH_API => 'webhook/failed_events', WC_Payments_API_Client::DOCUMENTS_API => 'documents', WC_Payments_API_Client::VAT_API => 'vat', WC_Payments_API_Client::LINKS_API => 'links', WC_Payments_API_Client::AUTHORIZATIONS_API => 'authorizations', WC_Payments_API_Client::FRAUD_OUTCOMES_API => 'fraud_outcomes', WC_Payments_API_Client::FRAUD_RULESET_API => 'fraud_ruleset', WC_Payments_API_Client::COMPATIBILITY_API => 'compatibility', ]; /** * Creates a new request, loading dependencies in there. * * @param mixed $id The identifier for various update/get/delete requests. * * @return static */ public static function create( $id = null ) { return WC_Payments::create_request( static::class, $id ); } /** * GET Request wrapped for easier request creation. * * @param string $api Api method. * @param mixed $id An optional ID for the item that will be updated/retrieved/deleted. * * @return Request|Get_Request * * @throws Invalid_Request_Parameter_Exception|\Exception */ public static function get( string $api, $id = null ) { /** * Request variable. * * @var Get_Request $request */ $request = WC_Payments::create_request( Get_Request::class, $id ); $request->set_api( $api ); return $request; } /** * Prevents the class from being constructed directly. * * @param WC_Payments_API_Client $api_client The API client to use to send requests. * @param WC_Payments_Http_Interface $http_interface The HTTP interface for the server. * @param mixed $id An optional ID for the item that will be updated/retrieved/deleted. * * @throws Invalid_Request_Parameter_Exception */ public function __construct( WC_Payments_API_Client $api_client, WC_Payments_Http_Interface $http_interface, $id = null ) { $this->api_client = $api_client; $this->http_interface = $http_interface; $this->set_request_route_id_parameter( $id ); } /** * Returns the needed API. * * @return string Check WCPay\Core\Server\APIs. */ abstract public function get_api(): string; /** * Returns the method of the request. * * @return string See the constants in WordPress's `Requests` class. */ abstract public function get_method(): string; /** * This is a legacy method, and is the same throughout the codebase. * Might be worth removing while refactoring to use the Core\Server API. * * @return bool */ public function is_site_specific(): bool { return true; } /** * If true, the request will be signed with the user token rather than blog token. Defaults to false. * * @return bool */ public function should_use_user_token(): bool { return false; } /** * Indicates if the raw response should be returned. * * @return bool */ public function should_return_raw_response(): bool { return false; } /** * Returns all of the parameters for the request. * * @return array * @throws Invalid_Request_Parameter_Exception If the request has not been initialized yet. */ final public function get_params() { $defaults = static::get_default_params(); $params = array_merge( $defaults, $this->params ); $missing_params = []; foreach ( static::get_required_params() as $name ) { if ( ! isset( $params[ $name ] ) ) { $missing_params[] = $name; } } if ( ! empty( $missing_params ) ) { throw new Invalid_Request_Parameter_Exception( esc_html( sprintf( 'Trying to access the parameters of a request which is not (fully) initialized yet. Missing parameter(s) for %s: %s', get_class( $this ), implode( ', ', $missing_params ) ) ), 'wcpay_core_invalid_request_parameter_missing_parameters' ); } foreach ( $params as $key => $value ) { if ( true === $value ) { // The WCPay server requires the string 'true'. $params[ $key ] = 'true'; } } return $params; } /** * Get request param by key. * * @param string $key Key to get. * * @return mixed * @throws Invalid_Request_Parameter_Exception */ final public function get_param( $key ) { if ( array_key_exists( $key, $this->params ) ) { return $this->params[ $key ]; } throw new Invalid_Request_Parameter_Exception( esc_html( sprintf( 'The passed key %s does not exist in Request class', $key ) ), 'wcpay_core_invalid_request_parameter_uninitialized_param' ); } /** * Allows the request to be modified, and then sends it. * * @return mixed Either the response array, or the correct object. * * @throws Extend_Request_Exception * @throws Immutable_Parameter_Exception * @throws Invalid_Request_Parameter_Exception */ final public function send() { return $this->format_response( $this->api_client->send_request( $this->apply_filters( $this->hook, ...$this->hook_args ) ) ); } /** * This is mimic of send method, but where API exception is handled. * The reason behind this is that sometimes API request can fail for valid reasons and instead of handling this exception on every request, you could use this function. * * @return mixed Either the response array, or the correct object. * * @throws Extend_Request_Exception * @throws Immutable_Parameter_Exception * @throws Invalid_Request_Parameter_Exception */ final public function handle_rest_request() { try { $data = $this->send(); // Make sure to return array if $data is instance or has parent as a Response class. if ( is_a( $data, Response::class ) ) { return $data->to_array(); } // Return the data and let caller to parse it as it pleases. return $data; } catch ( API_Exception $e ) { return new WP_Error( $e->get_error_code(), $e->getMessage() ); } } /** * Formats the response from the server. * * @param mixed $response The response from `WC_Payments_API_Client::request`. * @return mixed Either the same response, or the correct object. */ public function format_response( $response ) { return new Response( $response ); } /** * Used to validate passed ID from the constructor. You can easily override it if you need custom id handling in your classes. * * @param mixed $id ID parameter. * * @return void * @throws Invalid_Request_Parameter_Exception */ protected function set_request_route_id_parameter( $id ) { if ( method_exists( $this, 'set_id' ) ) { if ( null !== $id ) { $this->set_id( $id ); } else { throw new Invalid_Request_Parameter_Exception( 'This request requires an item ID.', 'wcpay_core_invalid_request_parameter_missing_id' ); } } } /** * Assign the WordPress hook and the arguments specific to the previously assigned hook. * * @param string $hook WordPress hook name. */ public function assign_hook( string $hook ) { $this->hook = $hook; } /** * Set hook arguments. Used when hook is predefined in the request class, but you want to pass hook args. * * @param mixed ...$args Arguments for the hook. * @return void */ public function set_hook_args( ...$args ) { $this->hook_args = $args; } /** * Stores a parameter within the internal props. * * Use this method within child classes in order to allow * those properties to be protected by overwriting. * * @param string $key The name of the parameter. * @param mixed $value And the value to set. */ final protected function set_param( string $key, $value ) { if ( $this->protected_mode && in_array( $key, static::get_immutable_params(), true ) ) { $this->throw_immutable_exception( $key ); } $this->params[ $key ] = $value; } /** * Unsets an existing parameter if it was set before. * * @param string $key The key of the parameter. */ final protected function unset_param( string $key ) { if ( $this->protected_mode && in_array( $key, static::get_immutable_params(), true ) ) { $this->throw_immutable_exception( $key ); } if ( isset( $this->params[ $key ] ) ) { unset( $this->params[ $key ] ); } } /** * Replaces all internal parameters of the class. * Only accessible from methods of this class, used for the `extend` method. * * @param array $params The new parameters to use. */ private function set_params( $params ) { $this->params = $params; } /** * Creates a new instance of the called class with the same props * as an existing request, which must be of a parent class. * * This method is only available within `apply_filters()`. * * @param Request $base_request The request to extend. * @return static An instance of the class. * @throws Extend_Request_Exception In case this is not a subclass of the base request. */ final public static function extend( Request $base_request ) { $current_class = static::class; $base_request->validate_extended_class( $current_class, $base_request->base_class ?? get_class( $base_request ) ); if ( ! $base_request->protected_mode ) { throw new Extend_Request_Exception( esc_html( get_class( $base_request ) . ' can only be extended within its ->apply_filters() method.' ), 'wcpay_core_extend_class_incorrectly' ); } $obj = new $current_class( $base_request->api_client, $base_request->http_interface, $base_request->id ?? null ); $obj->set_params( array_merge( static::DEFAULT_PARAMS, $base_request->params ) ); // Carry over the base class and protected mode into the child request. $obj->base_class = $base_request->base_class; $obj->protected_mode = true; return $obj; } /** * Allows the request to be altered/replaced through a filter. * * Call this method when the request has been completely prepared, * and is ready to be sent to the server. At this point functions, * which hook into the filter cannot alter the IMMUTABLE_PARAMS * of the request anymore. Instead they can either modify the other * mutable params, or extend the request. * * @param string $hook The filter to use. * @param mixed ...$args Other parameters for the hook. * @return static Either the same instance, or an object from a sub-class. * @throws Extend_Request_Exception In case a class does not exist. * @throws Immutable_Parameter_Exception In case an immutable propery is tried to change. * @throws Invalid_Request_Parameter_Exception In case an invalid property is passed. */ final public function apply_filters( $hook, ...$args ) { // Lock the class in order to prevent `set_param` for protected props. $this->protected_mode = true; $this->base_class = get_class( $this ); // Validate API route. $this->validate_api_route( $this->get_api() ); /** * Allows a request to be modified, extended or replaced. * * @param Request $request The request to modify. * @param mixed ...$args Other provided parameters for the hook. * @return Request Either the same request, or a sub-class. */ $replacement = apply_filters( $hook, $this, ...$args ); // Exit protected mode right after `apply_filters`. $this->protected_mode = false; $my_class = get_class( $this ); $new_class = get_class( $replacement ); if ( $new_class !== $my_class ) { $this->validate_extended_class( $new_class, $my_class ); } // NB: `array_diff` will only pick up updated props, not new ones. $difference = $this->array_diff( $this->params, $replacement->params ); if ( empty( $difference ) ) { // Nothing got overwritten, it's the same request, or one with only new props. return $replacement; } foreach ( static::get_immutable_params() as $param ) { if ( isset( $difference[ $param ] ) ) { $this->throw_immutable_exception( $param ); } } return $replacement; } /** * Throws an exception upon attempts to mutate an immutable parameter. * * @param string $param The name of the param. * @throws Immutable_Parameter_Exception An exception, which indicates which property is immutable. */ private function throw_immutable_exception( string $param ) { throw new Immutable_Parameter_Exception( esc_html( sprintf( 'The value of %s::%s is immutable and cannot be changed.', get_class( $this ), $param ) ), 'wcpay_core_immutable_parameter_changed' ); } /** * Returns an array with the names of params, which should not be modified. * * @return string[] The names of those params. */ public static function get_immutable_params() { return static::traverse_class_constants( 'IMMUTABLE_PARAMS', true ); } /** * Returns an array with the names of params, which are required. * * @return string[] The names of those params. */ public static function get_required_params() { return static::traverse_class_constants( 'REQUIRED_PARAMS', true ); } /** * Returns an array with the combined default params from all classes. */ public static function get_default_params() { return static::traverse_class_constants( 'DEFAULT_PARAMS' ); } /** * Combines array constants from a class's tree. * * @param string $constant_name The name of the constant to load. * @param bool $unique Whether to return unique items. Useful with numeric keys. * @return string[] The unique combined values from the arrays. */ public static function traverse_class_constants( string $constant_name, bool $unique = false ) { $keys = []; $class_name = static::class; do { $constant = "$class_name::$constant_name"; if ( defined( $constant ) ) { $keys = array_merge( constant( $constant ), $keys ); } $class_name = get_parent_class( $class_name ); } while ( $class_name ); if ( $unique ) { $keys = array_unique( $keys ); } return $keys; } /** * Generates the difference between two arrays. * * @param array $array1 The first array. * @param array $array2 The second array. * @return array The difference between the two arrays. */ private function array_diff( $array1, $array2 ) { $arr_to_json = function ( $item ) { return is_array( $item ) ? wp_json_encode( $item ) : $item; }; return array_diff_assoc( array_map( $arr_to_json, $array1 ), array_map( $arr_to_json, $array2 ) ); } /** * Validates Stripe identifiers. * * @param string $id The identifier to validate. * @param mixed|null $prefixes A prefix or an array of them (Optional). * @throws Invalid_Request_Parameter_Exception An exception if the format is not matched. * @return void */ protected function validate_stripe_id( $id, $prefixes = null ) { if ( empty( $id ) ) { throw new Invalid_Request_Parameter_Exception( esc_html__( 'Empty parameter is not allowed', 'woocommerce-payments' ), 'wcpay_core_invalid_request_parameter_stripe_id' ); } if ( is_null( $prefixes ) ) { $prefixes = '[a-z]+'; } else { if ( ! is_array( $prefixes ) ) { $prefixes = [ $prefixes ]; } $prefixes = '(' . implode( '|', array_map( 'preg_quote', $prefixes ) ) . ')'; } /** * IDs include a prefix (a few characters), and are up to 255 characters long. * * @see https://stripe.com/docs/upgrades#what-changes-does-stripe-consider-to-be-backwards-compatible */ $regex = "/^{$prefixes}_\w{1,250}$/"; if ( preg_match( $regex, $id ) ) { return; } throw new Invalid_Request_Parameter_Exception( esc_html( sprintf( // Translators: %s is a Stripe ID. __( '%s is not a valid Stripe identifier', 'woocommerce-payments' ), $id ) ), 'wcpay_core_invalid_request_parameter_stripe_id' ); } /** * Validate is number larger than passed compared number. * * @param float $value_to_validate Value to validate. * @param float $value_to_compare Value to compare. * @throws Invalid_Request_Parameter_Exception An exception if the format is not matched. * @return void */ protected function validate_is_larger_than( float $value_to_validate, float $value_to_compare ) { if ( $value_to_validate > $value_to_compare ) { return; } throw new Invalid_Request_Parameter_Exception( esc_html( sprintf( /* translators: %1$s and %2$s are both numbers */ __( 'Invalid number passed. Number %1$s needs to be larger than %2$s', 'woocommerce-payments' ), $value_to_validate, $value_to_compare ) ), 'wcpay_core_invalid_request_parameter_order' ); } /** * Currency code validator. * * @param string $currency_code Currency code. * * @return void * @throws Invalid_Request_Parameter_Exception */ public function validate_currency_code( string $currency_code ) { $account_data = WC_Payments::get_account_service()->get_cached_account_data(); if ( isset( $account_data['customer_currencies']['supported'] ) && ! in_array( $currency_code, $account_data['customer_currencies']['supported'], true ) ) { throw new Invalid_Request_Parameter_Exception( esc_html( sprintf( // Translators: %s is a currency code. __( '%s is not a supported currency for payments.', 'woocommerce-payments' ), $currency_code ) ), 'wcpay_core_invalid_request_parameter_currency_not_available' ); } } /** * Extend class validator. * * @param mixed $child_class Child class. * @param string $parent_class Parent class. * * @return void * @throws Extend_Request_Exception */ public function validate_extended_class( $child_class, string $parent_class ) { if ( ! is_subclass_of( $child_class, $parent_class ) ) { throw new Extend_Request_Exception( esc_html( sprintf( 'Failed to extend request. %s is not a subclass of %s', is_string( $child_class ) ? $child_class : get_class( $child_class ), $parent_class ) ), 'wcpay_core_extend_class_not_subclass' ); } } /** * Validate date with given format. * * @param string $date Date to validate. * @param string $format Format to check. * * @return void * @throws Invalid_Request_Parameter_Exception */ public function validate_date( string $date, string $format = 'Y-m-d H:i:s' ) { $d = DateTime::createFromFormat( $format, $date ); if ( ! ( $d && $d->format( $format ) === $date ) ) { throw new Invalid_Request_Parameter_Exception( esc_html( sprintf( // Translators: %1$s is a provided date string, %2$s is a date format. __( '%1$s is not a valid date for format %2$s.', 'woocommerce-payments' ), $date, $format ) ), 'wcpay_core_invalid_request_parameter_invalid_date' ); } } /** * Validate a redirect URL in the allowed_redirect_hosts filter. * * @param string $redirect_url The provided redirect URL. * * @return void * @throws Invalid_Request_Parameter_Exception */ public function validate_redirect_url( string $redirect_url ) { $check_fallback_url = wp_generate_password( 12, false ); if ( hash_equals( $check_fallback_url, wp_validate_redirect( $redirect_url, $check_fallback_url ) ) ) { throw new Invalid_Request_Parameter_Exception( esc_html( sprintf( // Translators: %s is a currency code. __( '%1$s is not a valid redirect URL. Use a URL in the allowed_redirect_hosts filter.', 'woocommerce-payments' ), $redirect_url ) ), 'wcpay_core_invalid_request_parameter_invalid_redirect_url' ); } } /** * Validate if the username exists and is valid on the site. * * @param string $user_name Username to validate. * * @return void * @throws Invalid_Request_Parameter_Exception */ public function validate_user_name( string $user_name ) { $user = get_user_by( 'login', $user_name ); if ( false === $user ) { throw new Invalid_Request_Parameter_Exception( esc_html( sprintf( // Translators: %s is a provided username. __( '%s is not a valid username.', 'woocommerce-payments' ), $user_name ) ), 'wcpay_core_invalid_request_parameter_invalid_username' ); } } /** * Validates API endpoint or route. * * @param string $api_route API route to validate. * * @throws Invalid_Request_Parameter_Exception */ public function validate_api_route( string $api_route ) { $api_route = explode( '/', $api_route ); // In case if you have something after "/" like id or something similar. // Some routes have 2 URIs. In case route we want to validate have 2 (or more) URI,s lets validate that first. // There could be micro optimization to validate only array keys with two 'URI's but for now we can skip that part. if ( ( count( $api_route ) > 1 && array_key_exists( "$api_route[0]/$api_route[1]", $this->route_list ) ) || array_key_exists( $api_route[0], $this->route_list ) ) { return; } throw new Invalid_Request_Parameter_Exception( 'Invalid request api route', 'wcpay_core_invalid_request_parameter_api_route_not_defined' ); } }
| ver. 1.4 |
Github
|
.
| PHP 8.1.33 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка