Coding standards
Security in ResourceSpace
Developer reference
Database
Action functions
Admin functions
Ajax functions
Annotation functions
API functions
Collections functions
Comment functions
Config functions
CSV export functions
Dash functions
Debug functions
Encryption functions
Facial recognition functions
File functions
General functions
Language functions
Log functions
Login functions
Message functions
Migration functions
Node functions
PDF functions
Plugin functions
Render functions
Reporting functions
Request functions
Research functions
Slideshow functions
Theme permission functions
User functions
Video functions
Database functions
Metadata functions
Resource functions
Search functions
Map functions
Job functions
Tab functions
Test functions

write_metadata()

Description

Writes metadata to a specified file using ExifTool.

Parameters

ColumnTypeDefaultDescription
$path string The file path where the metadata will be written.
$ref int The reference ID of the resource associated with the file.
$uniqid string "" A unique identifier for the temporary file location (optional).

Return

string|bool The path to the temporary file if successful, false otherwise.

Location

include/resource_functions.php lines 4599 to 4796

Definition

 
function write_metadata($path$ref$uniqid="")
    {
    
debug_function_call('write_metadata'func_get_args());

    if (!
is_valid_rs_path($path)) {
        
// Not a valid path to a ResourceSpace file source
        
return false;
    }

    
// copys the file to tmp and runs exiftool on it
    // uniqid tells the tmp file to be placed in an isolated folder within tmp
    
global $exiftool_remove_existing$storagedir$exiftool_write$exiftool_write_option$exiftool_no_process$mysql_charset$exiftool_write_omit_utf8_conversion;

    
# Fetch file extension and resource type.
    
$resource_data=get_resource_data($ref);
    
$extension=$resource_data["file_extension"];

    
$exiftool_fullpath get_utility_path("exiftool");

    
# Check if an attempt to write the metadata shall be performed.
    
if(false != $exiftool_fullpath && $exiftool_write && $exiftool_write_option && !in_array($extension$exiftool_no_process))
        {
        
debug("[write_metadata()][ref={$ref}] Attempting to write metadata...");
        
// Trust Exiftool's list of writable formats
        
$writable_formats run_command("{$exiftool_fullpath} -listwf");
        
$writable_formats str_replace("\n"""$writable_formats);
        
$writable_formats_array explode(" "$writable_formats);
        if(!
in_array(strtoupper((string) $extension), $writable_formats_array))
            {
            
debug("[write_metadata()][ref={$ref}] Extension '{$extension}' not in writable_formats_array - " json_encode($writable_formats_array));
            return 
false;
            }

        
$tmpfile createTempFile($path$uniqid'');
        if(
$tmpfile === false)
            {
            
debug("[write_metadata()][ref={$ref}] Unable to create temp file!");
            return 
false;
            }

        
# Add the call to exiftool and some generic arguments to the command string.
        # Argument -overwrite_original: Now that we have already copied the original file, we can use exiftool's overwrite_original on the tmpfile.
        # Argument -E: Escape values for HTML. Used for handling foreign characters in shells not using UTF-8.
        # Arguments -EXIF:all= -XMP:all= -IPTC:all=: Remove the metadata in the tag groups EXIF, XMP and IPTC.
        
$command $exiftool_fullpath " -m -overwrite_original -E ";
        if(
$exiftool_remove_existing)
            {
            
$command stripMetadata(null) . ' ';
            
debug("[write_metadata()][ref={$ref}] Removing existing metadata. Command: "json_encode($command));
            }

        
$metadata_all=get_resource_field_data($reffalse,true,null,getval("k","")!=""); // Using get_resource_field_data means we honour field permissions
        
$read_only_fields array_column(array_filter($metadata_all, function($value) {
            return (bool) 
$value['read_only'] == true;
        }), 
'ref');

        
$write_to=array();
        foreach(
$metadata_all as $metadata_item)
            {
            if(
trim($metadata_item["exiftool_field"]??"") != "" && !in_array($metadata_item['ref'], $read_only_fields))
                {
                
$write_to[] = $metadata_item;
                }
            }

        
$writtenfields=array(); // Need to check if we are writing to an embedded field from more than one RS field, in which case subsequent values need to be appended, not replaced

        
for($i 0$i<count($write_to); $i++) # Loop through all the found fields.
        
{
            
$fieldtype $write_to[$i]['type'];
            
$writevalue $write_to[$i]['value']??"";
            
# Formatting and cleaning of the value to be written - depending on the RS field type.
            
switch ($fieldtype)
                {
                case 
2:
                case 
3:
                case 
9:
                case 
12:
                    
# Check box list, drop down, radio buttons or dynamic keyword list: remove initial comma if present
                    
$writevalue strip_leading_comma($writevalue);
                    break;
                case 
4:
                case 
6:
                case 
10:
                    
# Date / Expiry Date: write datetype fields in exiftool preferred format
                    
if($writevalue!='')
                        {
                        
$writevalue_to_time=strtotime($writevalue);
                        if(
$writevalue_to_time!='')
                            {
                            
$writevalue date("Y:m:d H:i:sP"strtotime($writevalue));
                            }
                        }
                    break;
                    
# Other types, already set
                
}
            
$filtervalue=hook("additionalmetadatafilter""", [$write_to[$i]["exiftool_field"], $writevalue]);
            if (
$filtervalue) {
                
$writevalue $filtervalue;
            }
            
# Add the tag name(s) and the value to the command string.
            
$group_tags explode(","$write_to[$i]['exiftool_field']); # Each 'exiftool field' may contain more than one tag.
            
foreach ($group_tags as $group_tag)
                {
                
$group_tag strtolower($group_tag); # E.g. IPTC:Keywords -> iptc:keywords
                
if (strpos($group_tag,":")===false) {$tag $group_tag;} # E.g. subject -> subject
                
else {$tag substr($group_tagstrpos($group_tag,":")+1);} # E.g. iptc:keywords -> keywords
                
if(strpos($group_tag,"-") !== false && stripos($group_tag,"xmp") !== false)
                    {
                    
// Remove the XMP namespace for XMP data if included
                    
$group_tag substr($group_tag,0,(strpos($group_tag,"-")));
                    }
                
$exifappend=false// Need to replace values by default
                
if(isset($writtenfields[$group_tag]))
                    {
                    
// This embedded field is already being updated, we need to append values from this field
                    
$exifappend=true;
                    
debug("write_metadata - more than one field mapped to the tag '" $group_tag "'. Enabling append mode for this tag. ");
                    }

                switch (
$tag)
                    {
                    case 
"filesize":
                        
# Do nothing, no point to try to write the filesize.
                        
break;
                    case 
"filename":
                        
# Do nothing, no point to try to write the filename either as ResourceSpace controls this.
                        
break;
                    case 
"directory":
                        
# Do nothing, we don't want metadata to control this
                        
break;
                    case 
"keywords":
                        if(
substr($group_tag,0,3) != "xmp")
                            {
                            
# Only IPTC Keywords are a list type - these are written one at a time and not all together.
                            
if(!isset($writtenfields["keywords"])){$writtenfields["keywords"]="";}
                            
$keywords explode(","$writevalue); # "keyword1,keyword2, keyword3" (with or without spaces)
                            
if (implode(""$keywords) != "")
                                {
                                
# Only write non-empty keywords/ may be more than one field mapped to keywords so we don't want to overwrite with blank
                                
foreach ($keywords as $keyword)
                                    {
                                    
$keyword trim($keyword);
                                    if (
$keyword != "")
                                        {
                                        
debug("[write_metadata()][ref={$ref}] Writing keyword '{$keyword}'");
                                        
$writtenfields["keywords"].="," $keyword;
                                        
# Convert the data to UTF-8 if not already.
                                        
if (!$exiftool_write_omit_utf8_conversion && (!isset($mysql_charset) || (isset($mysql_charset) && strtolower($mysql_charset)!="utf8"))){$keyword mb_convert_encoding($keywordmb_detect_encoding($keyword), 'UTF-8');}
                                        
$command.= escapeshellarg("-" $group_tag "-=" htmlentities($keywordENT_QUOTES"UTF-8")) . " "// In case value is already embedded, need to manually remove it to prevent duplication
                                        
$command.= escapeshellarg("-" $group_tag "+=" htmlentities($keywordENT_QUOTES"UTF-8")) . " ";
                                        }
                                    }
                                }
                            break; 
// The break is in here so that Non-IPTC keywords continue to be handled by default
                            
}
                    default:
                        if(
$exifappend && ($writevalue=="" || ($writevalue!="" && strpos($writtenfields[$group_tag],$writevalue)!==false)))
                            {
                            
// The new value is blank or already included in what is being written, skip to next group tag
                            
continue 2# @see https://www.php.net/manual/en/control-structures.continue.php note
                            
}
                        
$writtenfields[$group_tag]=$writevalue;
                        
debug("[write_metadata()][ref={$ref}] Updating tag '{$group_tag}' with value '{$writevalue}'");
                        
# Write as is, convert the data to UTF-8 if not already.

                        
global $strip_rich_field_tags;
                        if (!
$exiftool_write_omit_utf8_conversion
                            
&& (!isset($mysql_charset)
                                || (isset(
$mysql_charset) && strtolower($mysql_charset)!="utf8")))
                            {
                            
$writevalue mb_convert_encoding($writevaluemb_detect_encoding($writevalue), 'UTF-8');
                            }
                            if (
$strip_rich_field_tags)
                            {
                                
$command.= escapeshellarg("-" $group_tag "=" trim(strip_tags(i18n_get_translated($writevalue)))) . " ";
                            }
                            else
                            {
                                
$command.= escapeshellarg("-" $group_tag "=" htmlentities(i18n_get_translated($writevalue), ENT_QUOTES"UTF-8")) . " ";
                            }
                    }
                }
            }

            
# Add the filename to the command string.
            
$command.= " " escapeshellarg($tmpfile);

            
# Perform the actual writing - execute the command string.
            
run_command($command);
        return 
$tmpfile;
       }
    else
        {
        
debug("[write_metadata()][ref={$ref}] Did not perform - write metadata!");
        return 
false;
        }
    }

This article was last updated 17th November 2024 15:05 Europe/London time based on the source file dated 15th November 2024 18:30 Europe/London time.