[TASK] Optimizations for IPv6-functions in t3lib_div
authorStefan Neufeind <typo3.neufeind@speedpartner.de>
Tue, 2 Aug 2011 11:08:08 +0000 (13:08 +0200)
committerAndreas Wolf <andreas.wolf@ikt-werk.de>
Sun, 7 Aug 2011 11:09:09 +0000 (13:09 +0200)
* speedup by using IPv6-support from PHP if present
* since there is IPv6Hex2Bin(), also add IPv6Bin2Hex()
* since there is normalizeIPv6(), also add compressIPv6()
* normalization also involves converting to lowercase
* extend unit-tests

Change-Id: I7c9eda4de0f2c06f06a530f1180233d592f9dfdc
Resolves: #28669
Releases: 4.6, 4.7
Reviewed-on: http://review.typo3.org/4019
Reviewed-by: Andreas Wolf
Tested-by: Andreas Wolf
t3lib/class.t3lib_div.php
tests/t3lib/class.t3lib_divTest.php

index 5539f8f..b59c9fd 100644 (file)
@@ -523,28 +523,64 @@ final class t3lib_div {
         *
         * @param string $hex IPv6 address in hex-presentation
         * @return string Binary representation (16 characters, 128 characters)
-        * @see normalizeIPv6()
+        * @see IPv6Bin2Hex()
         */
        public static function IPv6Hex2Bin($hex) {
-               // normalized representation has 39 characters (0000:0000:0000:0000:0000:0000:0000:0000)
-               if (strlen($hex) < 39) {
+                       // use PHP-function if PHP was compiled with IPv6-support
+               if (defined('AF_INET6')) {
+                       $bin = inet_pton($hex);
+               } else {
                        $hex = self::normalizeIPv6($hex);
+                       $hex = str_replace(':', '', $hex); // Replace colon to nothing
+                       $bin = pack("H*" , $hex);
                }
-               $hex = str_replace(':', '', $hex); // Replace colon to nothing
-               $bin = pack("H*" , $hex);
                return $bin;
        }
 
        /**
+        * Transform an IPv6 address from binary to hex-representation
+        *
+        * @param string $hex IPv6 address in hex-presentation
+        * @return string Binary representation (16 characters, 128 characters)
+        * @see IPv6Hex2Bin()
+        */
+       public static function IPv6Bin2Hex($bin) {
+                       // use PHP-function if PHP was compiled with IPv6-support
+               if (defined('AF_INET6')) {
+                       $hex = inet_ntop($bin);
+               } else {
+                       $hex = unpack("H*" , $bin);
+                       $hex = chunk_split($hex[1], 4, ':');
+                               // strip last colon (from chunk_split)
+                       $hex = substr($hex, 0, -1);
+                               // IPv6 is now in normalized form
+                               // compress it for easier handling and to match result from inet_ntop()
+                       $hex = self::compressIPv6($hex);
+               }
+               return $hex;
+
+       }
+
+       /**
         * Normalize an IPv6 address to full length
         *
         * @param string $address Given IPv6 address
         * @return string Normalized address
+        * @see compressIPv6()
         */
        public static function normalizeIPv6($address) {
                $normalizedAddress = '';
                $stageOneAddress = '';
 
+                       // according to RFC lowercase-representation is recommended
+               $address = strtolower($address);
+
+                       // normalized representation has 39 characters (0000:0000:0000:0000:0000:0000:0000:0000)
+               if (strlen($address) == 39) {
+                               // already in full expanded form
+                       return $address;
+               }
+
                $chunks = explode('::', $address); // Count 2 if if address has hidden zero blocks
                if (count($chunks) == 2) {
                        $chunksLeft = explode(':', $chunks[0]);
@@ -594,6 +630,48 @@ final class t3lib_div {
                return $normalizedAddress;
        }
 
+
+       /**
+        * Compress an IPv6 address to the shortest notation
+        *
+        * @param string $address Given IPv6 address
+        * @return string Compressed address
+        * @see normalizeIPv6()
+        */
+       public static function compressIPv6($address) {
+                       // use PHP-function if PHP was compiled with IPv6-support
+               if (defined('AF_INET6')) {
+                       $bin = inet_pton($address);
+                       $address = inet_ntop($bin);
+               } else {
+                       $address = self::normalizeIPv6($address);
+
+                               // append one colon for easier handling
+                               // will be removed later
+                       $address .= ':';
+
+                               // according to IPv6-notation the longest match
+                               // of a package of '0000:' may be replaced with ':'
+                               // (resulting in something like '1234::abcd')
+                       for ($counter = 8; $counter > 1; $counter--) {
+                               $search = str_repeat('0000:', $counter);
+                               if (($pos = strpos($address, $search)) !== FALSE) {
+                                       $address = substr($address, 0, $pos) . ':' . substr($address, $pos + ($counter*5));
+                                       break;
+                               }
+                       }
+
+                               // up to 3 zeros in the first part may be removed
+                       $address = preg_replace('/^0{1,3}/', '', $address);
+                               // up to 3 zeros at the beginning of other parts may be removed
+                       $address = preg_replace('/:0{1,3}/', ':', $address);
+
+                               // strip last colon (from chunk_split)
+                       $address = substr($address, 0, -1);
+               }
+               return $address;
+       }
+
        /**
         * Validate a given IP address.
         *
index 7931c8a..ddf0665 100644 (file)
@@ -299,15 +299,15 @@ class t3lib_divTest extends tx_phpunit_testcase {
        ///////////////////////////////
 
        /**
-        * Data provider for IPv6Hex2BinReturnsCorrectBinaryHosts
+        * Data provider for IPv6Hex2BinCorrect
         *
         * @return array Data sets
         */
-       public static function IPv6Hex2BinDataProviderCorrectlyConverted() {
+       public static function IPv6Hex2BinDataProviderCorrect() {
                return array(
                        'empty 1' => array('::', str_pad('', 16, "\x00")),
                        'empty 2, already normalized' => array('0000:0000:0000:0000:0000:0000:0000:0000', str_pad('', 16, "\x00")),
-                       'empty 3, already normalized' => array('0102:0304:0000:0000:0000:0000:0506:0078', "\x01\x02\x03\x04" . str_pad('', 8, "\x00") . "\x05\x06\x00\x78"),
+                       'already normalized' => array('0102:0304:0000:0000:0000:0000:0506:0078', "\x01\x02\x03\x04" . str_pad('', 8, "\x00") . "\x05\x06\x00\x78"),
                        'expansion in middle 1' => array('1::2', "\x00\x01" . str_pad('', 12, "\x00") . "\x00\x02"),
                        'expansion in middle 2' => array('beef::fefa', "\xbe\xef" . str_pad('', 12, "\x00") . "\xfe\xfa"),
                );
@@ -315,26 +315,54 @@ class t3lib_divTest extends tx_phpunit_testcase {
 
        /**
         * @test
-        * @dataProvider IPv6Hex2BinDataProviderCorrectlyConverted
+        * @dataProvider IPv6Hex2BinDataProviderCorrect
         */
-       public function IPv6Hex2BinReturnsCorrectBinaryHosts($inputIP, $binary) {
-               $this->assertTrue(t3lib_div::IPv6Hex2Bin($inputIP) === $binary);
+       public function IPv6Hex2BinCorrectlyConvertsAddresses($hex, $binary) {
+               $this->assertTrue(t3lib_div::IPv6Hex2Bin($hex) === $binary);
        }
 
-       /////////////////////////////////
-       // Tests concerning normalizeIPv6
-       /////////////////////////////////
+       ///////////////////////////////
+       // Tests concerning IPv6Bin2Hex
+       ///////////////////////////////
+
+       /**
+        * Data provider for IPv6Bin2HexCorrect
+        *
+        * @return array Data sets
+        */
+       public static function IPv6Bin2HexDataProviderCorrect() {
+               return array(
+                       'empty' => array(str_pad('', 16, "\x00"), '::'),
+                       'non-empty front' => array("\x01" . str_pad('', 15, "\x00"), '100::'),
+                       'non-empty back' => array(str_pad('', 15, "\x00") . "\x01", '::1'),
+                       'normalized' => array("\x01\x02\x03\x04" . str_pad('', 8, "\x00") . "\x05\x06\x00\x78", '102:304::506:78'),
+                       'expansion in middle 1' => array("\x00\x01" . str_pad('', 12, "\x00") . "\x00\x02", '1::2'),
+                       'expansion in middle 2' => array("\xbe\xef" . str_pad('', 12, "\x00") . "\xfe\xfa", 'beef::fefa'),
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider IPv6Bin2HexDataProviderCorrect
+        */
+       public function IPv6Bin2HexCorrectlyConvertsAddresses($binary, $hex) {
+               $this->assertEquals(t3lib_div::IPv6Bin2Hex($binary), $hex);
+       }
+
+       ////////////////////////////////////////////////
+       // Tests concerning normalizeIPv6 / compressIPv6
+       ////////////////////////////////////////////////
 
        /**
         * Data provider for normalizeIPv6ReturnsCorrectlyNormalizedFormat
         *
         * @return array Data sets
         */
-       public static function normalizeIPv6DataProviderCorrectlyNormalized() {
+       public static function normalizeCompressIPv6DataProviderCorrect() {
                return array(
                        'empty' => array('::', '0000:0000:0000:0000:0000:0000:0000:0000'),
                        'localhost' => array('::1', '0000:0000:0000:0000:0000:0000:0000:0001'),
-                       'some address on right side' => array('::F0F', '0000:0000:0000:0000:0000:0000:0000:0F0F'),
+                       'some address on right side' => array('::f0f', '0000:0000:0000:0000:0000:0000:0000:0f0f'),
                        'expansion in middle 1' => array('1::2', '0001:0000:0000:0000:0000:0000:0000:0002'),
                        'expansion in middle 2' => array('1:2::3', '0001:0002:0000:0000:0000:0000:0000:0003'),
                        'expansion in middle 3' => array('1::2:3', '0001:0000:0000:0000:0000:0000:0002:0003'),
@@ -344,10 +372,18 @@ class t3lib_divTest extends tx_phpunit_testcase {
 
        /**
         * @test
-        * @dataProvider normalizeIPv6DataProviderCorrectlyNormalized
+        * @dataProvider normalizeCompressIPv6DataProviderCorrect
+        */
+       public function normalizeIPv6CorrectlyNormalizesAddresses($compressed, $normalized) {
+               $this->assertEquals(t3lib_div::normalizeIPv6($compressed), $normalized);
+       }
+
+       /**
+        * @test
+        * @dataProvider normalizeCompressIPv6DataProviderCorrect
         */
-       public function normalizeIPv6ReturnsCorrectlyNormalizedFormat($inputIP, $normalized) {
-               $this->assertTrue(t3lib_div::normalizeIPv6($inputIP) === $normalized);
+       public function compressIPv6CorrectlyCompressesAdresses($compressed, $normalized) {
+               $this->assertEquals(t3lib_div::compressIPv6($normalized), $compressed);
        }
 
        ///////////////////////////////