Merge pull request #4831 from williamtheaker/master
[civicrm-core.git] / CRM / Utils / Type.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
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 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2014
32 * $Id: $
33 *
34 */
35 class CRM_Utils_Type {
36 const
37 T_INT = 1,
38 T_STRING = 2,
39 T_ENUM = 2,
40 T_DATE = 4,
41 T_TIME = 8,
42 T_BOOLEAN = 16,
43 T_TEXT = 32,
44 T_LONGTEXT = 32,
45 T_BLOB = 64,
46 T_TIMESTAMP = 256,
47 T_FLOAT = 512,
48 T_MONEY = 1024,
49 T_EMAIL = 2048,
50 T_URL = 4096,
51 T_CCNUM = 8192,
52 T_MEDIUMBLOB = 16384;
53
54 // @todo What's the point of these constants? Backwards compatibility?
55 const
56 TWO = 2,
57 FOUR = 4,
58 SIX = 6,
59 EIGHT = 8,
60 TWELVE = 12,
61 SIXTEEN = 16,
62 TWENTY = 20,
63 MEDIUM = 20,
64 THIRTY = 30,
65 BIG = 30,
66 FORTYFIVE = 45,
67 HUGE = 45;
68
69 /**
70 * Gets the string representation for a data type.
71 *
72 * @param int $type
73 * Integer number identifying the data type.
74 *
75 * @return string
76 * String identifying the data type, e.g. 'Int' or 'String'.
77 */
78 public static function typeToString($type) {
79 // @todo Use constants in the case statements, e.g. "case T_INT:".
80 // @todo return directly, instead of assigning a value.
81 // @todo Use a lookup array, as a property or as a local variable.
82 switch ($type) {
83 case 1:
84 $string = 'Int';
85 break;
86
87 case 2:
88 $string = 'String';
89 break;
90
91 case 3:
92 $string = 'Enum';
93 break;
94
95 case 4:
96 $string = 'Date';
97 break;
98
99 case 8:
100 $string = 'Time';
101 break;
102
103 case 16:
104 $string = 'Boolean';
105 break;
106
107 case 32:
108 $string = 'Text';
109 break;
110
111 case 64:
112 $string = 'Blob';
113 break;
114
115 // CRM-10404
116 case 12:
117 case 256:
118 $string = 'Timestamp';
119 break;
120
121 case 512:
122 $string = 'Float';
123 break;
124
125 case 1024:
126 $string = 'Money';
127 break;
128
129 case 2048:
130 $string = 'Date';
131 break;
132
133 case 4096:
134 $string = 'Email';
135 break;
136
137 case 16384:
138 $string = 'Mediumblob';
139 break;
140 }
141
142 return (isset($string)) ? $string : "";
143 }
144
145 /**
146 * Verify that a variable is of a given type, and apply a bit of processing.
147 *
148 * @param mixed $data
149 * The value to be verified/escaped.
150 * @param string $type
151 * The type to verify against.
152 * @param boolean $abort
153 * If TRUE, the operation will CRM_Core_Error::fatal() on invalid data.
154 *
155 * @return mixed
156 * The data, escaped if necessary.
157 */
158 public static function escape($data, $type, $abort = TRUE) {
159 switch ($type) {
160 case 'Integer':
161 case 'Int':
162 if (CRM_Utils_Rule::integer($data)) {
163 return $data;
164 }
165 break;
166
167 case 'Positive':
168 // CRM-8925 the 3 below are for custom fields of this type
169 case 'Country':
170 case 'StateProvince':
171 // Checked for multi valued state/country value
172 if (is_array($data)) {
173 $returnData = TRUE;
174 // @todo Reuse of the $data variable = asking for trouble.
175 // @todo This code will always return the last item in the array. Intended?
176 foreach ($data as $data) {
177 if (CRM_Utils_Rule::positiveInteger($data) || CRM_Core_DAO::escapeString($data)) {
178 $returnData = TRUE;
179 }
180 else {
181 $returnData = FALSE;
182 }
183 }
184 if ($returnData) {
185 return $data;
186 }
187 }
188 elseif (!is_numeric($data) && CRM_Core_DAO::escapeString($data)) {
189 return $data;
190 }
191 elseif (CRM_Utils_Rule::positiveInteger($data)) {
192 return $data;
193 }
194 break;
195
196 case 'File':
197 if (CRM_Utils_Rule::positiveInteger($data)) {
198 return $data;
199 }
200 break;
201
202 case 'Link':
203 if (CRM_Utils_Rule::url($data = trim($data))) {
204 return $data;
205 }
206 break;
207
208 case 'Boolean':
209 if (CRM_Utils_Rule::boolean($data)) {
210 return $data;
211 }
212 break;
213
214 case 'Float':
215 case 'Money':
216 if (CRM_Utils_Rule::numeric($data)) {
217 return $data;
218 }
219 break;
220
221 case 'String':
222 case 'Memo':
223 case 'Text':
224 return CRM_Core_DAO::escapeString($data);
225
226 case 'Date':
227 case 'Timestamp':
228 // a null date or timestamp is valid
229 if (strlen(trim($data)) == 0) {
230 return trim($data);
231 }
232
233 if ((preg_match('/^\d{8}$/', $data) ||
234 preg_match('/^\d{14}$/', $data)
235 ) &&
236 CRM_Utils_Rule::mysqlDate($data)
237 ) {
238 return $data;
239 }
240 break;
241
242 case 'ContactReference':
243 if (strlen(trim($data)) == 0) {
244 return trim($data);
245 }
246
247 if (CRM_Utils_Rule::validContact($data)) {
248 return $data;
249 }
250 break;
251
252 default:
253 CRM_Core_Error::fatal("Cannot recognize $type for $data");
254 break;
255 }
256
257 // @todo Use exceptions instead of CRM_Core_Error::fatal().
258 if ($abort) {
259 $data = htmlentities($data);
260 CRM_Core_Error::fatal("$data is not of the type $type");
261 }
262 return NULL;
263 }
264
265 /**
266 * Verify that a variable is of a given type
267 *
268 * @param mixed $data
269 * The value to validate.
270 * @param string $type
271 * The type to validate against.
272 * @param boolean $abort
273 * If TRUE, the operation will CRM_Core_Error::fatal() on invalid data.
274 * @name string $name
275 * The name of the attribute
276 *
277 * @return mixed
278 * The data, escaped if necessary
279 */
280 public static function validate($data, $type, $abort = TRUE, $name = 'One of parameters ') {
281 switch ($type) {
282 case 'Integer':
283 case 'Int':
284 if (CRM_Utils_Rule::integer($data)) {
285 return $data;
286 }
287 break;
288
289 case 'Positive':
290 if (CRM_Utils_Rule::positiveInteger($data)) {
291 return $data;
292 }
293 break;
294
295 case 'Boolean':
296 if (CRM_Utils_Rule::boolean($data)) {
297 return $data;
298 }
299 break;
300
301 case 'Float':
302 case 'Money':
303 if (CRM_Utils_Rule::numeric($data)) {
304 return $data;
305 }
306 break;
307
308 case 'Text':
309 case 'String':
310 case 'Link':
311 case 'Memo':
312 return $data;
313
314 case 'Date':
315 // a null date is valid
316 if (strlen(trim($data)) == 0) {
317 return trim($data);
318 }
319
320 if (preg_match('/^\d{8}$/', $data) &&
321 CRM_Utils_Rule::mysqlDate($data)
322 ) {
323 return $data;
324 }
325 break;
326
327 case 'Timestamp':
328 // a null timestamp is valid
329 if (strlen(trim($data)) == 0) {
330 return trim($data);
331 }
332
333 if ((preg_match('/^\d{14}$/', $data) ||
334 preg_match('/^\d{8}$/', $data)
335 ) &&
336 CRM_Utils_Rule::mysqlDate($data)
337 ) {
338 return $data;
339 }
340 break;
341
342 case 'ContactReference':
343 // null is valid
344 if (strlen(trim($data)) == 0) {
345 return trim($data);
346 }
347
348 if (CRM_Utils_Rule::validContact($data)) {
349 return $data;
350 }
351 break;
352
353 default:
354 CRM_Core_Error::fatal("Cannot recognize $type for $data");
355 break;
356 }
357
358 if ($abort) {
359 $data = htmlentities($data);
360 CRM_Core_Error::fatal("$name (value: $data) is not of the type $type");
361 }
362
363 return NULL;
364 }
365 }