PluginProbe
HTML Forms – Simple WordPress Forms Plugin / 1.1.2
HTML Forms – Simple WordPress Forms Plugin v1.1.2
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 1.3.17 All 66 releases
html-forms / src / Forms.php

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

360 lines 11.8 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_enqueue_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 // only respond to AJAX requests with _hf_form_id set.
179 if (empty($_POST['_hf_form_id'])
180 || empty( $_SERVER['HTTP_X_REQUESTED_WITH'] )
181 || strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) !== strtolower( 'XMLHttpRequest' ) ) {
182 return;
183 }
184
185 $data = $_POST;
186 $form_id = (int) $data['_hf_form_id'];
187 $form = hf_get_form($form_id);
188 $error_code = $this->validate_form($form, $data);
189
190 if (empty( $error_code ) ) {
191
192 /**
193 * Filters the field names that should be ignored on the Submission object.
194 * Fields starting with an underscore (_) are ignored by default.
195 *
196 * @param array $names
197 */
198 $ignored_field_names = apply_filters( 'hf_ignored_field_names', array() );
199
200 // filter out ignored field names
201 foreach( $data as $key => $value ) {
202 if( $key[0] === '_' || in_array( $key, $ignored_field_names ) ) {
203 unset( $data[$key] );
204 }
205 }
206
207 // strip slashes
208 $data = stripslashes_deep( $data );
209
210 // sanitize data: strip tags etc.
211 $data = $this->sanitize( $data );
212
213 // save form submission
214 $submission = new Submission();
215 $submission->form_id = $form_id;
216 $submission->data = $data;
217 $submission->ip_address = ! empty( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : '';
218 $submission->user_agent = ! empty( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] ) : '';
219 $submission->referer_url = ! empty( $_SERVER['HTTP_REFERER'] ) ? sanitize_text_field( $_SERVER['HTTP_REFERER'] ) : '';
220
221 if( $this->settings['save_submissions'] ) {
222 $submission->save();
223 }
224
225 // process form actions
226 if ( isset( $form->settings['actions'] ) ) {
227 foreach( $form->settings['actions'] as $action_settings ) {
228 /**
229 * Processes the specified form action and passes related data.
230 *
231 * @param array $action_settings
232 * @param Submission $submission
233 * @param Form $form
234 */
235 do_action('hf_process_form_action_' . $action_settings['type'], $action_settings, $submission, $form );
236 }
237 }
238
239 /**
240 * 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.
241 *
242 * @param Submission $submission
243 * @param Form $form
244 */
245 do_action( "hf_form_{$form->slug}_success", $submission, $form );
246
247 /**
248 * General purpose hook after all form actions have been processed.
249 *
250 * @param Submission $submission
251 * @param Form $form
252 */
253 do_action( 'hf_form_success', $submission, $form );
254 } else {
255 /**
256 * General purpose hook for when a form error occurred
257 *
258 * @param string $error_code
259 * @param Form $form
260 * @param array $data
261 */
262 do_action( 'hf_form_error', $error_code, $form, $data );
263 }
264
265 // Delay response until "wp_loaded" hook to give other plugins a chance to process stuff.
266 add_action( 'wp_loaded', function() use($error_code, $form) {
267 $response = $this->get_response_for_error_code( $error_code, $form );
268
269 // clear output, some plugin or hooked code might have thrown errors by now.
270 if( ob_get_level() > 0 ) {
271 ob_end_clean();
272 }
273
274 send_origin_headers();
275 send_nosniff_header();
276 nocache_headers();
277
278 wp_send_json($response, 200);
279 exit;
280 });
281 }
282
283 public function listen_for_preview() {
284 if( empty( $_GET['hf_preview_form'] ) || ! current_user_can( 'edit_forms' ) ) {
285 return;
286 }
287
288 try {
289 $form = hf_get_form( $_GET['hf_preview_form'] );
290 } catch( \Exception $e ) {
291 return;
292 }
293
294 show_admin_bar(false);
295 add_filter( 'pre_handle_404', '__return_true' );
296 add_action( 'template_redirect', function() use($form) {
297 // clear output, some plugin or hooked code might have thrown errors by now.
298 if( ob_get_level() > 0 ) {
299 ob_end_clean();
300 }
301
302 http_response_code(200);
303 require dirname( $this->plugin_file ) . '/views/form-preview.php';
304 exit;
305 });
306 }
307
308 private function get_response_for_error_code( $error_code, Form $form )
309 {
310 // return success response for empty error code string or spam (to trick bots)
311 if( $error_code === "" || $error_code === "spam" ) {
312 $response = array(
313 'message' => array(
314 'type' => 'success',
315 'text' => $form->get_message( 'success' ),
316 ),
317 'hide_form' => (bool)$form->settings['hide_after_success'],
318 );
319
320 if (!empty($form->settings['redirect_url'])) {
321 $response['redirect_url'] = $form->settings['redirect_url'];
322 }
323
324 return $response;
325 }
326
327 // get error message
328 $message = $form->get_message( $error_code );
329 if( empty( $message ) ) {
330 $message = $form->get_message( 'error' );
331 }
332
333 // return error response
334 return $response = array(
335 'message' => array(
336 'type' => 'warning',
337 'text' => $message,
338 ),
339 'error' => $error_code,
340 );
341 }
342
343 public function shortcode($attributes = array(), $content = '')
344 {
345 $slug_or_id = empty( $attributes['id'] ) ? $attributes['slug'] : $attributes['id'];
346
347 try {
348 $form = hf_get_form( $slug_or_id );
349 } catch( \Exception $e ) {
350 if ( ! current_user_can( 'manage_options' ) ) {
351 return $content;
352 }
353
354 return sprintf( '<p><strong>%s</strong> %s</p>', __( 'Error:', 'html-forms' ), sprintf( __( 'No form found with slug %s', 'html-forms' ), $attributes['slug'] ) );
355 }
356
357 return $form . $content;
358 }
359 }
360