Example #1
0
 private static function decElement($data, &$offset)
 {
     $sig = ord($data[$offset]);
     $offset++;
     $name = Util::parseCString($data, $offset);
     switch ($sig) {
         case self::ETYPE_ID:
             $binId = Util::unpack('a12id', $data, $offset, 12)['id'];
             $value = new \MongoId(str_pad(bin2hex($binId), 24, '0'));
             break;
         case self::ETYPE_STRING:
         case self::ETYPE_SYMBOL:
             $len = Util::unpack('Vlen', $data, $offset, 4)['len'];
             $value = substr($data, $offset, $len - 1);
             // subtract 1 for nul-terminator
             $offset += $len;
             break;
         case self::ETYPE_ARRAY:
         case self::ETYPE_DOCUMENT:
             $value = self::decDocument($data, $offset);
             break;
         case self::ETYPE_INT32:
             $value = Util::unpack('lint', $data, $offset, 4)['int'];
             break;
         case self::ETYPE_BOOL:
             $value = Util::unpack('C', $data, $offset, 1);
             if ($value[1]) {
                 $value = true;
             } else {
                 $value = false;
             }
             break;
         case self::ETYPE_UNDEF:
         case self::ETYPE_NULL:
             $value = null;
             break;
         case self::ETYPE_INT64:
             $vars = Util::unpack('V2i', $data, $offset, 8);
             $value = $vars['i1'] | $vars['i2'] << 32;
             break;
         case self::ETYPE_DOUBLE:
             $value = Util::unpack('ddouble', $data, $offset, 8)['double'];
             break;
         case self::ETYPE_CODE_W_S:
             $offset += 4;
             // skip whole element size int
         // skip whole element size int
         case self::ETYPE_CODE:
             $scope = [];
             $len = Util::unpack('Vlen', $data, $offset, 4)['len'];
             $code = substr($data, $offset, $len - 1);
             // subtract 1 for nul-terminator
             $offset += $len;
             if ($sig === self::ETYPE_CODE_W_S) {
                 $scope = self::decDocument($data, $offset);
             }
             $value = new \MongoCode($code, $scope);
             break;
         case self::ETYPE_REGEX:
             $regex = Util::parseCString($data, $offset);
             $flags = Util::parseCString($data, $offset);
             $value = new \MongoRegex('/' . $regex . '/' . $flags);
             break;
         case self::ETYPE_DATE:
             $vars = Util::unpack('V2i', $data, $offset, 8);
             $ms = ($vars['i2'] << 32) + $vars['i1'];
             $value = \MongoDate::createFromMs($ms);
             break;
         case self::ETYPE_TIMESTAMP:
             $vars = Util::unpack('V2i', $data, $offset, 8);
             $value = new \MongoTimestamp($vars['i2'], $vars['i1']);
             break;
         case self::ETYPE_BINARY:
             $vars = Util::unpack('Vlen/Csubtype', $data, $offset, 5);
             $len = $vars['len'];
             $subtype = $vars['subtype'];
             if ($subtype == 2) {
                 // binary subtype 2 special case
                 $len2 = Util::unpack('Vlen', $data, $offset, 4)['len'];
                 if ($len2 == $len - 4) {
                     $len = $len2;
                 } else {
                     // something is not right, restore offset
                     $offset -= 4;
                 }
             }
             if ($len < 0) {
                 throw new \RuntimeException(sprintf('invalid binary length for key "%s": %d', $name, $len), 22);
             }
             $bin = substr($data, $offset, $len);
             $value = new \MongoBinData($bin, $subtype);
             $offset += strlen($bin);
             break;
         case self::ETYPE_MAXKEY:
             $value = new \MongoMaxKey();
             break;
         case self::ETYPE_MINKEY:
             $value = new \MongoMinKey();
             break;
         default:
             throw new \RuntimeException('Invalid signature: 0x' . dechex($sig));
     }
     return [$name, $value];
 }