📄 exif.php
字号:
{
// Huge number of entries - abort
echo "<p>Error: huge number of EXIF entries - EXIF is probably Corrupted</p>\n";
return array ( FALSE , 0);
}
// If the data is corrupt or just stupid, the number of entries may zero,
// Indicate this by returning false
if ( $No_Entries === 0 )
{
// No entries - abort
return array ( FALSE , 0);
}
// Save the file position where first IFD record starts as non-standard offsets
// need to know this to calculate an absolute offset
$IFD_first_rec_pos = ftell( $filehnd );
// Read in the IFD structure
$IFD_Data = network_safe_fread( $filehnd, 12 * $No_Entries );
// Check if the entire IFD was able to be read
if ( strlen( $IFD_Data ) != (12 * $No_Entries) )
{
// Couldn't read the IFD Data properly, Some Casio files have no Next IFD pointer, hence cause this error
echo "<p>Error: EXIF Corrupted</p>\n";
return array(FALSE, 0);
}
// Last 4 bytes of a standard IFD are the offset to the next IFD
// Some NON-Standard IFD implementations do not have this, hence causing problems if it is read
// If the Next IFD pointer has been requested to be read,
if ( $read_next_ptr )
{
// Read the pointer to the next IFD
$Next_Offset_str = network_safe_fread( $filehnd, 4 );
$Next_Offset = get_IFD_Data_Type( $Next_Offset_str, 4, $Byte_Align );
}
else
{
// Otherwise set the pointer to zero ( no next IFD )
$Next_Offset = 0;
}
// Initialise current position to the start
$pos = 0;
// Loop for reading IFD entries
for ( $i = 0; $i < $No_Entries; $i++ )
{
// First 2 bytes of IFD entry are the tag number ( Unsigned Short )
$Tag_No_str = substr( $IFD_Data, $pos, 2 );
$Tag_No = get_IFD_Data_Type( $Tag_No_str, 3, $Byte_Align );
$pos += 2;
// Next 2 bytes of IFD entry are the data format ( Unsigned Short )
$Data_Type_str = substr( $IFD_Data, $pos, 2 );
$Data_Type = get_IFD_Data_Type( $Data_Type_str, 3, $Byte_Align );
$pos += 2;
// If Datatype is not between 1 and 12, then skip this entry, it is probably corrupted or custom
if (( $Data_Type > 12 ) || ( $Data_Type < 1 ) )
{
$pos += 8;
continue 1; // Stop trying to process the tag any further and skip to the next one
}
// Next 4 bytes of IFD entry are the data count ( Unsigned Long )
$Data_Count_str = substr( $IFD_Data, $pos, 4 );
$Data_Count = get_IFD_Data_Type( $Data_Count_str, 4, $Byte_Align );
$pos += 4;
if ( $Data_Count > 100000 )
{
echo "<p>Error: huge EXIF data count - EXIF is probably Corrupted</p>\n";
// Some Casio files have no Next IFD pointer, hence cause errors
return array ( FALSE , 0);
}
// Total Data size is the Data Count multiplied by the size of the Data Type
$Total_Data_Size = $GLOBALS['IFD_Data_Sizes'][ $Data_Type ] * $Data_Count;
$Data_Start_pos = -1;
// If the total data size is larger than 4 bytes, then the data part is the offset to the real data
if ( $Total_Data_Size > 4 )
{
// Not enough room for data - offset provided instead
$Data_Offset_str = substr( $IFD_Data, $pos, 4 );
$Data_Start_pos = get_IFD_Data_Type( $Data_Offset_str, 4, $Byte_Align );
// In some NON-STANDARD makernotes, the offset is relative to the start of the current IFD entry
if ( $local_offsets )
{
// This is a NON-Standard IFD, seek relative to the start of the current tag
fseek( $filehnd, $IFD_first_rec_pos + $pos - 8 + $Data_Start_pos );
}
else
{
// This is a normal IFD, seek relative to the start of the TIFF header
fseek( $filehnd, $Tiff_offset + $Data_Start_pos );
}
// Read the data block from the offset position
$DataStr = network_safe_fread( $filehnd, $Total_Data_Size );
}
else
{
// The data block is less than 4 bytes, and is provided in the IFD entry, so read it
$DataStr = substr( $IFD_Data, $pos, $Total_Data_Size );
}
// Increment the position past the data
$pos += 4;
// Now create the entry for output array
$Data_Array = array( );
// Read the data items from the data block
if ( ( $Data_Type != 2 ) && ( $Data_Type != 7 ) )
{
// The data type is Numerical, Read the data items from the data block
for ( $j = 0; $j < $Data_Count; $j++ )
{
$Part_Data_Str = substr( $DataStr, $j * $GLOBALS['IFD_Data_Sizes'][ $Data_Type ], $GLOBALS['IFD_Data_Sizes'][ $Data_Type ] );
$Data_Array[] = get_IFD_Data_Type( $Part_Data_Str, $Data_Type, $Byte_Align );
}
}
elseif ( $Data_Type == 2 )
{
// The data type is String(s) (type 2)
// Strip the last terminating Null
$DataStr = substr( $DataStr, 0, strlen($DataStr)-1 );
// Split the data block into multiple strings whereever there is a Null
$Data_Array = explode( "\x00", $DataStr );
}
else
{
// The data type is Unknown (type 7)
// Do nothing to data
$Data_Array = $DataStr;
}
// If this is a Sub-IFD entry,
if ( ( array_key_exists( $Tag_No, $GLOBALS[ "IFD_Tag_Definitions" ][$Tag_Definitions_Name] ) ) &&
( "SubIFD" == $GLOBALS[ "IFD_Tag_Definitions" ][$Tag_Definitions_Name][ $Tag_No ]['Type'] ) )
{
// This is a Sub-IFD entry, go and process the data forming Sub-IFD and use its output array as the new data for this entry
fseek( $filehnd, $Tiff_offset + $Data_Array[0] );
$Data_Array = read_Multiple_IFDs( $filehnd, $Tiff_offset, $Byte_Align, $GLOBALS[ "IFD_Tag_Definitions" ][$Tag_Definitions_Name][ $Tag_No ]['Tags Name'] );
}
$desc = "";
$units = "";
// Check if this tag exists in the list of tag definitions,
if ( array_key_exists ( $Tag_No, $GLOBALS[ "IFD_Tag_Definitions" ][$Tag_Definitions_Name]) )
{
if ( array_key_exists ( 'Description', $GLOBALS[ "IFD_Tag_Definitions" ][$Tag_Definitions_Name][ $Tag_No ] ) )
{
$desc = $GLOBALS[ "IFD_Tag_Definitions" ][$Tag_Definitions_Name][ $Tag_No ]['Description'];
}
if ( array_key_exists ( 'Units', $GLOBALS[ "IFD_Tag_Definitions" ][$Tag_Definitions_Name][ $Tag_No ] ) )
{
$units = $GLOBALS[ "IFD_Tag_Definitions" ][$Tag_Definitions_Name][ $Tag_No ]['Units'];
}
// Tag exists in definitions, append details to output array
$OutputArray[ $Tag_No ] = array ( "Tag Number" => $Tag_No,
"Tag Name" => $GLOBALS[ "IFD_Tag_Definitions" ][$Tag_Definitions_Name][ $Tag_No ]['Name'],
"Tag Description" => $desc,
"Data Type" => $Data_Type,
"Type" => $GLOBALS[ "IFD_Tag_Definitions" ][$Tag_Definitions_Name][ $Tag_No ]['Type'],
"Units" => $units,
"Data" => $Data_Array );
}
else
{
// Tag doesnt exist in definitions, append unknown details to output array
$OutputArray[ $Tag_No ] = array ( "Tag Number" => $Tag_No,
"Tag Name" => "Unknown Tag #" . $Tag_No,
"Tag Description" => "",
"Data Type" => $Data_Type,
"Type" => "Unknown",
"Units" => "",
"Data" => $Data_Array );
}
// Some information of type "Unknown" (type 7) might require information about
// how it's position and byte alignment in order to be decoded
if ( $Data_Type == 7 )
{
$OutputArray[ $Tag_No ]['Offset'] = $Data_Start_pos;
$OutputArray[ $Tag_No ]['Byte Align'] = $Byte_Align;
}
////////////////////////////////////////////////////////////////////////
// Special Data handling
////////////////////////////////////////////////////////////////////////
// Check if this is a Print Image Matching entry
if ( $OutputArray[ $Tag_No ]['Type'] == "PIM" )
{
// This is a Print Image Matching entry, decode it.
$OutputArray[ $Tag_No ] = Decode_PIM( $OutputArray[ $Tag_No ], $Tag_Definitions_Name );
}
// Interpret the entry into a text string using a custom interpreter
$text_val = get_Tag_Text_Value( $OutputArray[ $Tag_No ], $Tag_Definitions_Name );
// Check if a text string was generated
if ( $text_val !== FALSE )
{
// A string was generated, append it to the output array entry
$OutputArray[ $Tag_No ]['Text Value'] = $text_val;
$OutputArray[ $Tag_No ]['Decoded'] = TRUE;
}
else
{
// A string was NOT generated, append a generic string to the output array entry
$OutputArray[ $Tag_No ]['Text Value'] = get_IFD_value_as_text( $OutputArray[ $Tag_No ] ) . " " . $units;
$OutputArray[ $Tag_No ]['Decoded'] = FALSE;
}
// Check if this entry is the Maker Note
if ( ( $Tag_Definitions_Name == "EXIF" ) && ( $Tag_No == 37500 ) )
{
// Save some extra information which will allow Makernote Decoding with the output array entry
$OutputArray[ $Tag_No ]['Offset'] = $Data_Start_pos;
$OutputArray[ $Tag_No ][ 'Tiff Offset' ] = $Tiff_offset;
$OutputArray[ $Tag_No ]['ByteAlign'] = $Byte_Align;
// Save a pointer to this entry for Maker note processing later
$GLOBALS[ "Maker_Note_Tag" ] = & $OutputArray[ $Tag_No ];
}
// Check if this is a IPTC/NAA Record within the EXIF IFD
if ( ( ( $Tag_Definitions_Name == "EXIF" ) || ( $Tag_Definitions_Name == "TIFF" ) ) &&
( $Tag_No == 33723 ) )
{
// This is a IPTC/NAA Record, interpret it and put result in the data for this entry
$OutputArray[ $Tag_No ]['Data'] = get_IPTC( $DataStr );
$OutputArray[ $Tag_No ]['Decoded'] = TRUE;
}
// Change: Check for embedded XMP as of version 1.11
// Check if this is a XMP Record within the EXIF IFD
if ( ( ( $Tag_Definitions_Name == "EXIF" ) || ( $Tag_Definitions_Name == "TIFF" ) ) &&
( $Tag_No == 700 ) )
{
// This is a XMP Record, interpret it and put result in the data for this entry
$OutputArray[ $Tag_No ]['Data'] = read_XMP_array_from_text( $DataStr );
$OutputArray[ $Tag_No ]['Decoded'] = TRUE;
}
// Change: Check for embedded IRB as of version 1.11
// Check if this is a Photoshop IRB Record within the EXIF IFD
if ( ( ( $Tag_Definitions_Name == "EXIF" ) || ( $Tag_Definitions_Name == "TIFF" ) ) &&
( $Tag_No == 34377 ) )
{
// This is a Photoshop IRB Record, interpret it and put result in the data for this entry
$OutputArray[ $Tag_No ]['Data'] = unpack_Photoshop_IRB_Data( $DataStr );
$OutputArray[ $Tag_No ]['Decoded'] = TRUE;
}
// Exif Thumbnail
// Check that both the thumbnail length and offset entries have been processed,
// and that this is one of them
if ( ( ( ( $Tag_No == 513 ) && ( array_key_exists( 514, $Ou
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -