예제 #1
0
 /**
  * Load vendor database
  *
  * Clears the database and iterates over $input. Each entry of the form
  * "MAC_address[/bits] TAB short_name [whitespace # long_name]" gets parsed
  * and added to the database.
  *
  * @param array|\Traversable $input
  */
 public static function loadVendorDatabase($input)
 {
     self::$_vendorList = array();
     foreach ($input as $line) {
         // The regex produces a $matches array with these elements of interest:
         // [1] MAC address or prefix, with optional mask suffix ("/36")
         // [2] short vendor name (used if [4] is empty)
         // [4] long vendor name or empty string
         if ($line == '' or $line[0] == '#' or !preg_match("/^(\\H+)\t(\\H+)\\h*(# )?(.*)/", $line, $matches)) {
             continue;
         }
         // remove ':' and '-' delimiters
         $mac = str_replace(array(':', '-'), '', $matches[1]);
         $pos = strpos($mac, '/');
         if ($pos === false) {
             // No mask suffix. $mac is a prefix. Derive mask length (number
             // of bits) from prefix length (1 digit => 4 bits).
             $address = $mac;
             $length = strlen($mac) * 4;
         } else {
             // Split string at delimiter. Left part is the address or
             // prefix, right part is the mask length in bits.
             $address = substr($mac, 0, $pos);
             $length = substr($mac, $pos + 1);
         }
         self::$_vendorList[] = array('address' => str_pad($address, self::LENGTH_HEX, '0'), 'mask' => $length, 'vendor' => $matches[4] ?: $matches[2]);
     }
     // Convert raw data to platform-specific values. Use native 64 bit
     // integers if available, GMP objects otherwise (requires GMP
     // extension).
     // The mask length is converted to a bitmask.
     // @codeCoverageIgnoreStart
     if (PHP_INT_SIZE < 8) {
         if (!extension_loaded('gmp')) {
             throw new \ErrorException('64 bit integers not available, install GMP extension');
         }
         foreach (self::$_vendorList as &$entry) {
             $entry['address'] = gmp_init($entry['address'], 16);
             $entry['mask'] = (gmp_init(1) << $entry['mask']) - 1 << self::LENGTH_BITS - $entry['mask'];
         }
     } else {
         foreach (self::$_vendorList as &$entry) {
             $entry['address'] = hexdec($entry['address']);
             $entry['mask'] = (1 << $entry['mask']) - 1 << self::LENGTH_BITS - $entry['mask'];
         }
     }
     // @codeCoverageIgnoreEnd
 }
예제 #2
0
 /**
  * Load vendor database
  *
  * Clears the database and iterates over $input. Each entry of the form
  * "MAC_address[/bits] TAB short_name [whitespace # long_name]" gets parsed
  * and added to the database.
  *
  * @param array|\Traversable $input
  */
 public static function loadVendorDatabase($input)
 {
     self::$_vendorList = array();
     foreach ($input as $line) {
         /* This regular expression matches lines of the following pattern:
         
                        <MAC address><TAB><short name>[<whitespace># <long name>]
         
                        Matching lines leave $data as an array with exaxtly 5 elements:
                        [0] unused
                        [1] MAC address with optional mask suffix ("/36")
                        [2] short vendor name (used if [4] is empty)
                        [3] unused
                        [4] long vendor name or empty string
                     */
         if (!preg_match("/^(\\H+)\t(\\H+)\\h*(# )?(.*)/", $line, $data)) {
             continue;
         }
         // remove ':' and '-' delimiters
         $mac = str_replace(array(':', '-'), '', $data[1]);
         // extract bitmask if present
         $pos = strpos($mac, '/');
         if ($pos !== false) {
             $mask = substr($mac, $pos + 1);
             if ($mask % 4 != 0) {
                 // The precision of this string-based implementation is
                 // limited to 4 bits (1 hex digit). Entries with a number
                 // of mask bits that is not a multiple of 4 cannot be
                 // matched and are ignored.
                 if (\Library\Application::isDevelopment()) {
                     trigger_error("Ignoring MAC address {$data['1']} because mask is not a multiple of 4.", E_USER_NOTICE);
                 }
                 continue;
             }
             $numDigits = $mask / 4;
             $mac = substr($mac, 0, $pos);
             $mac = str_pad($mac, $numDigits, '0');
             // Fill with zeroes if too short
             $mac = substr($mac, 0, $numDigits);
             // Crop to maximun length if too long
         } else {
             $numDigits = strlen($mac);
         }
         self::$_vendorList[] = array('address' => strtoupper($mac), 'length' => $numDigits, 'vendor' => $data[4] ?: $data[2]);
     }
 }