PluginProbe
HTML Forms – Simple WordPress Forms Plugin / 1.1.4
HTML Forms – Simple WordPress Forms Plugin v1.1.4
1.7.0 trunk 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0 1.3.0 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 All 67 releases
html-forms / src / Forms.php

Forms.php in HTML Forms – Simple WordPress Forms Plugin 1.1.4, at src/Forms.php

363 lines 11.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace HTML_Forms;
4
5 class Forms
6 {
7
8 /**
9 * @var string
10 */
11 private $plugin_file;
12
13 /**
14 * @var array
15 */
16 private $settings;
17
18 /**
19 * Forms constructor.
20 *
21 * @param string $plugin_file
22 * @param array $settings
23 */
24 public function __construct($plugin_file, array $settings )
25 {
26 $this->plugin_file = $plugin_file;
27 $this->settings = $settings;
28 }
29
30 public function hook()
31 {
32 add_action('init', array($this, 'register'));
33 add_action('init', array($this, 'listen_for_submit') );
34 add_action('parse_request', array($this, 'listen_for_preview'));
35 add_action('wp_enqueue_scripts', array($this, 'assets'));
36 add_filter('hf_form_markup', 'hf_template');
37 }
38
39 public function register()
40 {
41 // register post type
42 register_post_type('html-form', array(
43 'labels' => array(
44 'name' => 'HTML Forms',
45 'singular_name' => 'HTML Form',
46 ),
47 'public' => false,
48 'capability_type' => 'form',
49 )
50 );
51
52 add_shortcode('hf_form', array($this, 'shortcode'));
53
54 // enable shortcodes in text widgets
55 add_filter( 'widget_text', 'shortcode_unautop' );
56 add_filter( 'widget_text', 'do_shortcode', 11 );
57 }
58
59 public function assets()
60 {
61 $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
62 $assets_url = plugins_url( 'assets/', $this->plugin_file );
63
64 wp_register_script('html-forms', $assets_url . "js/public{$suffix}.js", array(), HTML_FORMS_VERSION, true);
65 wp_localize_script('html-forms', 'hf_js_vars', array(
66 'ajax_url' => admin_url('admin-ajax.php'),
67 ));
68
69 if( $this->settings['load_stylesheet'] ) {
70 wp_enqueue_style( 'html-forms', $assets_url . "css/forms{$suffix}.css", array(), HTML_FORMS_VERSION );
71 }
72 }
73
74 /**
75 * @param Form $form
76 * @param array $data
77 * @return string
78 */
79 public function validate_form(Form $form, array $data)
80 {
81 // validate honeypot field
82 $honeypot_key = sprintf( '_hf_h%d', $form->ID );
83 if( ! isset( $data[$honeypot_key] ) || $data[$honeypot_key] !== "" ) {
84 return 'spam';
85 }
86
87 // validate size of POST array
88 if( count($data) > $form->get_field_count() && apply_filters( 'hf_validate_form_request_size', true ) ) {
89 return 'spam';
90 }
91
92 $required_fields = $form->get_required_fields();
93 foreach ($required_fields as $field_name) {
94 $value = hf_array_get( $data, $field_name );
95 if ( empty( $value ) ) {
96 return 'required_field_missing';
97 }
98 }
99
100 $email_fields = $form->get_email_fields();
101 foreach ($email_fields as $field_name) {
102 $value = hf_array_get( $data, $field_name );
103 if ( ! empty( $value ) && ! is_email( $value ) ) {
104 return 'invalid_email';
105 }
106 }
107
108 $error_code = '';
109
110 /**
111 * This filter allows you to perform your own form validation. The dynamic portion of the hook refers to the form slug.
112 *
113 * Return a non-empty string if you want to raise an error.
114 * Error codes with a specific error message are: "required_field_missing", "invalid_email", and "error"
115 *
116 * @param string $error_code
117 * @param Form $form
118 * @param array $data
119 */
120 $error_code = apply_filters( 'hf_validate_form_' . $form->slug, $error_code, $form, $data );
121
122 /**
123 * This filter allows you to perform your own form validation.
124 *
125 * Return a non-empty string if you want to raise an error.
126 * Error codes with a specific error message are: "required_field_missing", "invalid_email", and "error"
127 *
128 * @param string $error_code
129 * @param Form $form
130 * @param array $data
131 */
132 $error_code = apply_filters( 'hf_validate_form', $error_code, $form, $data );
133 if( ! empty( $error_code ) ) {
134 return $error_code;
135 }
136
137 // all good: no errors!
138 return '';
139 }
140
141 /**
142 * Sanitize array with values before saving. Can be called recursively.
143 *
144 * @param mixed $value
145 */
146 public function sanitize( $value )
147 {
148 if (is_string($value)) {
149 // strip all HTML tags & whitespace
150 $value = trim(strip_tags($value));
151
152 // convert &amp; back to &
153 $value = html_entity_decode($value, ENT_NOQUOTES);
154 } elseif ( is_array($value) || is_object($value) ) {
155 $new_value = array();
156 $vars = is_array( $value ) ? $value : get_object_vars( $value );
157
158 foreach($vars as $key => $sub_value) {
159 // skip empty values
160 if(empty($sub_value)) {
161 continue;
162 }
163
164 // sanitize key
165 $key = trim(strip_tags($key));
166
167 // sanitize sub value
168 $new_value[$key] = $this->sanitize($sub_value);
169 }
170 $value = is_object( $value ) ? (object) $new_value : $new_value;
171 }
172
173 return $value;
174 }
175
176 public function listen_for_submit()
177 {
178
179 // only respond to AJAX requests with _hf_form_id set.
180 if (empty($_POST['_hf_form_id'])
181 || empty( $_SERVER['HTTP_X_REQUESTED_WITH'] )
182 || strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) !== strtolower( 'XMLHttpRequest' ) ) {
183 return;
184 }
185
186 $data = $_POST;
187 $form_id = (int) $data['_hf_form_id'];
188 $form = hf_get_form($form_id);
189 $error_code = $this->validate_form($form, $data);
190
191 if (empty( $error_code ) ) {
192
193 /**
194 * Filters the field names that should be ignored on the Submission object.
195 * Fields starting with an underscore (_) are ignored by default.
196 *
197 * @param array $names
198 */
199 $ignored_field_names = apply_filters( 'hf_ignored_field_names', array() );
200
201 // filter out ignored field names
202 foreach( $data as $key => $value ) {
203 if( $key[0] === '_' || in_array( $key, $ignored_field_names ) ) {
204 unset( $data[$key] );
205 }
206 }
207
208 // strip slashes
209 $data = stripslashes_deep( $data );
210
211 // sanitize data: strip tags etc.
212 $data = $this->sanitize( $data );
213
214 // save form submission
215 $submission = new Submission();
216 $submission->form_id = $form_id;
217 $submission->data = $data;
218 $submission->ip_address = ! empty( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : '';
219 $submission->user_agent = ! empty( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] ) : '';
220 $submission->referer_url = ! empty( $_SERVER['HTTP_REFERER'] ) ? sanitize_text_field( $_SERVER['HTTP_REFERER'] ) : '';
221 $submission->submitted_at = gmdate( 'Y-m-d H:i:s' );
222
223 if( $this->settings['save_submissions'] ) {
224 $submission->save();
225 }
226
227 // process form actions
228 if ( isset( $form->settings['actions'] ) ) {
229 foreach( $form->settings['actions'] as $action_settings ) {
230 /**
231 * Processes the specified form action and passes related data.
232 *
233 * @param array $action_settings
234 * @param Submission $submission
235 * @param Form $form
236 */
237 do_action('hf_process_form_action_' . $action_settings['type'], $action_settings, $submission, $form );
238 }
239 }
240
241 /**
242 * General purpose hook after all form actions have been processed for this specific form. The dynamic portion of the hook refers to the form slug.
243 *
244 * @param Submission $submission
245 * @param Form $form
246 */
247 do_action( "hf_form_{$form->slug}_success", $submission, $form );
248
249 /**
250 * General purpose hook after all form actions have been processed.
251 *
252 * @param Submission $submission
253 * @param Form $form
254 */
255 do_action( 'hf_form_success', $submission, $form );
256 } else {
257 /**
258 * General purpose hook for when a form error occurred
259 *
260 * @param string $error_code
261 * @param Form $form
262 * @param array $data
263 */
264 do_action( 'hf_form_error', $error_code, $form, $data );
265 }
266
267 // Delay response until "wp_loaded" hook to give other plugins a chance to process stuff.
268 add_action( 'wp_loaded', function() use($error_code, $form) {
269 $response = $this->get_response_for_error_code( $error_code, $form );
270
271 // clear output, some plugin or hooked code might have thrown errors by now.
272 if( ob_get_level() > 0 ) {
273 ob_end_clean();
274 }
275
276 send_origin_headers();
277 send_nosniff_header();
278 nocache_headers();
279
280 wp_send_json($response, 200);
281 exit;
282 });
283 }
284
285 public function listen_for_preview() {
286 if( empty( $_GET['hf_preview_form'] ) || ! current_user_can( 'edit_forms' ) ) {
287 return;
288 }
289
290 try {
291 $form = hf_get_form( $_GET['hf_preview_form'] );
292 } catch( \Exception $e ) {
293 return;
294 }
295
296 show_admin_bar(false);
297 add_filter( 'pre_handle_404', '__return_true' );
298 remove_all_actions( 'template_redirect' );
299 add_action( 'template_redirect', function() use($form) {
300 // clear output, some plugin or hooked code might have thrown errors by now.
301 if( ob_get_level() > 0 ) {
302 ob_end_clean();
303 }
304
305 http_response_code(200);
306 require dirname( $this->plugin_file ) . '/views/form-preview.php';
307 exit;
308 });
309 }
310
311 private function get_response_for_error_code( $error_code, Form $form )
312 {
313 // return success response for empty error code string or spam (to trick bots)
314 if( $error_code === "" || $error_code === "spam" ) {
315 $response = array(
316 'message' => array(
317 'type' => 'success',
318 'text' => $form->get_message( 'success' ),
319 ),
320 'hide_form' => (bool)$form->settings['hide_after_success'],
321 );
322
323 if (!empty($form->settings['redirect_url'])) {
324 $response['redirect_url'] = $form->settings['redirect_url'];
325 }
326
327 return $response;
328 }
329
330 // get error message
331 $message = $form->get_message( $error_code );
332 if( empty( $message ) ) {
333 $message = $form->get_message( 'error' );
334 }
335
336 // return error response
337 return $response = array(
338 'message' => array(
339 'type' => 'warning',
340 'text' => $message,
341 ),
342 'error' => $error_code,
343 );
344 }
345
346 public function shortcode($attributes = array(), $content = '')
347 {
348 $slug_or_id = empty( $attributes['id'] ) ? $attributes['slug'] : $attributes['id'];
349
350 try {
351 $form = hf_get_form( $slug_or_id );
352 } catch( \Exception $e ) {
353 if ( ! current_user_can( 'manage_options' ) ) {
354 return $content;
355 }
356
357 return sprintf( '<p><strong>%s</strong> %s</p>', __( 'Error:', 'html-forms' ), sprintf( __( 'No form found with slug %s', 'html-forms' ), $attributes['slug'] ) );
358 }
359
360 return $form . $content;
361 }
362 }
363