CRM-19478 handle wierd contribution page id
[civicrm-core.git] / CRM / Utils / Type.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
fa938177 6 | Copyright CiviCRM LLC (c) 2004-2016 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
fa938177 31 * @copyright CiviCRM LLC (c) 2004-2016
6a488035
TO
32 */
33class CRM_Utils_Type {
7da04cde 34 const
353ffa53
TO
35 T_INT = 1,
36 T_STRING = 2,
37 T_ENUM = 2,
38 T_DATE = 4,
39 T_TIME = 8,
40 T_BOOLEAN = 16,
41 T_TEXT = 32,
42 T_LONGTEXT = 32,
43 T_BLOB = 64,
44 T_TIMESTAMP = 256,
45 T_FLOAT = 512,
46 T_MONEY = 1024,
47 T_EMAIL = 2048,
48 T_URL = 4096,
49 T_CCNUM = 8192,
6a488035
TO
50 T_MEDIUMBLOB = 16384;
51
2c05985c
CB
52 // @TODO What's the point of these constants? Backwards compatibility?
53 //
54 // These are used for field size (<input type=text size=2>), but redundant TWO=2
55 // usages are rare and should be eliminated. See CRM-18810.
7da04cde 56 const
353ffa53
TO
57 TWO = 2,
58 FOUR = 4,
59 SIX = 6,
60 EIGHT = 8,
61 TWELVE = 12,
62 SIXTEEN = 16,
63 TWENTY = 20,
64 MEDIUM = 20,
65 THIRTY = 30,
66 BIG = 30,
6a488035 67 FORTYFIVE = 45,
353ffa53 68 HUGE = 45;
6a488035
TO
69
70 /**
a3379cc1 71 * Gets the string representation for a data type.
6a488035 72 *
a3379cc1
AH
73 * @param int $type
74 * Integer number identifying the data type.
6a488035 75 *
a3379cc1
AH
76 * @return string
77 * String identifying the data type, e.g. 'Int' or 'String'.
6a488035 78 */
00be9182 79 public static function typeToString($type) {
d6528d9c
AH
80 // @todo Use constants in the case statements, e.g. "case T_INT:".
81 // @todo return directly, instead of assigning a value.
82 // @todo Use a lookup array, as a property or as a local variable.
6a488035
TO
83 switch ($type) {
84 case 1:
85 $string = 'Int';
86 break;
87
88 case 2:
89 $string = 'String';
90 break;
91
92 case 3:
93 $string = 'Enum';
94 break;
95
96 case 4:
97 $string = 'Date';
98 break;
99
100 case 8:
101 $string = 'Time';
102 break;
103
104 case 16:
105 $string = 'Boolean';
106 break;
107
108 case 32:
109 $string = 'Text';
110 break;
111
112 case 64:
113 $string = 'Blob';
114 break;
115
e7292422 116 // CRM-10404
6a488035
TO
117 case 12:
118 case 256:
119 $string = 'Timestamp';
120 break;
121
122 case 512:
123 $string = 'Float';
124 break;
125
126 case 1024:
127 $string = 'Money';
128 break;
129
130 case 2048:
131 $string = 'Date';
132 break;
133
134 case 4096:
135 $string = 'Email';
136 break;
137
138 case 16384:
139 $string = 'Mediumblob';
140 break;
141 }
142
143 return (isset($string)) ? $string : "";
144 }
145
7c99af4f 146 /**
147 * Helper function to call escape on arrays
148 *
149 * @see escape
150 */
151 public static function escapeAll($data, $type, $abort = TRUE) {
152 foreach ($data as $key => $value) {
153 $data[$key] = CRM_Utils_Type::escape($value, $type, $abort);
154 }
155 return $data;
156 }
157
0fa4baf0
MM
158 /**
159 * Helper function to call validate on arrays
160 *
161 * @see validate
162 */
163 public static function validateAll($data, $type, $abort = TRUE) {
164 foreach ($data as $key => $value) {
165 $data[$key] = CRM_Utils_Type::validate($value, $type, $abort);
166 }
167 return $data;
168 }
169
6a488035 170 /**
a3379cc1 171 * Verify that a variable is of a given type, and apply a bit of processing.
6a488035 172 *
a3379cc1
AH
173 * @param mixed $data
174 * The value to be verified/escaped.
175 * @param string $type
176 * The type to verify against.
77855840 177 * @param bool $abort
a3379cc1 178 * If TRUE, the operation will CRM_Core_Error::fatal() on invalid data.
6a488035 179 *
a3379cc1
AH
180 * @return mixed
181 * The data, escaped if necessary.
6a488035
TO
182 */
183 public static function escape($data, $type, $abort = TRUE) {
184 switch ($type) {
185 case 'Integer':
186 case 'Int':
187 if (CRM_Utils_Rule::integer($data)) {
2b0e7d03 188 return (int) $data;
6a488035
TO
189 }
190 break;
191
192 case 'Positive':
43b6f159
CW
193 if (CRM_Utils_Rule::positiveInteger($data)) {
194 return (int) $data;
195 }
196 break;
197
198 // CRM-8925 for custom fields of this type
6a488035
TO
199 case 'Country':
200 case 'StateProvince':
88ccd161
CW
201 // Handle multivalued data in delimited or array format
202 if (is_array($data) || (strpos($data, CRM_Core_DAO::VALUE_SEPARATOR) !== FALSE)) {
43b6f159 203 $valid = TRUE;
88ccd161 204 foreach (CRM_Utils_Array::explodePadded($data) as $item) {
43b6f159
CW
205 if (!CRM_Utils_Rule::positiveInteger($item)) {
206 $valid = FALSE;
9ff5f6c0
N
207 }
208 }
43b6f159 209 if ($valid) {
9ff5f6c0
N
210 return $data;
211 }
212 }
9ff5f6c0 213 elseif (CRM_Utils_Rule::positiveInteger($data)) {
43b6f159 214 return (int) $data;
6a488035
TO
215 }
216 break;
217
e7dcccf0 218 case 'File':
6a488035 219 if (CRM_Utils_Rule::positiveInteger($data)) {
43b6f159 220 return (int) $data;
6a488035
TO
221 }
222 break;
223
224 case 'Link':
225 if (CRM_Utils_Rule::url($data = trim($data))) {
226 return $data;
227 }
228 break;
229
230 case 'Boolean':
231 if (CRM_Utils_Rule::boolean($data)) {
232 return $data;
233 }
234 break;
235
236 case 'Float':
237 case 'Money':
238 if (CRM_Utils_Rule::numeric($data)) {
239 return $data;
240 }
241 break;
242
243 case 'String':
244 case 'Memo':
85bdc94e 245 case 'Text':
6a488035
TO
246 return CRM_Core_DAO::escapeString($data);
247
248 case 'Date':
249 case 'Timestamp':
250 // a null date or timestamp is valid
251 if (strlen(trim($data)) == 0) {
252 return trim($data);
253 }
254
255 if ((preg_match('/^\d{8}$/', $data) ||
256 preg_match('/^\d{14}$/', $data)
257 ) &&
258 CRM_Utils_Rule::mysqlDate($data)
259 ) {
260 return $data;
261 }
262 break;
263
264 case 'ContactReference':
265 if (strlen(trim($data)) == 0) {
266 return trim($data);
267 }
268
269 if (CRM_Utils_Rule::validContact($data)) {
258570f7 270 return (int) $data;
6a488035
TO
271 }
272 break;
273
f19a5565 274 case 'MysqlColumnNameOrAlias':
a33b83c5
MM
275 if (CRM_Utils_Rule::mysqlColumnNameOrAlias($data)) {
276 $data = str_replace('`', '', $data);
0fa4baf0 277 $parts = explode('.', $data);
da93a1ab 278 $data = '`' . implode('`.`', $parts) . '`';
0fa4baf0 279
00f11506
MM
280 return $data;
281 }
282 break;
283
284 case 'MysqlOrderByDirection':
537e8cb5 285 if (CRM_Utils_Rule::mysqlOrderByDirection($data)) {
0fa4baf0
MM
286 return strtolower($data);
287 }
288 break;
289
290 case 'MysqlOrderBy':
291 if (CRM_Utils_Rule::mysqlOrderBy($data)) {
292 $parts = explode(',', $data);
293 foreach ($parts as &$part) {
dd78a9ad 294 $part = preg_replace_callback('/^(?:(?:((?:`[\w-]{1,64}`|[\w-]{1,64}))(?:\.))?(`[\w-]{1,64}`|[\w-]{1,64})(?: (asc|desc))?)$/i', array('CRM_Utils_Type', 'mysqlOrderByCallback'), trim($part));
0fa4baf0
MM
295 }
296 return implode(', ', $parts);
00f11506
MM
297 }
298 break;
299
6a488035 300 default:
4f1da757
EM
301 CRM_Core_Error::fatal(
302 $type . " is not a recognised (camel cased) data type."
303 );
6a488035
TO
304 break;
305 }
306
d6528d9c 307 // @todo Use exceptions instead of CRM_Core_Error::fatal().
6a488035
TO
308 if ($abort) {
309 $data = htmlentities($data);
310 CRM_Core_Error::fatal("$data is not of the type $type");
311 }
312 return NULL;
313 }
314
315 /**
fe482240 316 * Verify that a variable is of a given type.
6a488035 317 *
a3379cc1
AH
318 * @param mixed $data
319 * The value to validate.
320 * @param string $type
321 * The type to validate against.
77855840 322 * @param bool $abort
a3379cc1
AH
323 * If TRUE, the operation will CRM_Core_Error::fatal() on invalid data.
324 * @name string $name
325 * The name of the attribute
6a488035 326 *
a3379cc1
AH
327 * @return mixed
328 * The data, escaped if necessary
6a488035
TO
329 */
330 public static function validate($data, $type, $abort = TRUE, $name = 'One of parameters ') {
331 switch ($type) {
332 case 'Integer':
333 case 'Int':
334 if (CRM_Utils_Rule::integer($data)) {
2b0e7d03 335 return (int) $data;
6a488035
TO
336 }
337 break;
338
339 case 'Positive':
340 if (CRM_Utils_Rule::positiveInteger($data)) {
258570f7 341 return (int) $data;
6a488035
TO
342 }
343 break;
344
345 case 'Boolean':
346 if (CRM_Utils_Rule::boolean($data)) {
347 return $data;
348 }
349 break;
350
351 case 'Float':
352 case 'Money':
353 if (CRM_Utils_Rule::numeric($data)) {
354 return $data;
355 }
356 break;
357
358 case 'Text':
359 case 'String':
360 case 'Link':
361 case 'Memo':
362 return $data;
363
364 case 'Date':
365 // a null date is valid
366 if (strlen(trim($data)) == 0) {
367 return trim($data);
368 }
369
370 if (preg_match('/^\d{8}$/', $data) &&
371 CRM_Utils_Rule::mysqlDate($data)
372 ) {
373 return $data;
374 }
375 break;
376
377 case 'Timestamp':
378 // a null timestamp is valid
379 if (strlen(trim($data)) == 0) {
380 return trim($data);
381 }
382
383 if ((preg_match('/^\d{14}$/', $data) ||
384 preg_match('/^\d{8}$/', $data)
385 ) &&
386 CRM_Utils_Rule::mysqlDate($data)
387 ) {
388 return $data;
389 }
390 break;
391
392 case 'ContactReference':
393 // null is valid
394 if (strlen(trim($data)) == 0) {
395 return trim($data);
396 }
397
398 if (CRM_Utils_Rule::validContact($data)) {
399 return $data;
400 }
401 break;
402
f19a5565 403 case 'MysqlColumnNameOrAlias':
a33b83c5 404 if (CRM_Utils_Rule::mysqlColumnNameOrAlias($data)) {
5d817a13
MM
405 return $data;
406 }
407 break;
408
409 case 'MysqlOrderByDirection':
410 if (CRM_Utils_Rule::mysqlOrderByDirection($data)) {
0fa4baf0 411 return strtolower($data);
5d817a13
MM
412 }
413 break;
414
415 case 'MysqlOrderBy':
416 if (CRM_Utils_Rule::mysqlOrderBy($data)) {
417 return $data;
418 }
419 break;
420
6a488035
TO
421 default:
422 CRM_Core_Error::fatal("Cannot recognize $type for $data");
423 break;
424 }
425
426 if ($abort) {
427 $data = htmlentities($data);
428 CRM_Core_Error::fatal("$name (value: $data) is not of the type $type");
429 }
430
431 return NULL;
432 }
96025800 433
0fa4baf0
MM
434 /**
435 * preg_replace_callback for MysqlOrderBy escape.
436 */
437 public static function mysqlOrderByCallback($matches) {
438 $output = '';
a33b83c5 439 $matches = str_replace('`', '', $matches);
0fa4baf0 440
a33b83c5 441 // Table name.
f19a5565 442 if (isset($matches[1]) && $matches[1]) {
a33b83c5 443 $output .= '`' . $matches[1] . '`.';
0fa4baf0
MM
444 }
445
a33b83c5 446 // Column name.
0fa4baf0 447 if (isset($matches[2]) && $matches[2]) {
a33b83c5 448 $output .= '`' . $matches[2] . '`';
0fa4baf0
MM
449 }
450
451 // Sort order.
452 if (isset($matches[3]) && $matches[3]) {
453 $output .= ' ' . $matches[3];
454 }
455
456 return $output;
457 }
458
eaecfa20
SL
459 /**
460 * Get list of avaliable Data Tupes for Option Groups
461 *
462 * @return array
463 */
464 public static function dataTypes() {
465 $types = array(
d67d221a 466 'Integer',
eaecfa20 467 'String',
d67d221a
SL
468 'Date',
469 'Time',
eaecfa20 470 'Timestamp',
d67d221a 471 'Money',
eaecfa20
SL
472 'Email',
473 );
474 return array_combine($types, $types);
475 }
476
6a488035 477}