PluginProbe
The Innovative Form Builder – IvyForms / 0.1.2
The Innovative Form Builder – IvyForms v0.1.2
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / backend / src / Common / Sanitizer / Sanitizer.php

Sanitizer.php in The Innovative Form Builder – IvyForms 0.1.2, at backend/src/Common/Sanitizer/Sanitizer.php

296 lines 9.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * @copyright © TMS-Plugins. All rights reserved.
5 * @licence See COPYING.md for license details.
6 */
7
8 namespace IvyForms\Common\Sanitizer;
9
10 // phpcs:disable PSR1.Files.SideEffects
11 if (!defined('ABSPATH')) {
12 exit; // Exit if accessed directly
13 }
14
15 use IvyForms\Common\Exceptions\ForbiddenException;
16 use IvyForms\Common\Exceptions\InvalidArgumentException;
17 use IvyForms\Services\Field\FieldType;
18
19 class Sanitizer
20 {
21 /**
22 * Sanitize all form data
23 *
24 * @param mixed[] $data
25 *
26 * @return mixed[]
27 */
28 public static function sanitizeFormData(array $data): array
29 {
30
31 return [
32 'id' => (int)($data['id'] ?? 0),
33 'name' => sanitize_text_field($data['name'] ?? ''),
34 'description' => sanitize_text_field($data['description'] ?? ''),
35 'showTitle' => (bool)($data['showTitle'] ?? false),
36 'published' => (bool)($data['published'] ?? false),
37 'showDescription' => (bool)($data['showDescription'] ?? false),
38 'fields' => self::sanitizeFields($data['fields'] ?? []),
39 ];
40 }
41 /**
42 * Sanitize all notification data
43 *
44 * @param mixed[] $data
45 *
46 * @return mixed[]
47 */
48 public static function sanitizeNotificationData(array $data): array
49 {
50 return [
51 'id' => (int)($data['id'] ?? 0),
52 'name' => sanitize_text_field($data['name'] ?? ''),
53 'sender' => sanitize_email($data['sender'] ?? ''),
54 'receiver' => sanitize_email($data['receiver'] ?? ''),
55 'status' => (bool)($data['status'] ?? false),
56 'subject' => sanitize_text_field($data['subject'] ?? ''),
57 'message' => sanitize_textarea_field($data['message'] ?? ''),
58 'smartLogic' => (bool)($data['smartLogic'] ?? false),
59 'formId' => (int)($data['formId'] ?? 0),
60 ];
61 }
62 /**
63 * Sanitize all confirmation data
64 *
65 * @param mixed[] $data
66 *
67 * @return mixed[]
68 */
69 public static function sanitizeConfirmationData(array $data): array
70 {
71 return [
72 'id' => (int)($data['id'] ?? 0),
73 'formId' => (int)($data['formId'] ?? 0),
74 'type' => sanitize_text_field($data['type'] ?? ''),
75 'status' => (bool)($data['status'] ?? false),
76 'showForm' => (bool)($data['showForm'] ?? false),
77 'message' => sanitize_textarea_field($data['message'] ?? ''),
78 'url' => sanitize_url(isset($data['url']) ? urldecode($data['url']) : ''),
79 'page' => sanitize_text_field($data['page'] ?? ''),
80 ];
81 }
82 /**
83 * Sanitize form fields
84 *
85 * @param mixed[] $fields
86 *
87 * @return mixed[]
88 */
89 private static function sanitizeFields(array $fields): array
90 {
91 return array_map(function ($field) {
92 $fieldType = FieldType::sanitize($field['type'] ?? '');
93 return [
94 'id' => (int)($field['id'] ?? 0),
95 'fieldIndex' => (int)($field['fieldIndex'] ?? 0),
96 'type' => sanitize_text_field($fieldType),
97 'label' => sanitize_text_field($field['label'] ?? ''),
98 'required' => (bool)($field['required'] ?? false),
99 'defaultValue' => sanitize_text_field($field['defaultValue'] ?? ''),
100 'placeholder' => sanitize_text_field($field['placeholder'] ?? ''),
101 'position' => (int)($field['position'] ?? 0)
102 ];
103 }, $fields);
104 }
105
106 /**
107 * Sanitize form/notification ID
108 *
109 * @param int $id
110 *
111 * @return int
112 *
113 * @throws InvalidArgumentException
114 */
115 public static function sanitizeId(int $id): int
116 {
117 if ($id <= 0) {
118 throw new InvalidArgumentException('Invalid form ID.');
119 }
120
121 return $id;
122 }
123
124 /**
125 * Sanitize form/notification IDs
126 *
127 * @param int[] $ids
128 *
129 * @return int[]
130 *
131 * @throws InvalidArgumentException
132 */
133 public static function sanitizeIds(array $ids): array
134 {
135 return array_map(function ($id) {
136 return (int)$id;
137 }, $ids);
138 }
139
140 /**
141 * Sanitize search parameters
142 *
143 * @param array<string, mixed> $params
144 *
145 * @return array<string, mixed>
146 */
147 public static function sanitizeSearchParams(array $params): array
148 {
149 return [
150 'page' => max((int)($params['page'] ?? 1), 1),
151 'perPage' => max((int)($params['perPage'] ?? 10), 1),
152 'search' => sanitize_text_field($params['search'] ?? ''),
153 'orderBy' => sanitize_text_field($params['orderBy'] ?? 'id'),
154 'order' => strtolower(sanitize_text_field($params['order'] ?? 'asc')) === 'desc' ? 'desc' : 'asc',
155 'filters' => [
156 'starred' => array_key_exists('starred', $params['filters'] ?? [])
157 ? (int)filter_var($params['filters']['starred'], FILTER_VALIDATE_BOOLEAN)
158 : null,
159 'published' => array_key_exists('published', $params['filters'] ?? [])
160 ? (int)filter_var($params['filters']['published'], FILTER_VALIDATE_BOOLEAN)
161 : null,
162 ],
163 'dateRange' => [
164 sanitize_text_field($params['dateRange'][0] ?? ''),
165 sanitize_text_field($params['dateRange'][1] ?? ''),
166 ],
167 ];
168 }
169
170 /**
171 * Sanitize form submission data based on field types
172 *
173 * @param mixed[] $data Form submission data
174 * @param mixed[] $formFields Form fields configuration
175 *
176 * @return mixed[] Sanitized submission data
177 */
178 public static function sanitizeFormSubmissionData(array $data, array $formFields): array
179 {
180 $sanitizedData = [];
181 $fieldMaps = self::buildFieldMaps($formFields);
182 $fieldLabelMap = $fieldMaps['labels'];
183 $fieldTypeMap = $fieldMaps['types'];
184
185 // Sanitize each form field based on its type
186 foreach ($data['values'] as $keyIndex => $value) {
187 // Skip WordPress internal fields
188 if (in_array($keyIndex, ['nonce', 'formId'])) {
189 $sanitizedData[$keyIndex] = $value;
190 continue;
191 }
192
193 $fieldType = $fieldTypeMap[$keyIndex] ?? '';
194 $fieldLabel = $fieldLabelMap[$keyIndex] ?? '';
195
196 $sanitizedData[$fieldLabel] = self::sanitizeByFieldType($fieldType, $value);
197 }
198
199 // Add form ID to sanitized data if present
200 if (isset($data['formId'])) {
201 $sanitizedData['formId'] = (int)$data['formId'];
202 }
203
204 return $sanitizedData;
205 }
206
207 /**
208 * Build field mapping arrays for labels and types
209 *
210 * @param mixed[] $formFields
211 *
212 * @return array<string, array<string, string>> Associative array with 'labels' and 'types' mappings
213 */
214 private static function buildFieldMaps(array $formFields): array
215 {
216 $fieldLabelMap = [];
217 $fieldTypeMap = [];
218
219 foreach ($formFields as $field) {
220 $fieldName = $field->getLabel() ?? '';
221 $key = $field->getType() . "_" . $field->getIndex();
222 $fieldLabelMap[$key] = $fieldName;
223 $fieldTypeMap[$key] = $field->getType() ?? '';
224 }
225
226 return [
227 'labels' => $fieldLabelMap,
228 'types' => $fieldTypeMap
229 ];
230 }
231
232 /**
233 * Sanitize a value based on its field type
234 *
235 * @param string $fieldType The type of field
236 * @param mixed $value The value to sanitize
237 *
238 * @return mixed Sanitized value
239 */
240 private static function sanitizeByFieldType(string $fieldType, $value)
241 {
242 switch ($fieldType) {
243 case 'email':
244 return sanitize_email($value);
245
246 case 'number':
247 return is_numeric($value) ? intval($value) : 0;
248
249 case 'phone':
250 // Remove everything except digits, +, and spaces
251 return preg_replace('/[^\d\s+]/', '', $value);
252
253 case 'paragraph':
254 return sanitize_textarea_field($value);
255
256 case 'text':
257 default:
258 // Default to text field sanitization
259 return sanitize_text_field($value);
260 }
261 }
262
263 /**
264 * Verify nonce with custom error handling
265 *
266 * @param string|null $nonce
267 *
268 * @throws ForbiddenException
269 */
270 public static function verifyNonce(?string $nonce): void
271 {
272 $nonce = sanitize_text_field($nonce);
273
274 if (!$nonce || !wp_verify_nonce($nonce, 'wp_rest')) {
275 throw new ForbiddenException('Invalid nonce.');
276 }
277 }
278 /**
279 * Verify submission nonce with custom error handling
280 *
281 * @param string|null $nonce
282 * @param int $formId
283 *
284 * @throws ForbiddenException
285 */
286 public static function verifySubmissionNonce(?string $nonce, int $formId): void
287 {
288 $nonce = sanitize_text_field($nonce);
289
290 // Verify the form-specific nonce
291 if (!wp_verify_nonce($nonce, 'ivyformsFrontSubmissionNonce_' . $formId)) {
292 throw new ForbiddenException('Invalid security token.');
293 }
294 }
295 }
296