Skip to content
Snippets Groups Projects
Commit eb7ad2f7 authored by Yassine Doghri's avatar Yassine Doghri
Browse files

fix(import): rewrite download_file helper to output curl response directly to file

This prevents memory exhaustion when downloading large files
parent 281eefc6
No related branches found
No related tags found
No related merge requests found
......@@ -136,7 +136,9 @@ if (! function_exists('publication_pill')) {
$customClass .
'">' .
$label .
($publicationStatus === 'with_podcast' ? '<Icon glyph="error-warning" class="flex-shrink-0 ml-1 text-lg" />' : '') .
($publicationStatus === 'with_podcast' ? icon('error-warning-fill', [
'class' => 'flex-shrink-0 ml-1 text-lg',
]) : '') .
'</span>';
}
}
......
......@@ -9,47 +9,12 @@ declare(strict_types=1);
*/
use CodeIgniter\Files\File;
use CodeIgniter\HTTP\ResponseInterface;
use Config\Mimes;
use Config\Services;
if (! function_exists('download_file')) {
function download_file(string $fileUrl, string $mimetype = ''): File
{
$client = Services::curlrequest();
$response = $client->get($fileUrl, [
'headers' => [
'User-Agent' => 'Castopod/' . CP_VERSION,
],
]);
// redirect to new file location
$newFileUrl = $fileUrl;
while (
in_array(
$response->getStatusCode(),
[
ResponseInterface::HTTP_MOVED_PERMANENTLY,
ResponseInterface::HTTP_FOUND,
ResponseInterface::HTTP_SEE_OTHER,
ResponseInterface::HTTP_NOT_MODIFIED,
ResponseInterface::HTTP_TEMPORARY_REDIRECT,
ResponseInterface::HTTP_PERMANENT_REDIRECT,
],
true,
)
) {
$newFileUrl = trim($response->header('location')->getValue());
$response = $client->get($newFileUrl, [
'headers' => [
'User-Agent' => 'Castopod/' . CP_VERSION,
],
'http_errors' => false,
]);
}
$fileExtension = pathinfo(parse_url($newFileUrl, PHP_URL_PATH), PATHINFO_EXTENSION);
$fileExtension = pathinfo(parse_url($fileUrl, PHP_URL_PATH), PATHINFO_EXTENSION);
$extension = $fileExtension === '' ? Mimes::guessExtensionFromType($mimetype) : $fileExtension;
$tmpFilename =
time() .
......@@ -57,9 +22,26 @@ if (! function_exists('download_file')) {
bin2hex(random_bytes(10)) .
'.' .
$extension;
$tmpfileKey = WRITEPATH . 'uploads/' . $tmpFilename;
file_put_contents($tmpfileKey, $response->getBody());
$tmpfilePath = WRITEPATH . 'uploads/' . $tmpFilename;
$file = fopen($tmpfilePath, 'w');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $fileUrl);
// output directly to file
curl_setopt($ch, CURLOPT_FILE, $file);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['User-Agent: Castopod/' . CP_VERSION]);
// follow redirects up to 20, like Apple Podcasts
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_MAXREDIRS, 20);
curl_exec($ch);
curl_close($ch);
fclose($file);
return new File($tmpfileKey);
return new File($tmpfilePath);
}
}
......@@ -39,6 +39,7 @@ $isEpisodeArea = isset($podcast) && isset($episode);
<div class="flex flex-wrap items-center truncate">
<?php if (($isEpisodeArea && $episode->is_premium) || ($isPodcastArea && $podcast->is_premium)): ?>
<div class="inline-flex items-center">
<?php // @icon('exchange-dollar-fill')?>
<IconButton uri="<?= route_to('subscription-list', $podcast->id) ?>" glyph="exchange-dollar-fill" variant="secondary" size="large" class="p-0 mr-2 border-0"><?= ($isEpisodeArea && $episode->is_premium) ? lang('PremiumPodcasts.episode_is_premium') : lang('PremiumPodcasts.podcast_is_premium') ?></IconButton>
<Heading tagName="h1" size="large" class="truncate"><?= $this->renderSection('pageTitle') ?></Heading>
</div>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment