source: trunk/lib/Validator.inc.php @ 468

Last change on this file since 468 was 468, checked in by anonymous, 10 years ago

Completed integrating /branches/eli_branch into /trunk. Changes include:

  • Removed closing ?> from end of files
  • Upgrade old-style contructor methods to use construct() instead.
  • Class properties and methods defined as public, private, static or protected
  • Ensure code runs under E_ALL with only mysql_* deprecated warnings
  • Search for the '@' symbol anywhere it might be used to supress runtime errors, then replace with proper error recovery.
  • Run the php cli -l option to check files for syntax errors.
  • Bring tests up-to-date with latest version and methods of PHPUnit
File size: 12.1 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    // Validator::validatePhone() return types.
50    const PHONE_SUCCESS = 0;
51    const PHONE_REGEX_FAIL = 1;
52    const PHONE_LENGTH_FAIL = 2;
53
54    /**
55     * Ensures a value is empty.
56     *
57     * @param  string $val The input data to validate.
58     * @return bool   true if form is not empty, false otherwise.
59     */
60    static public function notEmpty($val)
61    {
62        return '' != trim((string)$val);
63    }
64
65    /**
66     * Ensures a value is blank.
67     *
68     * @param  string $val The input data to validate.
69     * @return bool   true if form is empty, false otherwise.
70     */
71    static public function isEmpty($val)
72    {
73        return '' == trim((string)$val);
74    }
75
76    /**
77     * Check whether input is a string.
78     *
79     * @param  string $val The input data to validate.
80     * @return bool   true if form is a string, false otherwise.
81     */
82    static public function isString($val)
83    {
84        return '' == trim((string)$val) || is_string($val);
85    }
86
87    /**
88     * Check whether input is a number. Allows negative numbers.
89     *
90     * @param  string $val The input data to validate.
91     * @return bool   True if no errors found, false otherwise.
92     */
93    static public function isNumber($val)
94    {
95        return '' == trim((string)$val) || is_numeric($val);
96    }
97
98    /**
99     * addError if input is NOT an integer. Don't just use is_int() because the
100     * data coming from the user is *really* a string.
101     *
102     * @param  string $val The input data to validate.
103     * @return bool   true if value is an integer
104     */
105    static public function isInteger($val, $negative_ok=false)
106    {
107        $pattern = $negative_ok ? '/^-?[[:digit:]]+$/' : '/^[[:digit:]]+$/';
108        return '' == trim((string)$val) || (is_numeric($val) && preg_match($pattern, $val));
109    }
110
111    /**
112     * Check whether input is a float. Don't just use is_float() because the
113     * data coming from the user is *really* a string. Integers will also
114     * pass this test.
115     *
116     * @param  string $val The input data to validate.
117     * @return bool   true if value is a float
118     */
119    static public function isFloat($val, $negative_ok=false)
120    {
121        $pattern = $negative_ok ? '/^-?[[:digit:]]*(?:\.?[[:digit:]]+)$/' : '/^[[:digit:]]*(?:\.?[[:digit:]]+)$/';
122        return '' == trim((string)$val) || (is_numeric($val) && preg_match($pattern, $val));
123    }
124
125    /**
126     * Check whether input is an array.
127     *
128     * @param  string $val The input data to validate.
129     * @return bool   true if value is a float
130     */
131    static public function isArray($val)
132    {
133        return (is_string($val) && '' == trim((string)$val)) || is_array($val);
134    }
135
136    /**
137     * Check whether input matches the specified perl regular expression
138     * pattern.
139     *
140     * @param  string $val The input data to validate.
141     * @param  int    $regex            PREG that the string must match
142     * @param  bool   $valid_on_match   Set to true to be valid if match, or false to be valid if the match fails.
143     * @return bool   true if value passes regex test
144     */
145    static public function checkRegex($val, $regex, $valid_on_match=true)
146    {
147        return $valid_on_match ? preg_match($regex, $val) : !preg_match($regex, $val);
148    }
149
150    /**
151     * Tests if the string length is between specified values. Whitespace excluded for min.
152     *
153     * @param  string $val The input data to validate.
154     * @param  int    $min       minimum length of string, inclusive
155     * @param  int    $max       maximum length of string, inclusive
156     * @return bool   true if string length is within given boundaries
157     */
158    static public function stringLength($val, $min, $max)
159    {
160        return mb_strlen(trim((string)$val)) >= $min && mb_strlen($val) <= $max;
161    }
162
163    /**
164     * Check whether input is within a valid numeric range.
165     *
166     * @param  string $val The input data to validate.
167     * @param  int    $min       minimum value of number, inclusive
168     * @param  int    $max       maximum value of number, inclusive
169     * @return bool   True if no errors found, false otherwise.
170     */
171    static public function numericRange($val, $min, $max)
172    {
173        return '' == trim((string)$val) || (is_numeric($val) && $val >= $min && $val <= $max);
174    }
175
176    /**
177     * Validates an email address based on the recommendations in RFC 3696.
178     * Is more loose than restrictive, to allow the many valid variants of
179     * email addresses while catching the most common mistakes.
180     * http://www.faqs.org/rfcs/rfc822.html
181     * http://www.faqs.org/rfcs/rfc2822.html
182     * http://www.faqs.org/rfcs/rfc3696.html
183     * http://www.faqs.org/rfcs/rfc1035.html
184     *
185     * @access  public
186     * @param   string  $val    The input data to validate..
187     * @param   bool    $strict Do we run strict tests?
188     * @return  const           One of the constant values: Validate::EMAIL_SUCCESS|Validate::EMAIL_REGEX_FAIL|Validate::EMAIL_LENGTH_FAIL|Validate::EMAIL_MX_FAIL
189     * @author  Quinn Comendant <quinn@strangecode.com>
190     */
191    static public function validateEmail($val, $strict=false)
192    {
193        require_once 'codebase/lib/Email.inc.php';
194        $e = new Email();
195
196        // Test email address format.
197        if (!preg_match($e->getParam('regex'), $val, $e_parts)) {
198            return self::EMAIL_REGEX_FAIL;
199        }
200
201        // We have a match! Here are the captured subpatterns, on which further tests are run.
202        // The part before the @.
203        $local = $e_parts[2];
204
205        // The part after the @.
206        // If domain is an IP [XXX.XXX.XXX.XXX] strip off the brackets.
207        $domain = $e_parts[3]{0} == '[' ? mb_substr($e_parts[3], 1, -1) : $e_parts[3];
208
209        // Test length.
210        if (mb_strlen($local) > 64 || mb_strlen($domain) > 191) {
211            return self::EMAIL_LENGTH_FAIL;
212        }
213
214        // Strict tests below.
215
216        // Check domain exists: It's a domain if ip2long fails; checkdnsrr ensures a MX record exists; gethostbyname() ensures the domain exists.
217        if ($strict && ip2long($domain) === false && function_exists('checkdnsrr') && !checkdnsrr($domain . '.', 'MX') && gethostbyname($domain) == $domain) {
218            return self::EMAIL_MX_FAIL;
219        }
220
221        return self::EMAIL_SUCCESS;
222    }
223
224    /**
225     * Check whether input is a valid phone number. Notice: it is now set
226     * to allow characters like - or () or + so people can type in a phone
227     * number that looks like: +1 (530) 555-1212
228     *
229     * @param  string  $form_name the name of the incoming form variable
230     *
231     * @return bool    true if no errors found, false otherwise
232     */
233    static public function validatePhone($val)
234    {
235        if (!self::checkRegex($val, '/^[0-9 +().-]*$/', true)) {
236            return self::PHONE_REGEX_FAIL;
237        }
238        if (!self::stringLength($val, 0, 25)) {
239            return self::PHONE_LENGTH_FAIL;
240        }
241        return self::PHONE_SUCCESS;
242    }
243
244    /**
245     * Verifies that date can be processed by the strtotime function.
246     * Empty strings are considered valid. Other values are tested on their return value from strtotime(). Null values will fail.
247     *
248     * @param  string  $val The input data to validate.
249     * @return bool    True if no errors found, false otherwise.
250     */
251    static public function validateStrDate($val)
252    {
253        if (is_string($val) && '' === trim($val)) {
254            // Don't be too bothered about empty strings.
255            return true;
256        }
257
258        $timestamp = strtotime($val);
259        if (!$timestamp || $timestamp < 1) {
260            return false;
261        } else {
262            return true;
263        }
264    }
265
266    /**
267     * Verifies credit card number using the Luhn (mod 10) algorithm.
268     * http://en.wikipedia.org/wiki/Luhn_algorithm
269     *
270     * @param  string  $val   The input data to validate..
271     * @param  string  $cc_num      Card number to verify.
272     * @param  string  $cc_type     Optional, card type to do specific checks.
273     * @return bool    True if no errors found, false otherwise.
274     */
275    static public function validateCCNumber($val, $cc_type=null)
276    {
277        // Get rid of any non-digits
278        $cc_num = preg_replace('/[^\d]/', '', $val);
279
280        // Perform card-specific checks, if applicable
281        switch ($cc_type) {
282        case self::CC_TYPE_VISA :
283            $regex = '/^4\d{15}$|^4\d{12}$/';
284            break;
285        case self::CC_TYPE_MASTERCARD :
286            $regex = '/^5[1-5]\d{14}$/';
287            break;
288        case self::CC_TYPE_AMEX :
289            $regex = '/^3[47]\d{13}$/';
290            break;
291        case self::CC_TYPE_DISCOVER :
292            $regex = '/^6011\d{12}$/';
293            break;
294        case self::CC_TYPE_DINERS :
295            $regex = '/^30[0-5]\d{11}$|^3[68]\d{12}$/';
296            break;
297        case self::CC_TYPE_JCB :
298            $regex = '/^3\d{15}$|^2131|1800\d{11}$/';
299            break;
300        default :
301            $regex = '';
302            break;
303        }
304
305        if ('' != $regex && !preg_match($regex, $cc_num)) {
306            // Invalid format.
307            return false;
308        }
309
310        // The Luhn formula works right to left, so reverse the number.
311        $cc_num = strrev($cc_num);
312
313        $luhn_total = 0;
314
315        $num = mb_strlen($cc_num);
316        for ($i=0; $i<$num; $i++) {
317            // Get each digit.
318            $digit = mb_substr($cc_num, $i, 1);
319
320            //  If it's an odd digit, double it.
321            if ($i / 2 != floor($i / 2)) {
322                $digit *= 2;
323            }
324
325            //  If the result is two digits, add them.
326            if (mb_strlen($digit) == 2) {
327                $digit = mb_substr($digit, 0, 1) + mb_substr($digit, 1, 1);
328            }
329
330            //  Add the current digit to the $luhn_total.
331            $luhn_total += $digit;
332        }
333
334        // If the Total is evenly divisible by 10, it's cool!
335        return $luhn_total % 10 == 0;
336    }
337
338    /**
339     * Check whether a file was selected for uploading. If file is missing, it's an error.
340     *
341     * @param  string $form_name The input data to validate.
342     * @return bool   True if no errors found, false otherwise.
343     */
344    static public function fileUploaded($form_name)
345    {
346        if (!isset($_FILES[$form_name]['name']) || empty($_FILES[$form_name]['name'])) {
347            return false;
348        }
349
350        if (is_array($_FILES[$form_name]['name'])) {
351            foreach($_FILES[$form_name]['name'] as $f) {
352                if ('' == $f) {
353                    return false;
354                }
355            }
356        } else {
357            if ('' == $_FILES[$form_name]['name']) {
358                return false;
359            }
360        }
361
362        return true;
363    }
364
365} // THE END
366
Note: See TracBrowser for help on using the repository browser.