예제 #1
0
파일: Bundled.php 프로젝트: horde/horde
 /**
  *
  * @param mixed $path  Filename -or- an open PHP stream.
  *
  * @return array
  */
 protected function _readData($path)
 {
     if (is_resource($path)) {
         $in = new Horde_Stream_Existing(array('stream' => $path));
         $in->rewind();
     } else {
         $in = new Horde_Stream_Existing(array('stream' => @fopen($path, 'rb')));
     }
     $globalOffset = 0;
     $result = array('Errors' => 0);
     // if the path was invalid, this error will catch it
     if (!$in) {
         $result['Errors'] = 1;
         $result['Error'][$result['Errors']] = Horde_Image_Translation::t("The file could not be opened.");
         return $result;
     }
     // First 2 bytes of JPEG are 0xFFD8
     $data = bin2hex($in->substring(0, 2));
     if ($data == 'ffd8') {
         $result['ValidJpeg'] = 1;
     } else {
         $result['ValidJpeg'] = 0;
         if (!is_resource($path)) {
             $in->close();
         }
         return $result;
     }
     $result['ValidIPTCData'] = 0;
     $result['ValidJFIFData'] = 0;
     $result['ValidEXIFData'] = 0;
     $result['ValidAPP2Data'] = 0;
     $result['ValidCOMData'] = 0;
     // Next 2 bytes are marker tag (0xFFE#)
     $data = bin2hex($in->substring(0, 2));
     $size = bin2hex($in->substring(0, 2));
     // Loop through markers till you get to FFE1 (Exif marker)
     while (!$in->eof() && $data != 'ffe1' && $data != 'ffc0' && $data != 'ffd9') {
         switch ($data) {
             case 'ffe0':
                 // JFIF Marker
                 $result['ValidJFIFData'] = 1;
                 $result['JFIF']['Size'] = hexdec($size);
                 if (hexdec($size) - 2 > 0) {
                     $data = $in->substring(0, hexdec($size) - 2);
                     $result['JFIF']['Data'] = $data;
                 }
                 $result['JFIF']['Identifier'] = substr($data, 0, 5);
                 $result['JFIF']['ExtensionCode'] = bin2hex(substr($data, 6, 1));
                 $globalOffset += hexdec($size) + 2;
                 break;
             case 'ffed':
                 // IPTC Marker
                 $result['ValidIPTCData'] = 1;
                 $result['IPTC']['Size'] = hexdec($size);
                 if (hexdec($size) - 2 > 0) {
                     $data = $in->substring(0, hexdec($size) - 2);
                     $result['IPTC']['Data'] = $data;
                 }
                 $globalOffset += hexdec($size) + 2;
                 break;
             case 'ffe2':
                 // EXIF extension Marker
                 $result['ValidAPP2Data'] = 1;
                 $result['APP2']['Size'] = hexdec($size);
                 if (hexdec($size) - 2 > 0) {
                     $data = $in->substring(0, hexdec($size) - 2);
                     $result['APP2']['Data'] = $data;
                 }
                 $globalOffset += hexdec($size) + 2;
                 break;
             case 'fffe':
                 // COM extension Marker
                 $result['ValidCOMData'] = 1;
                 $result['COM']['Size'] = hexdec($size);
                 if (hexdec($size) - 2 > 0) {
                     $data = $in->substring(0, hexdec($size) - 2);
                     $result['COM']['Data'] = $data;
                 }
                 $globalOffset += hexdec($size) + 2;
                 break;
             case 'ffe1':
                 $result['ValidEXIFData'] = 1;
                 break;
         }
         $data = bin2hex($in->substring(0, 2));
         $size = bin2hex($in->substring(0, 2));
     }
     if ($data != 'ffe1') {
         if (!is_resource($path)) {
             $in->close();
         }
         return $result;
     }
     $result['ValidEXIFData'] = 1;
     // Size of APP1
     $result['APP1Size'] = hexdec($size);
     // Start of APP1 block starts with 'Exif' header (6 bytes)
     $header = $in->substring(0, 6);
     // Then theres a TIFF header with 2 bytes of endieness (II or MM)
     $header = $in->substring(0, 2);
     switch ($header) {
         case 'II':
             $intel = 1;
             $result['Endien'] = 'Intel';
             break;
         case 'MM':
             $intel = 0;
             $result['Endien'] = 'Motorola';
             break;
         default:
             // not sure what the default should be, but this seems reasonable
             $intel = 1;
             $result['Endien'] = 'Unknown';
             break;
     }
     // 2 bytes of 0x002a
     if (bin2hex($in->substring(0, 2)) != '002a') {
         $result['Errors'] = $result['Errors'] + 1;
         $result['Error'][$result['Errors']] = 'Unexpected value.';
         return $result;
     }
     // Then 4 bytes of offset to IFD0 (usually 8 which includes all 8 bytes
     // of TIFF header)
     $offset = bin2hex($in->substring(0, 4));
     if ($intel == 1) {
         $offset = Horde_Image_Exif::intel2Moto($offset);
     }
     // Check for extremely large values here
     if (hexdec($offset) > 100000) {
         $result['ValidEXIFData'] = 0;
         if (!is_resource($path)) {
             $in->close();
         }
         return $result;
     }
     if (hexdec($offset) > 8) {
         $unknown = $in->substring(0, hexdec($offset) - 8);
     }
     // add 12 to the offset to account for TIFF header
     $globalOffset += 12;
     //===========================================================
     // Start of IFD0
     $num = bin2hex($in->substring(0, 2));
     if ($intel == 1) {
         $num = Horde_Image_Exif::intel2Moto($num);
     }
     $num = hexdec($num);
     $result['IFD0NumTags'] = $num;
     // 1000 entries is too much and is probably an error.
     if ($num < 1000) {
         for ($i = 0; $i < $num; $i++) {
             $this->_readEntry($result, $in, $intel, 'IFD0', $globalOffset);
         }
     } else {
         $result['Errors'] = $result['Errors'] + 1;
         $result['Error'][$result['Errors']] = 'Illegal size for IFD0';
     }
     // store offset to IFD1
     $offset = bin2hex($in->substring(0, 4));
     if ($intel == 1) {
         $offset = Horde_Image_Exif::intel2Moto($offset);
     }
     $result['IFD1Offset'] = hexdec($offset);
     // Check for SubIFD
     if (!isset($result['IFD0']['ExifOffset']) || $result['IFD0']['ExifOffset'] == 0) {
         if (!is_resource($path)) {
             $in->close();
         }
         return $result;
     }
     // seek to SubIFD (Value of ExifOffset tag) above.
     $ExifOffset = $result['IFD0']['ExifOffset'];
     if (!$in->seek($globalOffset + $ExifOffset, false)) {
         $result['Errors'] = $result['Errors'] + 1;
         $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Couldnt Find SubIFD");
     }
     //===========================================================
     // Start of SubIFD
     $num = bin2hex($in->substring(0, 2));
     if ($intel == 1) {
         $num = Horde_Image_Exif::intel2Moto($num);
     }
     $num = hexdec($num);
     $result['SubIFDNumTags'] = $num;
     // 1000 entries is too much and is probably an error.
     if ($num < 1000) {
         for ($i = 0; $i < $num; $i++) {
             $this->_readEntry($result, $in, $intel, 'SubIFD', $globalOffset);
         }
     } else {
         $result['Errors'] = $result['Errors'] + 1;
         $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Illegal size for SubIFD");
     }
     // Add the 35mm equivalent focal length:
     // Now properly get this using the FocalLength35mmFilm tag
     //$result['SubIFD']['FocalLength35mmEquiv'] = get35mmEquivFocalLength($result);
     // Check for IFD1
     if (!isset($result['IFD1Offset']) || $result['IFD1Offset'] == 0) {
         if (!is_resource($path)) {
             $in->close();
         }
         return $result;
     }
     // seek to IFD1
     if (!$in->seek($globalOffset + $result['IFD1Offset'], false)) {
         $result['Errors'] = $result['Errors'] + 1;
         $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Couldnt Find IFD1");
     }
     //===========================================================
     // Start of IFD1
     $num = bin2hex($in->substring(0, 2));
     if ($intel == 1) {
         $num = Horde_Image_Exif::intel2Moto($num);
     }
     $num = hexdec($num);
     $result['IFD1NumTags'] = $num;
     // 1000 entries is too much and is probably an error.
     if ($num < 1000) {
         for ($i = 0; $i < $num; $i++) {
             $this->_readEntry($result, $in, $intel, 'IFD1', $globalOffset);
         }
     } else {
         $result['Errors'] = $result['Errors'] + 1;
         $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Illegal size for IFD1");
     }
     // include the thumbnail raw data...
     if ($result['IFD1']['JpegIFOffset'] > 0 && $result['IFD1']['JpegIFByteCount'] > 0) {
         $cpos = $in->pos();
         if ($in->seek($globalOffset + $result['IFD1']['JpegIFOffset'], false)) {
             $data = $in->substring(0, $result['IFD1']['JpegIFByteCount']);
         } else {
             $result['Errors'] = $result['Errors'] + 1;
         }
         $result['IFD1']['ThumbnailData'] = $data;
     }
     // Check for Interoperability IFD
     if (!isset($result['SubIFD']['ExifInteroperabilityOffset']) || $result['SubIFD']['ExifInteroperabilityOffset'] == 0) {
         if (!is_resource($path)) {
             $in->close();
         }
         return $result;
     }
     // Seek to InteroperabilityIFD
     if (!$in->seek($globalOffset + $result['SubIFD']['ExifInteroperabilityOffset'], false)) {
         $result['Errors'] = $result['Errors'] + 1;
         $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Couldnt Find InteroperabilityIFD");
     }
     //===========================================================
     // Start of InteroperabilityIFD
     $num = bin2hex($in->substring(0, 2));
     if ($intel == 1) {
         $num = Horde_Image_Exif::intel2Moto($num);
     }
     $num = hexdec($num);
     $result['InteroperabilityIFDNumTags'] = $num;
     // 1000 entries is too much and is probably an error.
     if ($num < 1000) {
         for ($i = 0; $i < $num; $i++) {
             $this->_readEntry($result, $in, $intel, 'InteroperabilityIFD', $globalOffset);
         }
     } else {
         $result['Errors'] = $result['Errors'] + 1;
         $result['Error'][$result['Errors']] = Horde_Image_Translation::t("Illegal size for InteroperabilityIFD");
     }
     if (!is_resource($path)) {
         $in->close();
     }
     return $result;
 }