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

process_collection_download()

Description

Generate a collection download ZIP file and the download filename

This array will be updated and passed to subsidiary functions to keep track of processed file, generate text etc.
Could be moved to an object later
[
"filename" => [the name of download file],
"collection" => [Collection ID],
"collection_resources" => [Resources to include in download],
"collectiondata" => [Collection data - from get_collection()],
"exiftool_write_option" => [Write exif data?],
"useoriginal" => [Use original if requested size not available?],
"size" => [Requested Download size ID],
"settings_id" => [Index of selected option from $collection_download_settings],
"deletion_array" => [Array of paths to delete],
"include_csv_file" => [Include metadata CSV file?],
"include_alternatives" => [Include alternative files?],
"includetext" => Include text file?,
"collection_download_tar" => [Generate a TAR file?],
"count_data_only_types" => [Count of data only resources],
"id" => [Optional unique identifier - [used to create a download.php link that is specific to the user],
"k" => External access key from download request if set
];

[
"filename" => [the name of download file],
"path" => [path to the zip file],
"completed" => [Set to true if a tar has been sent],
];

Parameters

ColumnTypeDefaultDescription
$dl_data: array
'collection_download_tar'
'include_alternatives'
as 'k']
$dl_data array Array of collection download options passed from collection_download.php or from the offline job

Return

array Array of data about the created file and the download file nam, or the TAR status i.e.

Location

include/collections_functions.php lines 6548 to 6951

Definition

 
function process_collection_download(array $dl_data): array
{
    
// Set eleemnts that may not have been set e.g. a job created in an earlier version
    
foreach (['archiver''collection_download_tar''include_alternatives''k'] as $unset_var)
    if (!isset(
$dl_data[$unset_var])) {
        
$dl_data[$unset_var] = false;
    }

    
$collection                 = (int) ($dl_data['collection'] ?? 0);
    
$collectiondata             $dl_data['collectiondata'] ?? [];
    
// Please note re: collection_resources - the current collection resources are not retrieved here as
    // these may have changed since the download was requested. Used to be stored as "result" element
    
$collection_resources       $dl_data['collection_resources'] ?? ($dl_data['result'] ?? []);
    
$size                       = (string) ($dl_data['size'] ?? "");
    
$useoriginal                = (bool) ($dl_data['useoriginal'] ?? false);
    
$id                         = (string) ($dl_data['id'] ?? uniqid("Col" $collection));
    
$includetext                = (bool) ($dl_data['includetext'] ?? false);
    
$count_data_only_types      = (int) ($dl_data['count_data_only_types'] ?? 0);
    
$settings_id                = (string) ($dl_data['settings_id'] ?? "");
    
$include_csv_file           = (bool) ($dl_data['include_csv_file'] ?? false);
    
$include_alternatives       = (bool) ($dl_data['include_alternatives'] ?? false);
    
$collection_download_tar    = (bool) ($dl_data['collection_download_tar'] ?? false);
    
$archiver                   = (bool) ($dl_data["archiver"] ?? false);
    
// Set this as global -  required by write_metadata()
    
global $exiftool_write_option;
    
$saved_exiftool_write_option $exiftool_write_option;
    
$exiftool_write_option $dl_data['exiftool_write_option'];

    if (empty(
$collectiondata) && $collection 0) {
        
$collectiondata get_collection($collection);
    }
    if (
        empty(
$collectiondata)
        || empty(
$collection_resources)
        || !isset(
$GLOBALS["userref"]) // Downloads need to be linked to a user
    
) {
        
debug("Missing collection data, Unable to proceed with collection download");
        return [];
    }

    
$zip false;
    if (!
$collection_download_tar) {    
        
// Generate a randomised path for zip file
        
$extension $archiver $GLOBALS["collection_download_settings"][$settings_id]["extension"] : "zip";
        
$zipfile get_temp_dir(false'user_downloads') . DIRECTORY_SEPARATOR $GLOBALS["userref"] . "_" md5($GLOBALS["username"] . $id $GLOBALS["scramble_key"]) . "." $extension;
        
debug('Collection download : $zipfile =' $zipfile);
        if (
$GLOBALS['use_zip_extension']) {
            
$zip = new ZipArchive();
            
$zip->open($zipfileZIPARCHIVE::CREATE);
        }
    }

    
$dl_data['includefiles'] = []; // Store array of files to include in download
    
$dl_data['deletion_array'] = [];
    
$dl_data['filenames'] = []; // Set up an array to store the filenames as they are found (to analyze dupes)
    
$dl_data['used_resources'] = [];
    
$dl_data['subbed_original_resources'] = [];
    
$allsizes get_all_image_sizes(true);
    
$rescount count($collection_resources);

    if (
$includetext) { 
        
// Initiate text file
        
$dl_data['text'] = i18n_get_collection_name($collectiondata) . "\r\n" .
        
$GLOBALS["lang"]["downloaded"] . " " nicedate(date("Y-m-d H:i:s"), truetrue) . "\r\n\r\n" .
        
$GLOBALS["lang"]["contents"] . ":\r\n\r\n";
        if (
$size == "") {
            
$dl_data['sizetext'] = "";
        } else {
            
$dl_data['sizetext'] = "-" $size;
        }
    }

    
db_begin_transaction("collection_download"); // Ensure all log updates are committed at once
    
for ($n 0$n $rescount$n++) {
        
// Set a flag to indicate whether file should be included
        
$skipresource false
        if (!isset(
$collection_resources[$n]['resource_type'])) {
            
// Resource data is not present - e.g. an offline job
            
$collection_resources[$n] = get_resource_data($collection_resources[$n]["ref"]);
            
$dl_data['collection_resources'][$n] = $collection_resources[$n]; // Update so will be passed to other functions
        
}
        
resource_type_config_override($collection_resources[$n]['resource_type'], false); # False means execute override for every resource

        
$copy false;
        
$ref $collection_resources[$n]['ref'];
        
$access get_resource_access($collection_resources[$n]);
        
$use_watermark check_use_watermark();
        
$subbed_original false;

        
// Do not download resources without proper access level
        
if ($access 1) {
            
debug('Collection download : skipping resource ID ' $ref ' user ID ' $GLOBALS["userref"] . ' does not have access to this resource');
            continue;
        }

        
// Get all possible sizes for this resource. 
        // If largest available has been requested then include internal or user could end up with no file depite being able to see the preview
        
$sizes array_filter($allsizes, function ($availsize) use ($access$size) {
            return 
                (
$availsize["allow_restricted"] || $access === 0)
                && ((int) 
$availsize["internal"] === || $size == "largest");
        });

        
# Check availability of original file
        
$p get_resource_path($reftrue""false$collection_resources[$n]["file_extension"]);
        if (
            
file_exists($p
            && ((
$access == 0) || ($access == && $GLOBALS["restricted_full_download"]))
            && 
resource_download_allowed($ref''$collection_resources[$n]['resource_type'], -1true)
        ) {
            
$dl_data['available_sizes']['original'][] = $ref;
        }

        
// Check for the availability of each size and load it to the available_sizes array
        
foreach ($sizes as $sizeinfo) {
            if (
in_array($collection_resources[$n]['file_extension'], $GLOBALS["ffmpeg_supported_extensions"])) {
                
$size_id $sizeinfo['id'];
                
// Video files only have a 'pre' sized derivative so flesh out the sizes array using that.
                
$p get_resource_path($reftrue'pre'false$collection_resources[$n]['file_extension']);
                
$size_id 'pre';
                if (
                    
resource_download_allowed($ref$size_id$collection_resources[$n]['resource_type'], -1true)
                    &&
                    (
                        
hook('size_is_available''', array($collection_resources[$n], $p$size_id))
                        || 
file_exists($p)
                    )
                ) {
                    
$dl_data['available_sizes'][$sizeinfo['id']][] = $ref;
                }
            } elseif (
in_array($collection_resources[$n]['file_extension'], array_merge($GLOBALS["ffmpeg_audio_extensions"], ['mp3']))) {
                
// Audio files are ported to mp3 and do not have different preview sizes
                
$p get_resource_path($reftrue''false'mp3');
                if (
                    
resource_download_allowed($ref''$collection_resources[$n]['resource_type'], -1true)
                    &&
                    (
                        
hook('size_is_available''', array($collection_resources[$n], $p''))
                        || 
file_exists($p)
                    )
                ) {
                        
$dl_data['available_sizes'][$sizeinfo['id']][] = $ref;
                }
            } else {
                
$size_id $sizeinfo['id'];
                
$size_extension get_extension($collection_resources[$n], $size_id);
                
$p get_resource_path($reftrue$size_idfalse$size_extension);
                if (
                    
resource_download_allowed($ref$size_id$collection_resources[$n]['resource_type'], -1true)
                    &&
                    (
                        
hook('size_is_available''', array($collection_resources[$n], $p$size_id))
                        || 
file_exists($p)
                    )
                ) {
                    
$dl_data['available_sizes'][$size_id][] = $ref;
                }
            }
        }

        
// Check which size to use
        
if ($size == "largest") {
            foreach (
$dl_data['available_sizes'] as $available_size => $resources) {
                if (
in_array($ref$resources)) {
                    
$usesize $available_size;
                    if (
$available_size == 'original') {
                        
$usesize "";
                        
// Has access to the original so no need to check previews
                        
break;
                    }
                }
            }
        } else {
            
$usesize = ($size == 'original') ? "" $size;
        }

        if (
in_array($collection_resources[$n]['file_extension'], $GLOBALS["ffmpeg_supported_extensions"]) && $usesize !== '') {
            
// Supported video formats will only have a pre sized derivative
            
$pextension $GLOBALS["ffmpeg_preview_extension"];
            
$p get_resource_path($reftrue'pre'false$pextension, -11);
            
$usesize 'pre';
        } elseif (
in_array($collection_resources[$n]['file_extension'], array_merge($GLOBALS["ffmpeg_audio_extensions"], ['mp3'])) && $usesize !== '') {
            
// Supported audio formats are ported to mp3
            
$pextension 'mp3';
            
$p get_resource_path($reftrue''false'mp3', -11);
            
$usesize '';
        } else {
            
$pextension get_extension($collection_resources[$n], $usesize);
            
$p get_resource_path($reftrue$usesizefalse$pextension, -11$use_watermark);
        }

        
$target_exists file_exists($p);
        
$replaced_file false;

        
$new_file hook('replacedownloadfile''', array($collection_resources[$n], $usesize$pextension$target_exists));
        if (
            
$new_file != ''
            
&& $p != $new_file
        
) {
            
$p $new_file;
            
$dl_data['deletion_array'][] = $p;
            
$replaced_file true;
            
$target_exists file_exists($p);
        } elseif (
            !
$target_exists
            
&& $useoriginal
            
&& resource_download_allowed($ref''$collection_resources[$n]['resource_type'], -1true)
        ) {
            
// This size doesn't exist, so we'll try using the original instead
            
$p get_resource_path($reftrue''false$collection_resources[$n]['file_extension'], -11$use_watermark);
            
$pextension $collection_resources[$n]['file_extension'];
            
$subbed_original true;
            
$dl_data['subbed_original_resources'][] = $ref;
            
$target_exists file_exists($p);
        }

        
// Move to next resource if file doesn't exist or restricted access and user doesn't have access to the requested size
        
if (
            !(
                (
                    (
$target_exists && $access == 0)
                    || (
                        
$target_exists
                        
&& $access == 1
                        
&& (image_size_restricted_access($size) || ($usesize == '' && $GLOBALS["restricted_full_download"]))
                    )
                )
                && 
resource_download_allowed($ref$usesize$collection_resources[$n]['resource_type'], -1true)
            )
        ) {
            
debug('Collection download : Skipping resource ID ' . (int) $ref
                
' file inaccessible to user - $target_exists = ' $target_exists
                
', $access = ' $access
                
', image_size_restricted_access(' $size ') = ' image_size_restricted_access($size)
                . 
', $usesize = ' $usesize
                
', $restricted_full_download = ' $GLOBALS["restricted_full_download"]
                . 
', resource_download_allowed() = ' resource_download_allowed($ref$usesize$collection_resources[$n]['resource_type'], -1true)
            );
            
// Set to skip, although alternative files may still be available
            
$skipresource true;
        }        
        
        
$tmpfile false;
        if (!
$skipresource) {
            
$dl_data['used_resources'][] = $ref;
            if (
$exiftool_write_option && !$collection_download_tar) {
                
$tmpfile write_metadata($p$ref$id);
                if (
$tmpfile !== false && file_exists($tmpfile)) {
                    
// File already in tmp, just rename it
                    
$p $tmpfile
                } elseif (!
$replaced_file) {
                    
// Copy the file from filestore rather than renaming
                    
$copy true
                }
            }

            
// If using original filenames when downloading, copy the file to new location so the name is included.
            
$filename get_download_filename($ref$usesize0$pextension);
            
collection_download_use_original_filenames_when_downloading(
                
$dl_data,
                
$filename,
                
$ref,
                
$pextension,
                
$p,
                
$copy,
            );

            if (
hook("downloadfilenamealt")) {
                
$filename hook("downloadfilenamealt");
            }
            if (
$includetext) {
                
$addtext collection_download_process_text_file($dl_data$ref$filename$subbed_original);
                
$dl_data['text'] .= $addtext;
            }

            
hook('modifydownloadfile');
            if (
$collection_download_tar) {
                
$usertempdir get_temp_dir(false"rs_" $GLOBALS["userref"] . "_" $id);
                
debug("collection_download adding symlink: " $p " - " $usertempdir DIRECTORY_SEPARATOR $filename);
                
$GLOBALS["use_error_exception"] = true;
                try {
                    
symlink($p$usertempdir DIRECTORY_SEPARATOR $filename);
                } catch (
Throwable $e) {
                    
debug("process_collection_download(): Unable to create symlink for resource $ref {$e->getMessage()}");
                    return [];
                }
                unset(
$GLOBALS["use_error_exception"]);
            } elseif (
$GLOBALS['use_zip_extension']) {
                
debug("Adding $p - ($filename) for ref " $ref " to " $zip->filename);
                
set_processing_message((string) ($n+"/" $rescount " " $GLOBALS["lang"]["filesaddedtozip"]));
                
$success $zip->addFile($p$filename);
                
debug('Collection download : Added resource ' $ref ' to zip archive = ' . ($success 'true' 'false'));
            } else {
                
$dl_data['includefiles'][] = $p;
            }
        }

        if (
$include_alternatives) {
            
debug("Processing alternative files for resource $ref");
            
// Process alternatives
            
$alternatives get_alternative_files($ref);
            foreach (
$alternatives as $alternative) {
                
debug("Processing alternative file {$alternative['ref']} for resource $ref, extension: $size_extension");
                
$pextension get_extension($alternative$usesize);
                
$p get_resource_path($reftrue$usesizefalse$pextensiontrue1$use_watermark''$alternative["ref"]);
                
$target_exists file_exists($p);
                if (
                    !
$target_exists
                    
&& ($useoriginal || in_array("format_chooser"$GLOBALS["plugins"]))
                    && 
resource_download_allowed($ref''$collection_resources[$n]['resource_type'], $alternative["ref"], true)
                ) {
                    
debug("Using original alternative file for alternative file {$alternative['ref']}");
                    
// This size doesn't exist, so we'll try using the original instead
                    // Always use original if using format chooser as the option is not then available and dynamically generating custom sizes is not supported for alternatives
                    
$p get_resource_path($reftrue''false$alternative['file_extension'], -11$use_watermark''$alternative["ref"]);
                    
$pextension $alternative['file_extension'];
                    
$target_exists file_exists($p);
                    
$usesize "";
                }

                
debug("Using filepath $p for alternative ref " $alternative["ref"]);
                if (
$target_exists) {
                    
$download_filename_format_saved $GLOBALS["download_filename_format"];
                    if (
strpos($GLOBALS["download_filename_format"], "%alternative") === false) {
                        
// To be safe, add in the alternative ID if not present in configured download filename format or
                        // it may conflict with the primary resource file
                        
$GLOBALS["download_filename_format"] = str_replace(
                            
".%extension",
                            
"%alternative.%extension",
                            
$GLOBALS["download_filename_format"]
                        );
                    }
                    
$filename get_download_filename($ref$usesize$alternative["ref"], $pextension);
                    
$GLOBALS["download_filename_format"] = $download_filename_format_saved;

                    
collection_download_use_original_filenames_when_downloading(
                        
$dl_data,
                        
$filename,
                        
$ref,
                        
$pextension,
                        
$p,
                        
$copy,
                    );

                    
debug("Adding $p ($filename) for alternative ref " $alternative["ref"]);
                    
set_processing_message((string) ($n+"/" $rescount " " $GLOBALS["lang"]["filesaddedtozip"]));
                    if (
$collection_download_tar) {
                        
// $usertempdir = get_temp_dir(false, "rs_" . $GLOBALS["userref"] . "_" . $id);
                        
debug("collection_download adding symlink: " $p " - " $usertempdir DIRECTORY_SEPARATOR $filename);
                        
$GLOBALS["use_error_exception"] = true;
                        try {
                            
symlink($p$usertempdir DIRECTORY_SEPARATOR $filename);
                        } catch (
Throwable $e) {
                            
debug("process_collection_download(): Unable to create symlink for ref {$ref},
                                alternative file 
{$alternative["ref"]}{$e->getMessage()}");
                            continue;
                        }
                        unset(
$GLOBALS["use_error_exception"]);
                    } elseif(
$archiver) {
                        
$dl_data["includefiles"][] = $p;
                    } else {
                        
$success $zip->addFile($p$filename);
                        
debug('Collection download : Added resource ' $ref ' to zip archive = ' . ($success 'true' 'false'));
                    }
                } else {
                    
debug("No file found for alternative ref " $alternative["ref"]);

                }
            }
        }
        
collection_download_log_resource_ready($dl_data$tmpfile$ref);
    }

    if (
$count_data_only_types) {
        
collection_download_process_data_only_types($dl_data$zip);
    }
    
collection_download_process_summary_notes($dl_data$filename$zip);
    if (
$include_csv_file == 'yes') {
        
collection_download_process_csv_metadata_file($dl_data$zip);
    }

    if (
$collection_download_tar) {
        
$suffix '.tar';
    } elseif (
$archiver) {
        
$suffix '.' $GLOBALS["collection_download_settings"][$settings_id]['extension'];
    } else {
        
$suffix '.zip';
    }
    
$filename "";
    
collection_download_process_collection_download_name($filename$collection$size$suffix$collectiondata);
    
$completed collection_download_process_archive_command($dl_data$zip$filename$zipfile);
    
collection_download_clean_temp_files($dl_data['deletion_array']);

    
db_end_transaction("collection_download");

    
// Reset global 
    
$exiftool_write_option $saved_exiftool_write_option;

    return [
        
"filename"  => $filename,
        
"path"      => $zipfile,
        
"completed" => $completed,
    ];
}

This article was last updated 31st March 2025 13:05 Europe/London time based on the source file dated 25th March 2025 11:20 Europe/London time.