File indexing completed on 2024-05-12 06:03:14

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Validate
0017  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0018  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0019  * @version    $Id$
0020  */
0021 
0022 /**
0023  * @see Zend_Validate_Abstract
0024  */
0025 // require_once 'Zend/Validate/Abstract.php';
0026 
0027 /**
0028  * @category   Zend
0029  * @package    Zend_Validate
0030  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0031  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0032  */
0033 class Zend_Validate_Ip extends Zend_Validate_Abstract
0034 {
0035     const INVALID        = 'ipInvalid';
0036     const NOT_IP_ADDRESS = 'notIpAddress';
0037 
0038     /**
0039      * @var array
0040      */
0041     protected $_messageTemplates = array(
0042         self::INVALID        => "Invalid type given. String expected",
0043         self::NOT_IP_ADDRESS => "'%value%' does not appear to be a valid IP address",
0044     );
0045 
0046     /**
0047      * internal options
0048      *
0049      * @var array
0050      */
0051     protected $_options = array(
0052         'allowipv6' => true,
0053         'allowipv4' => true
0054     );
0055 
0056     /**
0057      * Sets validator options
0058      *
0059      * @param array $options OPTIONAL Options to set, see the manual for all available options
0060      */
0061     public function __construct($options = array())
0062     {
0063         if ($options instanceof Zend_Config) {
0064             $options = $options->toArray();
0065         } else if (!is_array($options)) {
0066             $options = func_get_args();
0067             $temp['allowipv6'] = array_shift($options);
0068             if (!empty($options)) {
0069                 $temp['allowipv4'] = array_shift($options);
0070             }
0071 
0072             $options = $temp;
0073         }
0074 
0075         $options += $this->_options;
0076         $this->setOptions($options);
0077     }
0078 
0079     /**
0080      * Returns all set options
0081      *
0082      * @return array
0083      */
0084     public function getOptions()
0085     {
0086         return $this->_options;
0087     }
0088 
0089     /**
0090      * Sets the options for this validator
0091      *
0092      * @param array $options
0093      * @throws Zend_Validate_Exception
0094      * @return Zend_Validate_Ip
0095      */
0096     public function setOptions($options)
0097     {
0098         if (array_key_exists('allowipv6', $options)) {
0099             $this->_options['allowipv6'] = (boolean) $options['allowipv6'];
0100         }
0101 
0102         if (array_key_exists('allowipv4', $options)) {
0103             $this->_options['allowipv4'] = (boolean) $options['allowipv4'];
0104         }
0105 
0106         if (!$this->_options['allowipv4'] && !$this->_options['allowipv6']) {
0107             // require_once 'Zend/Validate/Exception.php';
0108             throw new Zend_Validate_Exception('Nothing to validate. Check your options');
0109         }
0110 
0111         return $this;
0112     }
0113 
0114     /**
0115      * Defined by Zend_Validate_Interface
0116      *
0117      * Returns true if and only if $value is a valid IP address
0118      *
0119      * @param  mixed $value
0120      * @return boolean
0121      */
0122     public function isValid($value)
0123     {
0124         if (!is_string($value)) {
0125             $this->_error(self::INVALID);
0126             return false;
0127         }
0128 
0129         $this->_setValue($value);
0130         if (($this->_options['allowipv4'] && !$this->_options['allowipv6'] && !$this->_validateIPv4($value)) ||
0131             (!$this->_options['allowipv4'] && $this->_options['allowipv6'] && !$this->_validateIPv6($value)) ||
0132             ($this->_options['allowipv4'] && $this->_options['allowipv6'] && !$this->_validateIPv4($value) && !$this->_validateIPv6($value))) {
0133             $this->_error(self::NOT_IP_ADDRESS);
0134             return false;
0135         }
0136 
0137         return true;
0138     }
0139 
0140     /**
0141      * Validates an IPv4 address
0142      *
0143      * @param string $value
0144      * @return bool
0145      */
0146     protected function _validateIPv4($value) {
0147         $ip2long = ip2long($value);
0148         if($ip2long === false) {
0149             return false;
0150         }
0151 
0152         return $value == long2ip($ip2long);
0153     }
0154 
0155     /**
0156      * Validates an IPv6 address
0157      *
0158      * @param  string $value Value to check against
0159      * @return boolean True when $value is a valid ipv6 address
0160      *                 False otherwise
0161      */
0162     protected function _validateIPv6($value) {
0163         if (strlen($value) < 3) {
0164             return $value == '::';
0165         }
0166 
0167         if (strpos($value, '.')) {
0168             $lastcolon = strrpos($value, ':');
0169             if (!($lastcolon && $this->_validateIPv4(substr($value, $lastcolon + 1)))) {
0170                 return false;
0171             }
0172 
0173             $value = substr($value, 0, $lastcolon) . ':0:0';
0174         }
0175 
0176         if (strpos($value, '::') === false) {
0177             return preg_match('/\A(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}\z/i', $value);
0178         }
0179 
0180         $colonCount = substr_count($value, ':');
0181         if ($colonCount < 8) {
0182             return preg_match('/\A(?::|(?:[a-f0-9]{1,4}:)+):(?:(?:[a-f0-9]{1,4}:)*[a-f0-9]{1,4})?\z/i', $value);
0183         }
0184 
0185         // special case with ending or starting double colon
0186         if ($colonCount == 8) {
0187             return preg_match('/\A(?:::)?(?:[a-f0-9]{1,4}:){6}[a-f0-9]{1,4}(?:::)?\z/i', $value);
0188         }
0189 
0190         return false;
0191     }
0192 }