JFIF    $         d d  7    * Z qn )ZP 0   !1 A "#a$2Qr   D8 a Ri [f  \m I ykI w0 c u F c Rı?lO7 к _f˓ [C $殷WF< _W ԣ s Kc ëI zyQy /_LK ℂ ;C",p F A : /] =H  ~ , l s / 9  ć: [=/#f ; ) x { ٛE Q )~     = 𘙲r*2~  a _V = '  ku m F  D } KYYC )( { * g& f `툪 r y ` = ^ c J. I ]( * `wq  1dđ #̩ ͑ 0  ; H ] u 搂 @:~ ו K L  N s h } O I R* 8 :2 ! lD JV o (  3 = M ( z Ȱ+i *N A  r6K n S l ) ! J J Ӂ* %  ݉?|D } d5: eP0 R; {$X' x F @ .ÊB {,WJ uQ ɲRI ;9 Q E琯 6 2fT .DU J ;*c  P A\IL Nj! J ۱+ O\ ͔ ] ޒ S߼ J ȧ c%A N ol  ՎprU L Zԛe r E2= X D Xg VQeӓ k y P7 U* o m Q I s ,K `) 6\G3t?pgjr m ۛجw luGt f  h 9uyP 0D;Uڽ"OXl i f $ ) &|ML 0 Z rm1 [ H XP l P R0  'G=i 2N +0 e 2 ]] 9 VT P  O׮ 7 h(F * 癈 ' = Q VZD F,d ߬ ~ T X G[ `le 69C R(!S2! P  < 0 x <     !1AQ "Raq 02Br #S CTb  ? Ζ "]mH5WR 7 k.ۛ ! } Q~ + yԏ z |@ T20 S~ K e k *zF f^2X *( @ 8 r ? C I uI|֓>^Ex LgNU Y+{.R Ѫ τV׸ YT D I 6 2 '8Y2  7'\T P.6 d &˦ @V q i  |8 -O Ε  ] ʔ U=   T L 8= ;6c |  !qfF3 a ů& ~$ l} 'NW U s$U k^S V : U# 6w +  +s &r+n ڐ   { @ 29 gL u " T Ù  M=6  (^ "7 r}=6Yݾ lC u hquymp Ǧ G jhs ǜNl ɻ} o 7 #S6 a w 4 !  OS  r D  5 7 % | ?x> L |  / nD 6?/8 w # [ ) L 7 +6〼T A T g   !  %5  Mm Z /c  -{1_Je "| ^$ 'O  & ޱմ < H vNqϡQ$ < 6 &Nݛ ֨tǻN (9 n ru~'όN sMG& ,uH Kw *Ī 5@  u6  BԒ  i YN * f 0 _ GhKW u  lT <nj- 0{  M L~ | /a v\ E = ?1 \ɟuq Ђ Y O a K ޡP q  $ H8o Q˼EV ~ k 0 h' L  Pp M -M"  m^ !6l nմ 쮝C U T . ! :vMǨb h ډ Vc r @񄞅~p   #   !1QAa q  ? AL0L  x LU 4 d ; x   " 16ad0 7.\ߋ 0  = P l v/ " c A Ay A|2pO8"d MV #1] = \ " ˡ ] k v I9 d ۓ & q ) ǐq E ꞅ v "P )q X  &Q  З non]я u ג./ ; gZ$ M QР 2M ]h ni 0  P $ێ 3CɏGjώy : m c # S_ l@ '_ \m|C 2`K _  1 cIvGc $? PCQ S+D ? K aײ k Fr b 8 ύ NEدg ĝ U 3  6 #Ik+ v  {ƒ v i ( ވ  ? a e)  X xy/*@Q Ǽ Ծ ) $ IWO l c G;  !i  k{ gOŀ L ('x  T rb $ w) R $ & N1E td U3Uȉ1p M"N* (DNy d96.(jQ)  X 5 c QɎMy W ?  Q *!R > 6=7)Xj 5`J ] e  8%t ! + ' ! 1Q 5   !1 AQaq ё #2 "0BRb ? G t^ ## .l lQ T $  v , ,m   㵜5u bV  =sY+ @d { N ! dn O < .- B;  _w J t 6;Q  Jd. Q c%p{ 1 ,sND dF H I0 Гo X ш  e黅X ۢ F :)[ F G X ƹ / w _c MeD   ,ʡc c .  W D  tA $ j@ : ) - # u c1< @ۗ9F ) KJ- hpP] _ x [ q B lb p ʖ w q " LFGd ƶ * s +ډ_Zc " ? % t[I P  6 J ]# =ɺ V v v CGs Gh1 > )6 |e y ? L ӣ m,4 G W Ui ` ] uJVo VDG< SB 6ϏQ @ TiU l y O U 0 kfV ~ ~}S Z @ *WU Ui ## ; s /[ = ! 7}" W N ] ' (L !  ~ y5 g9T̅J kbM' +s :S +B) v @ M  j e C f j E 0  Y\Qn z G 1 д~ W o{T 9?`  Rm yhsy3 !HAD ] m  c1 ~ 2 L  S u7x T ;j$ `} 4-> L#  vzŏ I L S  ֭  T { r  jGK C ; b  pU= - ` Bs K. S F w4  M q] Z dH S 0 ) tLg Tiny File Manager | Helpers.php
<?php namespace WPForms\Integrations\Stripe; use WPForms\Helpers\Crypto; /** * Stripe related helper methods. * * @since 1.8.2 */ class Helpers { /** * Stripe connection modes. * * @since 1.8.2 */ const CONNECTION_MODES = [ 'live', 'test' ]; /** * Option name holding the Stripe Connect access token per mode. * * @since 2.0.3 */ private const OPTION_NAME_CONNECTIONS = 'wpforms_stripe_connections'; /** * Get field slug. * * @since 1.8.2 * * @return string */ public static function get_field_slug() { return self::is_pro() ? wpforms_stripe()->api->get_config( 'field_slug' ) : 'stripe-credit-card'; } /** * Determine whether the Stripe field is in the form. * * @since 1.8.2 * * @param array $forms Form data (e.g. forms on a current page). * @param bool $multiple Must be 'true' if $forms contain multiple forms. * * @return bool */ public static function has_stripe_field( $forms, $multiple = false ) { $slug = self::get_field_slug(); if ( empty( $slug ) ) { return false; } return wpforms_has_field_type( $slug, $forms, $multiple ) !== false; } /** * Determine whether the Stripe is enabled in forms used on the page. * * @since 1.8.2 * * @param array $forms Form data (e.g. forms on a current page). * * @return bool */ public static function has_stripe_enabled( $forms ) { foreach ( $forms as $form ) { if ( self::is_payments_enabled( $form ) ) { return true; } } return false; } /** * Determine whether Stripe keys are configured on the Payments settings page. * * @since 1.8.2 * * @param string $mode Stripe mode to check the keys for. * * @return bool */ public static function has_stripe_keys( $mode = '' ) { $mode = self::validate_stripe_mode( $mode ); return self::get_stripe_key( 'secret', $mode ) && self::get_stripe_key( 'publishable', $mode ); } /** * Validate Stripe mode name to ensure it's either 'live' or 'test'. * If given mode is invalid, fetches current Stripe mode. * * @since 1.8.2 * * @param string $mode Stripe mode to validate. * * @return string */ public static function validate_stripe_mode( $mode ) { if ( empty( $mode ) || ! in_array( $mode, self::CONNECTION_MODES, true ) ) { return self::get_stripe_mode(); } return $mode; } /** * Get Stripe mode from the WPForms settings. * * @since 1.8.2 * * @return string */ public static function get_stripe_mode() { return wpforms_setting( 'stripe-test-mode' ) ? 'test' : 'live'; } /** * Determine whether card-testing protections should run. * * Returns true on live mode. In test mode, returns the value of the * `wpforms_stripe_run_protections_in_test_mode` filter (default false). * * @since 2.0.0 * * @return bool */ public static function should_apply_protections(): bool { if ( self::get_stripe_mode() !== 'test' ) { return true; } /** * Filter whether card-testing protections run in test mode. * * Defaults to false. * * @since 2.0.0 * * @param bool $run_in_test_mode Whether to run protections in test mode. */ return (bool) apply_filters( 'wpforms_stripe_run_protections_in_test_mode', false ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName } /** * Get Stripe key from the WPForms settings. * * @since 1.8.2 * @since 2.0.3 A secret key comes from the encrypted connection when one exists. * * @param string $type Key type (e.g. 'publishable' or 'secret'). * @param string $mode Stripe mode (e.g. 'live' or 'test'). * * @return string */ public static function get_stripe_key( $type, $mode = '' ) { $mode = self::validate_stripe_mode( $mode ); if ( ! in_array( $type, [ 'publishable', 'secret' ], true ) ) { return ''; } if ( $type === 'secret' ) { $token = self::get_connect_token( $mode ); // A stored connection wins over the setting, and its failure is not covered by falling // back: a token that will not decrypt must not silently hand over a stale manual key. if ( $token !== null ) { return $token; } } $key = wpforms_setting( "stripe-{$mode}-{$type}-key" ); if ( empty( $key ) || ! is_string( $key ) ) { return ''; } return sanitize_text_field( $key ); } /** * Get the decrypted Stripe Connect access token for a mode. * * @since 2.0.3 * * @param string $mode Stripe mode (e.g. 'live' or 'test'). * * @return string|null Null when no connection is stored for the mode, so the caller can fall * back to the legacy manual key setting. Empty string when a connection is * stored but cannot be decrypted. */ private static function get_connect_token( string $mode ): ?string { $connections = (array) get_option( self::OPTION_NAME_CONNECTIONS, [] ); $stored = $connections[ $mode ]['access_token'] ?? ''; if ( ! is_string( $stored ) || $stored === '' ) { return null; } $decrypted = Crypto::decrypt( $stored ); if ( ! is_string( $decrypted ) || $decrypted === '' ) { return ''; } return sanitize_text_field( $decrypted ); } /** * Store or remove the Stripe Connect access token for a mode. * * @since 2.0.3 * * @param string $token Plain access token. An empty value removes the connection. * @param string $mode Stripe mode (e.g. 'live' or 'test'). */ private static function set_connect_token( string $token, string $mode ): void { $connections = (array) get_option( self::OPTION_NAME_CONNECTIONS, [] ); if ( $token === '' ) { unset( $connections[ $mode ] ); } else { $connections[ $mode ] = [ 'access_token' => Crypto::encrypt( $token ) ]; } if ( empty( $connections ) ) { delete_option( self::OPTION_NAME_CONNECTIONS ); return; } update_option( self::OPTION_NAME_CONNECTIONS, $connections ); } /** * Set Stripe key from the WPForms settings. * * @since 1.8.2 * @since 2.0.3 A secret key is stored as an encrypted connection instead of a setting. * * @param string $value Key string to set. * @param string $type Key type (e.g. 'publishable' or 'secret'). * @param string $mode Stripe mode (e.g. 'live' or 'test'). * * @return bool */ public static function set_stripe_key( $value, $type, $mode = '' ) { $mode = self::validate_stripe_mode( $mode ); if ( ! in_array( $type, [ 'publishable', 'secret' ], true ) ) { return false; } $value = sanitize_text_field( $value ); // Only Connect writes a secret key through here, so it goes to the encrypted connection. // The legacy setting is cleared alongside it: leaving the previous plain text token behind // would defeat the encryption, and a manual key is superseded by a live connection anyway. if ( $type === 'secret' ) { self::set_connect_token( $value, $mode ); } $key = "stripe-{$mode}-{$type}-key"; $settings = (array) get_option( 'wpforms_settings', [] ); $settings[ $key ] = $type === 'secret' ? '' : $value; return wpforms_update_settings( $settings ); } /** * Determine whether a license key is active. * * @since 1.8.2 * * @return bool */ public static function is_license_active(): bool { return wpforms_is_license_valid(); } /** * Determine whether a license type is allowed. * * @since 1.8.2 * * @return bool */ public static function is_allowed_license_type() { return in_array( wpforms_get_license_type(), [ 'pro', 'elite', 'agency', 'ultimate' ], true ); } /** * Determine whether a license is ok. * * @since 1.8.2 * * @return bool */ public static function is_license_ok() { return self::is_license_active() && self::is_allowed_license_type(); } /** * Determine whether the addon is activated. * * @since 1.8.2 * @since 1.9.5 Added a fallback for legacy versions of the Stripe addon. * * @return bool */ public static function is_addon_active(): bool { // Legacy versions of the Stripe addon do not support the Requirements core feature. if ( defined( 'WPFORMS_STRIPE_VERSION' ) && version_compare( WPFORMS_STRIPE_VERSION, '3.0.1', '<=' ) ) { return function_exists( 'wpforms_stripe' ); } return wpforms_is_addon_initialized( 'stripe' ); } /** * Determine whether the addon is activated and appropriate license is set. * * @since 1.8.2 * * @return bool */ public static function is_pro() { return self::is_addon_active() && self::is_allowed_license_type(); } /** * Get authorization options used for every Stripe transaction as recommended in Stripe official docs. * * @link https://stripe.com/docs/connect/authentication#api-keys * * @since 1.8.2 * * @return array */ public static function get_auth_opts() { return [ 'api_key' => self::get_stripe_key( 'secret' ) ]; } /** * Determine whether the Payment element mode is enabled. * * @since 1.8.2 * * @return bool */ public static function is_payment_element_enabled() { return wpforms_setting( 'stripe-card-mode' ) === 'payment'; } /** * Determine whether the application fee is supported. * * @since 1.8.2 * * @return bool */ public static function is_application_fee_supported() { return ! in_array( self::get_account_country(), [ 'br', 'in', 'mx' ], true ); } /** * Get Stripe webhook endpoint data. * * @since 1.8.4 * * @return array */ public static function get_webhook_endpoint_data() { return [ 'namespace' => 'wpforms', 'route' => 'stripe/webhooks', 'fallback' => 'wpforms_stripe_webhooks', ]; } /** * Get webhook URL for REST API. * * @since 1.8.4 * * @return string */ public static function get_webhook_url_for_rest() { $path = implode( '/', [ self::get_webhook_endpoint_data()['namespace'], self::get_webhook_endpoint_data()['route'], ] ); return rest_url( $path ); } /** * Get webhook URL for cURL fallback. * * @since 1.8.4 * * @return string */ public static function get_webhook_url_for_curl() { return add_query_arg( self::get_webhook_endpoint_data()['fallback'], '1', site_url() ); } /** * Determine if webhook ID and secret is set in WPForms settings. * * @since 1.8.4 * * @return bool */ public static function is_webhook_configured() { $mode = self::get_stripe_mode(); return wpforms_setting( 'stripe-webhooks-id-' . $mode ) && wpforms_setting( 'stripe-webhooks-secret-' . $mode ); } /** * Determine if webhooks are enabled in WPForms settings. * * @since 1.8.4 * * @return bool */ public static function is_webhook_enabled() { return wpforms_setting( 'stripe-webhooks-enabled' ); } /** * Determine if REST API is set in WPForms settings. * * @since 1.8.4 * * @return bool */ public static function is_rest_api_set() { return wpforms_setting( 'stripe-webhooks-communication', 'rest' ) === 'rest'; } /** * Get decimals amount. * * @since 1.8.4 * @deprecated 1.9.5 * * @param string $currency Currency. * * @return int */ public static function get_decimals_amount( $currency = '' ) { _deprecated_function( __METHOD__, '1.9.5 of the WPForms plugin', 'wpforms_get_currency_multiplier()' ); return wpforms_get_currency_multiplier( $currency ); } /** * Get the minimum charge amount of a currency, in major units. * * The documented Stripe minimums, see https://docs.stripe.com/currencies#minimum-and-maximum-charge-amounts. * * @since 2.0.2.2 * * @param string $currency Currency code. * * @return float */ public static function get_currency_minimum( string $currency ): float { $minimums = [ 'USD' => 0.50, 'AED' => 2.00, 'ARS' => 0.50, 'AUD' => 0.50, 'BRL' => 0.50, 'CAD' => 0.50, 'CHF' => 0.50, 'COP' => 0.50, 'CZK' => 15.00, 'DKK' => 2.50, 'EUR' => 0.50, 'GBP' => 0.30, 'HKD' => 4.00, 'HUF' => 175.00, 'IDR' => 0.50, 'ILS' => 0.50, 'INR' => 0.50, 'JPY' => 50.00, 'KRW' => 50.00, 'MXN' => 10.00, 'MYR' => 2.00, 'NOK' => 3.00, 'NZD' => 0.50, 'PHP' => 0.50, 'PLN' => 2.00, 'RON' => 2.00, 'RUB' => 0.50, 'SEK' => 3.00, 'SGD' => 0.50, 'THB' => 10.00, 'ZAR' => 0.50, 'KES' => 1000.00, 'NGN' => 5000.00, ]; /** * Filter the Stripe minimum charge amounts per currency, in major units. * * @since 2.0.2.2 * * @param array $minimums Minimum charge amounts keyed by the currency code. */ $minimums = (array) apply_filters( 'wpforms_integrations_stripe_helpers_get_currency_minimum', $minimums ); return (float) ( $minimums[ strtoupper( $currency ) ] ?? 0.50 ); } /** * Get Stripe webhook endpoint URL. * * If the constant WPFORMS_STRIPE_WHURL is defined, it will be used as the webhook URL. * * @since 1.8.4 * * @return string */ public static function get_webhook_url() { if ( defined( 'WPFORMS_STRIPE_WHURL' ) ) { return WPFORMS_STRIPE_WHURL; } if ( self::is_rest_api_set() ) { return self::get_webhook_url_for_rest(); } return self::get_webhook_url_for_curl(); } /** * Is Stripe payment enabled for the form. * * @since 1.8.4 * * @param array $form_data Form data. * * @return bool */ public static function is_payments_enabled( $form_data ) { return self::is_modern_settings_enabled( $form_data ) || ! empty( $form_data['payments']['stripe']['enable'] ); } /** * Is Stripe modern payment enabled for the form. * * @since 1.8.4 * * @param array $form_data Form data. * * @return bool */ public static function is_modern_settings_enabled( $form_data ) { return ! empty( $form_data['payments']['stripe']['enable_one_time'] ) || ! empty( $form_data['payments']['stripe']['enable_recurring'] ); } /** * Detect if form supports multiple subscription plans. * * @since 1.8.4 * * @param array $form_data Form data. * * @return bool */ public static function is_form_supports_multiple_recurring_plans( $form_data ) { return ! isset( $form_data['payments']['stripe'] ) || empty( $form_data['payments']['stripe']['recurring']['enable'] ); } /** * Determine if legacy payment settings should be displayed. * * @since 1.8.4 * * @param array $form_data Form data. * * @return bool */ public static function is_legacy_payment_settings( $form_data ) { $has_legacy_settings = ! self::is_form_supports_multiple_recurring_plans( $form_data ); // Return early if form has legacy payment settings. if ( $has_legacy_settings ) { return true; } $addon_compat = ( new StripeAddonCompatibility() )->init(); // Return early if Stripe Pro addon doesn't support modern settings (multiple plans). if ( $addon_compat && ! $addon_compat->is_supported_modern_settings() ) { return true; } return false; } /** * Determine whether the Link is supported. * * @link https://docs.stripe.com/payments/payment-methods/integration-options#payment-method-availability * * @since 1.8.8 * * @return bool */ public static function is_link_supported(): bool { return ! in_array( self::get_account_country(), [ 'br', 'in', 'id', 'th' ], true ); } /** * Get the maximum number of cycles for recurring plans. * * @since 1.9.8 * * @return int */ public static function recurring_plan_cycles_max(): int { /** * Filters the maximum number of cycles for recurring plans. * * @since 1.9.8 * * @param int $max Maximum number of cycles. */ return (int) apply_filters( 'wpforms_stripe_recurring_plan_cycles_max', 100 ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName } /** * Get account country. * * @since 1.8.8 * * @return string */ private static function get_account_country(): string { $mode = self::get_stripe_mode(); return get_option( "wpforms_stripe_{$mode}_account_country", '' ); } /** * Get the WPForms Payments settings page URL. * * @since 1.10.1.1 * * @return string */ public static function get_settings_page_url(): string { return add_query_arg( [ 'page' => 'wpforms-settings', 'view' => 'payments', ], admin_url( 'admin.php' ) ); } }