PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.32
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.32
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | classes/models/FrmFormState.php +58 -19 6.36.32 View file →
@@ -13,9 +13,9 @@
13 13 */
14 14 class FrmFormState {
15 15
16 16 /**
17 - * @var FrmFormState $instance
17 + * @var FrmFormState|null
18 18 */
19 19 private static $instance;
20 20
21 21 /**
@@ -29,8 +29,9 @@
29 29
30 30 /**
31 31 * @param string $key
32 32 * @param mixed $value
33 + *
33 34 * @return void
34 35 */
35 36 public static function set_initial_value( $key, $value ) {
36 37 if ( is_callable( 'FrmProFormState::set_initial_value' ) ) {
@@ -45,9 +46,9 @@
45 46 /**
46 47 * @return bool true if just initialized.
47 48 */
48 49 private static function maybe_initialize() {
49 - if ( ! isset( self::$instance ) ) {
50 + if ( ! self::$instance ) {
50 51 self::$instance = new self();
51 52 return true;
52 53 }
53 54 return false;
@@ -55,8 +56,9 @@
55 56
56 57 /**
57 58 * @param string $key
58 59 * @param mixed $value
60 + *
59 61 * @return void
60 62 */
61 63 public function set( $key, $value ) {
62 64 $this->state[ $key ] = $value;
@@ -64,8 +66,9 @@
64 66
65 67 /**
66 68 * @param string $key
67 69 * @param mixed $default
70 + *
68 71 * @return mixed
69 72 */
70 73 public static function get_from_request( $key, $default ) {
71 74 if ( self::maybe_initialize() ) {
@@ -73,13 +76,16 @@
73 76 }
74 77 return self::$instance->get( $key, $default );
75 78 }
76 79
80 + /**
81 + * @param string $key
82 + * @param mixed $default
83 + *
84 + * @return mixed
85 + */
77 86 public function get( $key, $default ) {
78 - if ( isset( $this->state[ $key ] ) ) {
79 - return $this->state[ $key ];
80 - }
81 - return $default;
87 + return $this->state[ $key ] ?? $default;
82 88 }
83 89
84 90 /**
85 91 * Render a basic version of the state field from Pro.
@@ -86,8 +92,9 @@
86 92 * This is required only when submitting with AJAX.
87 93 * It is used to track the value of a title=1|0 or description=1|0 option in a [formidable] shortcode.
88 94 *
89 95 * @param stdClass $form
96 + *
90 97 * @return void
91 98 */
92 99 public static function maybe_render_state_field( $form ) {
93 100 if ( is_callable( 'FrmProFormState::maybe_render_state_field' ) ) {
@@ -95,14 +102,16 @@
95 102 // This way we can also avoid duplicate state fields if Pro isn't up to date.
96 103 return;
97 104 }
98 105
99 - if ( empty( $form->options['ajax_submit'] ) ) {
100 - // This is only required for AJAX submit.
106 + if ( ! self::$instance && ! self::get_state_from_request() ) {
101 107 return;
102 108 }
103 109
104 - if ( empty( self::$instance ) && ! self::get_state_from_request() ) {
110 + $honeypot_field_id = self::$instance->get( 'honeypot_field_id', 0 );
111 +
112 + if ( empty( $form->options['ajax_submit'] ) && ! $honeypot_field_id ) {
113 + // This is only required for AJAX submit, or when the honeypot field is on the page.
105 114 return;
106 115 }
107 116
108 117 $state_title = ! empty( self::$instance->state['title'] ) ? 1 : 0;
@@ -109,10 +118,10 @@
109 118 $state_description = ! empty( self::$instance->state['description'] ) ? 1 : 0;
110 119 $settings_title = ! empty( $form->options['show_title'] ) ? 1 : 0;
111 120 $settings_description = ! empty( $form->options['show_description'] ) ? 1 : 0;
112 121
113 - if ( $state_title === $settings_title && $state_description === $settings_description ) {
114 - // Avoid state field if it matches form settings.
122 + if ( $state_title === $settings_title && $state_description === $settings_description && ! $honeypot_field_id ) {
123 + // Avoid state field if it matches form settings and there is no honeypot.
115 124 return;
116 125 }
117 126
118 127 self::$instance->render_state_field();
@@ -122,23 +131,30 @@
122 131 * @return bool true if there is valid state data in the request.
123 132 */
124 133 private static function get_state_from_request() {
125 134 $encrypted_state = FrmAppHelper::get_post_param( 'frm_state', '', 'sanitize_text_field' );
135 +
126 136 if ( ! $encrypted_state ) {
127 137 return false;
128 138 }
139 +
129 140 $secret = self::get_encryption_secret();
130 141 $decrypted_state = openssl_decrypt( $encrypted_state, 'AES-128-ECB', $secret );
142 +
131 143 if ( false === $decrypted_state ) {
132 144 return false;
133 145 }
146 +
134 147 $decoded_state = json_decode( $decrypted_state, true );
148 +
135 149 if ( ! is_array( $decoded_state ) ) {
136 150 return false;
137 151 }
152 +
138 153 foreach ( $decoded_state as $key => $value ) {
139 154 self::set_initial_value( self::decompressed_key( $key ), $value );
140 155 }
156 +
141 157 return true;
142 158 }
143 159
144 160 /**
@@ -144,13 +160,17 @@
144 160 /**
145 161 * @return void
146 162 */
147 163 public function render_state_field() {
164 + if ( ! self::open_ssl_is_installed() ) {
165 + return;
166 + }
167 +
148 168 if ( ! $this->state && ! self::get_state_from_request() ) {
149 169 return;
150 170 }
151 - $state_string = $this->get_state_string();
152 - echo '<input name="frm_state" type="hidden" value="' . esc_attr( $state_string ) . '" />';
171 +
172 + echo '<input name="frm_state" type="hidden" value="' . esc_attr( $this->get_state_string() ) . '" />';
153 173 }
154 174
155 175 /**
156 176 * @return string
@@ -155,16 +175,29 @@
155 175 /**
156 176 * @return string
157 177 */
158 178 private function get_state_string() {
159 - $secret = self::get_encryption_secret();
160 - $compressed_state = $this->compressed_state();
161 - $json_encoded = json_encode( $compressed_state );
162 - $encrypted = openssl_encrypt( $json_encoded, 'AES-128-ECB', $secret );
163 - return $encrypted;
179 + if ( ! self::open_ssl_is_installed() ) {
180 + return '';
181 + }
182 +
183 + $secret = self::get_encryption_secret();
184 + $json_encoded = json_encode( $this->compressed_state() );
185 + return openssl_encrypt( $json_encoded, 'AES-128-ECB', $secret );
164 186 }
165 187
166 188 /**
189 + * Returns true if open SSL is installed.
190 + *
191 + * @since 6.12
192 + *
193 + * @return bool
194 + */
195 + private static function open_ssl_is_installed() {
196 + return function_exists( 'openssl_encrypt' );
197 + }
198 +
199 + /**
167 200 * Return state but with shorter keys to use for the state string.
168 201 *
169 202 * @return array
170 203 */
@@ -169,11 +202,13 @@
169 202 * @return array
170 203 */
171 204 private function compressed_state() {
172 205 $compressed = array();
206 +
173 207 foreach ( $this->state as $key => $value ) {
174 208 $compressed[ self::compressed_key( $key ) ] = $value;
175 209 }
210 +
176 211 return $compressed;
177 212 }
178 213
179 214 /**
@@ -181,8 +216,9 @@
181 216 * "title" => "t".
182 217 * "description" => "d".
183 218 *
184 219 * @param string $key
220 + *
185 221 * @return string
186 222 */
187 223 private static function compressed_key( $key ) {
188 224 return $key[0];
@@ -193,8 +229,9 @@
193 229 * Pro supports additional keys include "i" for include_fields and "g" for get params.
194 230 * To avoid conflicts, we should not add "i" or "g" in Lite for another state property.
195 231 *
196 232 * @param string $key
233 + *
197 234 * @return string The full key name if one is found. If nothing is found, the $key param is passed back.
198 235 */
199 236 private static function decompressed_key( $key ) {
200 237 switch ( $key ) {
@@ -201,8 +238,10 @@
201 238 case 'd':
202 239 return 'description';
203 240 case 't':
204 241 return 'title';
242 + case 'h':
243 + return 'honeypot_field_id';
205 244 }
206 245 return $key;
207 246 }
208 247
@@ -218,9 +257,9 @@
218 257 }
219 258
220 259 // We don't have a secret, so let's generate one.
221 260 $secret_key = is_callable( 'sodium_crypto_secretbox_keygen' ) ? sodium_crypto_secretbox_keygen() : wp_generate_password( 32, true, true );
222 - add_option( 'frm_form_state_key', base64_encode( $secret_key ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
261 + update_option( 'frm_form_state_key', base64_encode( $secret_key ), false ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
223 262
224 263 return $secret_key;
225 264 }
226 265 }