PluginProbe
HTML Forms – Simple WordPress Forms Plugin / 1.1
HTML Forms – Simple WordPress Forms Plugin v1.1
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, at src/Forms.php

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