Issues

ZF-7277: Zend_Validate_Hostname fails when iconv internal encoding differs from input character set

Description

The same issue as ZF-3174. Zend_Validate_Hostname will generate errors when internal encoding is set to a different value from the input data due to use of iconv_strlen without providing the charset parameter. Since string comparisons against UTF-8 data are occurring here, the input string should be converted to UTF-8 first, and then all iconv operations should be performed with UTF-8 encoding.

Patch:


--- Hostname.php        (revision 16719)                                                                                                                    
+++ Hostname.php        (working copy)                                                                                                                      
@@ -157,6 +157,13 @@                                                                                                                                        
      * @var string                                                                                                                                         
      */                                                                                                                                                    
     protected $_tld;                                                                                                                                       
+                                                                                                                                                           
+    /**                                                                                                                                                    
+     * Encoding to use                                                                                                                                     
+     *                                                                                                                                                     
+     * @var string|null                                                                                                                                    
+     */                                                                                                                                                    
+    protected $_encoding;                                                                                                                                  
                                                                                                                                                            
     /**                                                                                                                                                    
      * Array for valid Idns                                                                                                                                
@@ -330,11 +337,14 @@                                                                                                                                       
      * @param boolean          $validateIdn OPTIONAL Set whether IDN domains are validated (default true)                                                  
      * @param boolean          $validateTld OPTIONAL Set whether the TLD element of a hostname is validated (default true)                                 
      * @param Zend_Validate_Ip $ipValidator OPTIONAL                                                                                                       
+     * @param string|null      $encoding    OPTIONAL                                                                                                       
      * @return void                                                                                                                                        
      * @see http://iana.org/cctld/…  Technical Specifications for ccTLDs                                      
      */                                                                                                                                                    
-    public function __construct($allow = self::ALLOW_DNS, $validateIdn = true, $validateTld = true, Zend_Validate_Ip $ipValidator = null)                  
+    public function __construct($allow = self::ALLOW_DNS, $validateIdn = true, $validateTld = true, Zend_Validate_Ip $ipValidator = null, $encoding = null)
     {                                                                                                                                                      
+        $this->setEncoding($encoding);                                                                                                                     
+                                                                                                                                                           
         // Set allow options                                                                                                                               
         $this->setAllow($allow);                                                                                                                           
                                                                                                                                                            
@@ -344,8 +354,41 @@                                                                                                                                        
                                                                                                                                                            
         $this->setIpValidator($ipValidator);                                                                                                               
     }                                                                                                                                                      
+                                                                                                                                                           
+    /**                                                                                                                                                    
+     * Returns the actual encoding                                                                                                                         
+     *                                                                                                                                                     
+     * @return string                                                                                                                                      
+     */                                                                                                                                                    
+    public function getEncoding()                                                                                                                          
+    {                                                                                                                                                      
+        return $this->_encoding;                                                                                                                           
+    }                                                                                                                                                      
                                                                                                                                                            
     /**                                                                                                                                                    
+     * Sets a new encoding to use                                                                                                                          
+     *                                                                                                                                                     
+     * @param string $encoding                                                                                                                             
+     * @return Zend_Validate_StringLength                                                                                                                  
+     */                                                                                                                                                    
+    public function setEncoding($encoding = null)                                                                                                          
+    {                                                                                                                                                      
+        if ($encoding !== null) {                                                                                                                          
+            $orig   = iconv_get_encoding('internal_encoding');                                                                                             
+            $result = iconv_set_encoding('internal_encoding', $encoding);                                                                                  
+            if (!$result) {                                                                                                                                
+                require_once 'Zend/Validate/Exception.php';                                                                                                
+                throw new Zend_Validate_Exception('Given encoding not supported on this OS!');                                                             
+            }                                                                                                                                              
+
+            iconv_set_encoding('internal_encoding', $orig);
+        }
+
+        $this->_encoding = $encoding;
+        return $this;
+    }
+
+    /**
      * @param Zend_Validate_Ip $ipValidator OPTIONAL
      * @return void;
      */
@@ -417,13 +460,17 @@
         $valueString = (string) $value;

         $this->_setValue($valueString);
+
+        if(null !== $this->_encoding) {
+            $valueString = iconv($this->_encoding, 'UTF-8', $valueString);
+        }

         // Check input against IP address schema
         if ($this->_ipValidator->setTranslator($this->getTranslator())->isValid($valueString)) {
             if (!($this->_allow & self::ALLOW_IP)) {
                 $this->_error(self::IP_ADDRESS_NOT_ALLOWED);
                 return false;
-            } else{
+            } else {
                 return true;
             }
         }
@@ -505,7 +552,7 @@
                                     $length = $this->_idnLength[strtoupper($this->_tld)];
                                 }

-                                if (iconv_strlen($domainPart) > $length) {
+                                if (iconv_strlen($domainPart, 'UTF-8') > $length) {
                                     $this->_error(self::INVALID_HOSTNAME);
                                 } else {
                                     $check = true;

Comments

Fixed with r17138