source: branches/eli_branch/lib/Validator.inc.php @ 447

Last change on this file since 447 was 447, checked in by anonymous, 11 years ago

Changed some global constants to class constants (in cases where backwards compatability wouldn't break).

File size: 11.3 KB
Line 
1<?php
2/**
3 * The Strangecode Codebase - a general application development framework for PHP
4 * For details visit the project site: <http://trac.strangecode.com/codebase/>
5 * Copyright 2001-2012 Strangecode, LLC
6 *
7 * This file is part of The Strangecode Codebase.
8 *
9 * The Strangecode Codebase is free software: you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your option)
12 * any later version.
13 *
14 * The Strangecode Codebase is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * The Strangecode Codebase. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/**
24 * Validator.inc.php
25 *
26 * The Validator class provides a methods for validating input against different criteria.
27 * All functions return true if the input passes the test.
28 *
29 * @author    Quinn Comendant <quinn@strangecode.com>
30 * @version   1.0
31 */
32
33class Validator {
34
35    // Known credit card types.
36    const CC_TYPE_VISA = 1;
37    const CC_TYPE_MASTERCARD = 2;
38    const CC_TYPE_AMEX = 3;
39    const CC_TYPE_DISCOVER = 4;
40    const CC_TYPE_DINERS = 5;
41    const CC_TYPE_JCB = 6;
42
43    // Validator::validateEmail() return types.
44    const EMAIL_SUCCESS = 0;
45    const EMAIL_REGEX_FAIL = 1;
46    const EMAIL_LENGTH_FAIL = 2;
47    const EMAIL_MX_FAIL = 3;
48
49    /**
50     * Ensures a value is empty.
51     *
52     * @param  string $val The input data to validate.
53     * @return bool   true if form is not empty, false otherwise.
54     */
55    public function notEmpty($val)
56    {
57        return '' != trim((string)$val);
58    }
59
60    /**
61     * Ensures a value is blank.
62     *
63     * @param  string $val The input data to validate.
64     * @return bool   true if form is empty, false otherwise.
65     */
66    public function isEmpty($val)
67    {
68        return '' == trim((string)$val);
69    }
70
71    /**
72     * Check whether input is a string.
73     *
74     * @param  string $val The input data to validate.
75     * @return bool   true if form is a string, false otherwise.
76     */
77    public function isString($val)
78    {
79        return '' == trim((string)$val) || is_string($val);
80    }
81
82    /**
83     * Check whether input is a number. Allows negative numbers.
84     *
85     * @param  string $val The input data to validate.
86     * @return bool   True if no errors found, false otherwise.
87     */
88    public function isNumber($val)
89    {
90        return '' == trim((string)$val) || is_numeric($val);
91    }
92
93    /**
94     * addError if input is NOT an integer. Don't just use is_int() because the
95     * data coming from the user is *really* a string.
96     *
97     * @param  string $val The input data to validate.
98     * @return bool   true if value is an integer
99     */
100    public function isInteger($val, $negative_ok=false)
101    {
102        $pattern = $negative_ok ? '/^-?[[:digit:]]+$/' : '/^[[:digit:]]+$/';
103        return '' == trim((string)$val) || (is_numeric($val) && preg_match($pattern, $val));
104    }
105
106    /**
107     * Check whether input is a float. Don't just use is_float() because the
108     * data coming from the user is *really* a string. Integers will also
109     * pass this test.
110     *
111     * @param  string $val The input data to validate.
112     * @return bool   true if value is a float
113     */
114    public function isFloat($val, $negative_ok=false)
115    {
116        $pattern = $negative_ok ? '/^-?[[:digit:]]*(?:\.?[[:digit:]]+)$/' : '/^[[:digit:]]*(?:\.?[[:digit:]]+)$/';
117        return '' == trim((string)$val) || (is_numeric($val) && preg_match($pattern, $val));
118    }
119
120    /**
121     * Check whether input is an array.
122     *
123     * @param  string $val The input data to validate.
124     * @return bool   true if value is a float
125     */
126    public function isArray($val)
127    {
128        return (is_string($val) && '' == trim((string)$val)) || is_array($val);
129    }
130
131    /**
132     * Check whether input matches the specified perl regular expression
133     * pattern.
134     *
135     * @param  string $val The input data to validate.
136     * @param  int    $regex            PREG that the string must match
137     * @param  bool   $valid_on_match   Set to true to be valid if match, or false to be valid if the match fails.
138     * @return bool   true if value passes regex test
139     */
140    public function checkRegex($val, $regex, $valid_on_match=true)
141    {
142        return $valid_on_match ? preg_match($regex, $val) : !preg_match($regex, $val);
143    }
144
145    /**
146     * Tests if the string length is between specified values. Whitespace excluded for min.
147     *
148     * @param  string $val The input data to validate.
149     * @param  int    $min       minimum length of string, inclusive
150     * @param  int    $max       maximum length of string, inclusive
151     * @return bool   true if string length is within given boundaries
152     */
153    public function stringLength($val, $min, $max)
154    {
155        return mb_strlen(trim((string)$val)) >= $min && mb_strlen($val) <= $max;
156    }
157
158    /**
159     * Check whether input is within a valid numeric range.
160     *
161     * @param  string $val The input data to validate.
162     * @param  int    $min       minimum value of number, inclusive
163     * @param  int    $max       maximum value of number, inclusive
164     * @return bool   True if no errors found, false otherwise.
165     */
166    public function numericRange($val, $min, $max)
167    {
168        return '' == trim((string)$val) || (is_numeric($val) && $val >= $min && $val <= $max);
169    }
170
171    /**
172     * Validates an email address based on the recommendations in RFC 3696.
173     * Is more loose than restrictive, to allow the many valid variants of
174     * email addresses while catching the most common mistakes.
175     * http://www.faqs.org/rfcs/rfc822.html
176     * http://www.faqs.org/rfcs/rfc2822.html
177     * http://www.faqs.org/rfcs/rfc3696.html
178     * http://www.faqs.org/rfcs/rfc1035.html
179     *
180     * @access  public
181     * @param   string  $val    The input data to validate..
182     * @return  const           One of the constant values: Validate::EMAIL_SUCCESS|Validate::EMAIL_REGEX_FAIL|Validate::EMAIL_LENGTH_FAIL|Validate::EMAIL_MX_FAIL
183     * @author  Quinn Comendant <quinn@strangecode.com>
184     */
185    public function validateEmail($val)
186    {
187        require_once 'codebase/lib/Email.inc.php';
188        $e = new Email();
189
190        // Test email address format.
191        if (!preg_match($e->getParam('regex'), $val, $e_parts)) {
192            return self::EMAIL_REGEX_FAIL;
193        }
194
195        // We have a match! Here are the captured subpatterns, on which further tests are run.
196        // The part before the @.
197        $local = $e_parts[2];
198
199        // The part after the @.
200        // If domain is an IP [XXX.XXX.XXX.XXX] strip off the brackets.
201        $domain = $e_parts[3]{0} == '[' ? mb_substr($e_parts[3], 1, -1) : $e_parts[3];
202
203        // Test length.
204        if (mb_strlen($local) > 64 || mb_strlen($domain) > 191) {
205            return self::EMAIL_LENGTH_FAIL;
206        }
207
208        // Check domain exists: It's a domain if ip2long fails; Checkdnsrr ensures a MX record exists; Gethostbyname() ensures the domain exists.
209        // Compare ip2long twice for php4 backwards compat.
210        if ((ip2long($domain) == '-1' || ip2long($domain) === false) && function_exists('checkdnsrr') && !checkdnsrr($domain . '.', 'MX') && gethostbyname($domain) == $domain) {
211            // FIXME: Do we care?
212            // return self::EMAIL_MX_FAIL;
213        }
214
215        return self::EMAIL_SUCCESS;
216    }
217
218    /**
219     * Verifies that date can be processed by the strtotime function.
220     *
221     * @param  string  $val The input data to validate.
222     * @return bool    True if no errors found, false otherwise.
223     */
224    public function validateStrDate($val)
225    {
226        $app =& App::getInstance();
227
228        if ('' == trim($val)) {
229            // Don't be too bothered about empty strings.
230            return true;
231        }
232
233        $timestamp = strtotime($val);
234        // Return values change between php4 and php5.
235        if ('' != trim($val) && ($timestamp === -1 || $timestamp === false)) {
236            return false;
237        } else {
238            return true;
239        }
240    }
241
242
243    /**
244     * Verifies credit card number using the Luhn (mod 10) algorithm.
245     * http://en.wikipedia.org/wiki/Luhn_algorithm
246     *
247     * @param  string  $val   The input data to validate..
248     * @param  string  $cc_num      Card number to verify.
249     * @param  string  $cc_type     Optional, card type to do specific checks.
250     * @return bool    True if no errors found, false otherwise.
251     */
252     public function validateCCNumber($val, $cc_type=null)
253     {
254         // Get rid of any non-digits
255         $cc_num = preg_replace('/[^\d]/', '', $val);
256
257         // Perform card-specific checks, if applicable
258         switch ($cc_type) {
259             case self::CC_TYPE_VISA :
260                 $regex = '/^4\d{15}$|^4\d{12}$/';
261                 break;
262             case self::CC_TYPE_MASTERCARD :
263                 $regex = '/^5[1-5]\d{14}$/';
264                 break;
265             case self::CC_TYPE_AMEX :
266                 $regex = '/^3[47]\d{13}$/';
267                 break;
268             case self::CC_TYPE_DISCOVER :
269                 $regex = '/^6011\d{12}$/';
270                 break;
271             case self::CC_TYPE_DINERS :
272                 $regex = '/^30[0-5]\d{11}$|^3[68]\d{12}$/';
273                 break;
274             case self::CC_TYPE_JCB :
275                 $regex = '/^3\d{15}$|^2131|1800\d{11}$/';
276                 break;
277             default :
278                 $regex = '';
279                 break;
280         }
281
282         if ('' != $regex && !preg_match($regex, $cc_num)) {
283             // Invalid format.
284             return false;
285         }
286
287         // The Luhn formula works right to left, so reverse the number.
288         $cc_num = strrev($cc_num);
289
290         $luhn_total = 0;
291
292         $num = mb_strlen($cc_num);
293         for ($i=0; $i<$num; $i++) {
294             // Get each digit.
295             $digit = mb_substr($cc_num, $i, 1);
296
297             //  If it's an odd digit, double it.
298             if ($i / 2 != floor($i / 2)) {
299                 $digit *= 2;
300             }
301
302             //  If the result is two digits, add them.
303             if (mb_strlen($digit) == 2) {
304                 $digit = mb_substr($digit, 0, 1) + mb_substr($digit, 1, 1);
305             }
306
307             //  Add the current digit to the $luhn_total.
308             $luhn_total += $digit;
309         }
310
311         // If the Total is evenly divisible by 10, it's cool!
312         return $luhn_total % 10 == 0;
313     }
314
315    /**
316     * Check whether a file was selected for uploading. If file is missing, it's an error.
317     *
318     * @param  string $form_name The input data to validate.
319     * @return bool   True if no errors found, false otherwise.
320     */
321    public function fileUploaded($form_name)
322    {
323        if (!isset($_FILES[$form_name]['name']) || empty($_FILES[$form_name]['name'])) {
324            return false;
325        }
326
327        if (is_array($_FILES[$form_name]['name'])) {
328            foreach($_FILES[$form_name]['name'] as $f) {
329                if ('' == $f) {
330                    return false;
331                }
332            }
333        } else {
334            if ('' == $_FILES[$form_name]['name']) {
335                return false;
336            }
337        }
338
339        return true;
340    }
341
342} // THE END
343
Note: See TracBrowser for help on using the repository browser.