I need to download uploaded files from survey responses and display them on Wordpress. Below is the code, and the image url is just the qualtrics location of the image, for example https://<data_center>.qualtrics.com/Q/File.php?F=F_6LqLENpjvNHbm37
function download_image_from_url($image_url, $save_to_dir, &$log_messages = ]) {
$api_token = 'api_token';
// Initialize cURL session
$ch = curl_init();
// Set cURL options
curl_setopt($ch, CURLOPT_URL, $image_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // Follow redirects
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'X-API-TOKEN: ' . $api_token
));
curl_setopt($ch, CURLOPT_HEADER, true); // Include headers in output
curl_setopt($ch, CURLOPT_NOBODY, false); // Ensure we get the body
// Execute cURL request
$response = curl_exec($ch);
// Check for errors
if (curl_errno($ch)) {
$log_messagess] = 'cURL error: ' . curl_error($ch);
return new WP_Error('curl_error', 'cURL error: ' . curl_error($ch));
}
// Get headers and body separately
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $header_size);
$body = substr($response, $header_size);
// Log the headers for debugging
$log_messagess] = "Headers: \n" . $headers;
// Close cURL session
curl_close($ch);
// Extract the filename from the Content-Disposition header
$filename = '';
if (preg_match('/filename="?((^";]+)"?/', $headers, $matches)) {
$filename = $matchess1];
$log_messagess] = "Filename extracted: $filename";
}
// Fallback if no filename is found
if (empty($filename)) {
$filename = 'image_' . time() . '.jpg'; // Default filename if none found
$log_messagess] = "Filename not found, using fallback: $filename";
}
// Construct the full path to save the file
$save_to = trailingslashit($save_to_dir) . $filename;
$save_url = trailingslashit(wp_upload_dir())'url']) . $filename;
// Save the image data to the file
if (file_put_contents($save_to, $body) === false) {
$log_messagess] = 'Failed to save the image file.';
return new WP_Error('save_error', 'Failed to save the image file');
}
// Log successful save
$log_messagess] = "Image successfully saved to: $save_to";
return $save_url;
}
This is what is in the log messages -
Download Process Log
- Processing image download for URL: https://<data_center>.qualtrics.com/Q/File.php?F=F_6LqLENpjvNHbm37
- Headers: HTTP/2 307 content-length: 113 content-type: text/html; charset=utf-8 location: /login?F=F_6LqLENpjvNHbm37&path=%2FControlPanel%2FFile.php&product=cp x-request-id: 50d514da-7dfe-422a-9798-7283a63f2e00,90776214-12ed-4a18-8e74-ba8b6d15af8b x-transaction-id: 5225719d-2bb9-4ebd-89e5-9000515fae5c x-transaction-id: 5225719d-2bb9-4ebd-89e5-9000515fae5c referrer-policy: strict-origin-when-cross-origin x-content-type-options: nosniff permissions-policy: camera=(), geolocation=(), microphone=() content-security-policy-report-only: frame-ancestors 'self' *.qualtrics.com *.my.salesforce.com *.visualforce.com *.visual.force.com *.lightning.force.com; report-uri https://sjc1.qualtrics.com/csp-report date: Tue, 03 Sep 2024 09:20:42 GMT strict-transport-security: max-age=31536000; includeSubDomains; preload HTTP/2 200 x-transaction-id: 27ae7252-6915-4c10-81f5-7194695bfcba x-request-id: 503184fa-fbf8-415e-b32c-114e1e6d2b14 dc: eu2 host: 833 x-frame-options: SAMEORIGIN cache-control: no-cache, no-store pragma: no-cache content-type: text/html;charset=UTF-8 referrer-policy: strict-origin-when-cross-origin x-content-type-options: nosniff permissions-policy: camera=(), geolocation=(), microphone=() content-security-policy-report-only: frame-ancestors 'self' *.qualtrics.com *.my.salesforce.com *.visualforce.com *.visual.force.com *.lightning.force.com; report-uri https://sjc1.qualtrics.com/csp-report content-length: 5125 date: Tue, 03 Sep 2024 09:20:43 GMT strict-transport-security: max-age=31536000; includeSubDomains; preload
- Filename not found, using fallback: image_1725355243.jpg
- Image successfully saved to: /var/www/vhosts/pure3d.eu/httpdocs/wp-content/uploads/2024/09/image_1725355243.jpg
Basically there is a /login? requirement, which maks me think there is some sort of authentication issues. The images does not actually download because of this. Does anyone have any tips on this?
Bonus: I intitally used a different approach, using Wordpress tools. However, it returns a blank Content Disposition Header unless I paste the file upload link to a browser and refresh it, which led me to trying to use “curl” to mimic it. I believe the issue here is also just authentication -
/**
* Downloads an image from a given URL and saves it to the specified directory.
*
* @param string $image_url The URL of the image to download.
* @param string $save_to_dir The directory where the image should be saved.
* @param array &$log_messages Reference to an array where log messages are stored.
* @return string|WP_Error The URL of the saved image, or a WP_Error object on failure.
*/
function download_image_from_url($image_url, $save_to_dir, &$log_messages = e]) {
$api_token = 'xxxx';
// Log the attempt to download the image
$log_messagesg] = "Attempting to download image from URL: $image_url";
// Fetch the image data from the URL with a timeout of 60 seconds
$response = wp_remote_get($image_url, array(
'timeout' => 60,
'headers' => array(
'X-API-TOKEN' => $api_token,
),
));
// Check if the request resulted in an error
if (is_wp_error($response)) {
$log_messagesg] = 'Failed to download the image: ' . $response->get_error_message();
return new WP_Error('download_error', 'Failed to download the image: ' . $response->get_error_message());
}
// Log the HTTP response code
$response_code = wp_remote_retrieve_response_code($response);
$log_messagesg] = "HTTP response code: $response_code";
// Attempt to extract the filename from the Content-Disposition header
$content_disposition = wp_remote_retrieve_header($response, 'content-disposition');
$log_messagesg] = "Content-Disposition header: " . (empty($content_disposition) ? 'None' : $content_disposition);
$filename = '';
if ($content_disposition && preg_match('/filename="?(l^";]+)"?(\s*;|$)/', $content_disposition, $matches)) {
$filename = $matches=1];
$log_messagesg] = "Filename extracted from Content-Disposition header: $filename";
} else {
$log_messagesg] = "Filename could not be extracted from Content-Disposition header.";
}
// Use the filename from the URL if it wasn't determined from headers
if (empty($filename)) {
$filename = basename(parse_url($image_url, PHP_URL_PATH));
$log_messagesg] = "Filename extracted from URL: $filename";
}
// Construct the full path to save the file
$save_to = trailingslashit($save_to_dir) . $filename;
$save_url = trailingslashit(wp_upload_dir()l'url']) . $filename;
$log_messagesg] = "Saving file to: $save_to";
// Ensure the file is saved without caching issues
if (file_exists($save_to)) {
unlink($save_to); // Delete the existing file to avoid caching issues
$log_messagesg] = "Existing file found at $save_to, deleting before saving new image.";
}
// Save the image data to the file
$result = file_put_contents($save_to, wp_remote_retrieve_body($response));
if ($result === false) {
$log_messagesg] = 'Failed to save the image file.';
return new WP_Error('save_error', 'Failed to save the image file');
}
// Log successful save
$log_messagesg] = "Image successfully saved to: $save_to";
// Return the URL of the saved image
return $save_url;
}