Jump to content

Force pdf download


Zeka
 Share

Recommended Posts

Hi.

I have file field on a page wich contain pdf files.

As i understand in almost all modern browsers pdf files will be opened in it, but i need to force files download. 

I can use "download" attribute, but it does not work in IE.

Is there some build-in methods for that in PW.

Thanks!

Link to comment
Share on other sites

Hi, Horst and thank you for answer.
For now i implement solution based on url segments. 
<?php
if($input->urlSegment1 == 'download') {
    if($input->urlSegment2) {
        $names = array();
        $urls = array();
        foreach ($page->diagnostic_referral_repeater as $referral) {
            foreach ($referral->diagnostic_referral_files as $file) {
                array_push($names, $file->name);
                array_push($urls, $file->filename);
            }
        }
        $key = array_search($input->urlSegment2, $names);
        if($key !== false) {
            wireSendFile($urls[$key]);
        } else {
            throw new Wire404Exception();
        }
    }
} else if($input->urlSegment1) {
  // unknown URL segment, send a 404
  throw new Wire404Exception();
}
?>
                            <?php foreach ($page->diagnostic_referral_repeater as $referral) { ?>
                                <div class="diagnostic-referral">
                                    <div class="diagnostic-referral__box">
                                        <div class="diagnostic-referral__title">
                                            <?php echo $referral->diagnostic_referral_category->title; ?>
                                        </div>
                                        <?php echo $referral->render('diagnostic_referral_files', 'diagnostic-referral'); ?>
                                        <div class="diagnostic-referral__files">
                                            <?php foreach ($referral->diagnostic_referral_files as $file) { ?>
                                                <div class="diagnostic-referral-file">
                                                    <a href="<?php echo $page->path.'download/'.$file->name; ?>" class="diagnostic-referral-file__link">
                                                        <div class="diagnostic-referral-file__icon">
                                                            <span class="icon-download"></span>
                                                        </div>
                                                        <div class="diagnostic-referral-file__title">
                                                            <?php echo $file->description; ?>
                                                        </div>
                                                    </a>
                                                </div>
                                            <?php } ?>
                                        </div>
                                    </div>
                                </div>
                            <?php } ?>

Do you have any recommendation to improve it? 

Thanks. 

  • Like 1
Link to comment
Share on other sites

  • 9 months later...

I used a much simpler and faster method utilizing the pagefile class.

My link looks like this:

// Sorry for smarty language. but thats what I used
{if $page->files|@count > 0}
            {foreach $page->files as $file}
                <p>
                    {if $file->description}

                        {$file->description}
                    {else}
                        {$file->name}
                    {/if}
                    <br>
                    <a href="download/{$file->name}" class="link-icon">Download</a>
                    | {$file->filesizeStr}
                </p>
                {*{/if}*}
            {/foreach}
        {/if}

and then in my _init.php I used the following code

if ($input->urlSegment1 == 'download') {
        $download_options = array(
            // boolean: halt program execution after file send
            'exit' => true,
            // boolean|null: whether file should force download (null=let content-type header decide)
            'forceDownload' => true,
            // string: filename you want the download to show on the user's computer, or blank to use existing.
            'downloadFilename' => '',
        );
        session_write_close();
        if ($input->urlSegment2) {
            $pagefile = $page->files[$input->urlSegment2];
            if($pagefile){
                wireSendFile($pagefile->filename, $download_options);
            }
        }
    }

EDIT: The downside when implementing this in the _init.php is, that you can´t send a Wire404Exception, because this file gets included (prepended) and PHP doesn´t like exeptions in included files. If you paste this code into one of your templates you could add trowing a Wire404Exception.

Edited by jmartsch
  • Like 6
  • Thanks 1
Link to comment
Share on other sites

  • 6 years later...

Sorry to bring a thread from the dead, but I'm banging my head against the wall with this. I'm by no means a processwire expert and this is probably the most in-depth I've ever gone into understanding it. 

I've used Zeka's solution. In 2023 you need to add 

<?php namespace ProcessWire; ?>

for wireSendFile() to work.

 

The URL segment works and creates a link to the file, but the file does not download - it opens in the browser.
This is an example url with the downloads:
https://zar.co.com/handoffs/hera-title-colorado-posters/

The URL segment gets appended after this, for example - ....colorado-posters/download/name-of-file.jpg


This is my setup in the config.php:

$config->fileContentTypes = array(
	'?' => '+application/octet-stream',
	'txt' => '+text/plain',
	'csv' => '+text/csv',
	'pdf' => '+application/pdf',
	'doc' => '+application/msword',
	'docx' => '+application/vnd.openxmlformats-officedocument.wordprocessingml.document',
	'xls' => '+application/vnd.ms-excel',
	'xlsx' => '+application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
	'ppt' => '+application/vnd.ms-powerpoint',
	'pptx' => '+application/vnd.openxmlformats-officedocument.presentationml.presentation',
	'rtf' => '+application/rtf',
	'gif' => 'image/gif',
	'jpg' => 'image/jpeg',
	'jpeg' => 'image/jpeg',
	'png' => 'image/png',
	'svg' => 'image/svg+xml',
	'webp' => 'image/webp',
	'zip' => '+application/zip',
	'mp3' => 'audio/mpeg',
);

Could someone point me in the right direction?

Link to comment
Share on other sites

For whoever stumbles on this, the issue was exactly in the FileContentTypes. Every type that should be forced to download should have a "+" in front, which I did not have. So, this is the correct setup in config.php (for my case):

$config->fileContentTypes = array(
	'?' => '+application/octet-stream',
	'txt' => '+text/plain',
	'csv' => '+text/csv',
	'pdf' => '+application/pdf',
	'doc' => '+application/msword',
	'docx' => '+application/vnd.openxmlformats-officedocument.wordprocessingml.document',
	'xls' => '+application/vnd.ms-excel',
	'xlsx' => '+application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
	'ppt' => '+application/vnd.ms-powerpoint',
	'pptx' => '+application/vnd.openxmlformats-officedocument.presentationml.presentation',
	'rtf' => '+application/rtf',
	'gif' => '+image/gif',
	'jpg' => '+image/jpeg',
	'jpeg' => '+image/jpeg',
	'png' => '+image/png',
	'svg' => '+image/svg+xml',
	'webp' => '+image/webp',
	'zip' => '+application/zip',
	'mp3' => '+audio/mpeg',
);

In addition, I wanted to use original file names, not the ones that Processwire creates when uploading files. This modification to Zeka's code manages that through html_entity_decode:

                    if($input->urlSegment1 == 'download') {
                        if($input->urlSegment2) {
                            $names = array();
                            $urls = array();
                            $originalNames = array();
                            foreach ($page->handoff_files as $handoff_file_repeater) {
                                $file = $handoff_file_repeater->file;
                                $original_name_unencoded = html_entity_decode($file->uploadName);  
                                array_push($names, $file->name);
                                array_push($urls, $file->filename);
                                array_push($originalNames, $original_name_unencoded);
                            }
                            $key = array_search($input->urlSegment2, $names);
                            if($key !== false) {
                                wireSendFile($urls[$key], [
                                    "downloadFilename" => $originalNames[$key],
                                ]);
                            } else {
                                throw new Wire404Exception();
                            }
                        }
                    } else if($input->urlSegment1) {
                      // unknown URL segment, send a 404
                      throw new Wire404Exception();
                    }


                    foreach ($page->handoff_files as $handoff_file_repeater){
                        $file = $handoff_file_repeater->file;
                        $fileSizeInBytes = $files->size($file->filename);
                        $formattedSize = formatFileSize($fileSizeInBytes);      
                        $original_name_unencoded = html_entity_decode($file->uploadName);    
                      
                    ?>

                        <div class="file-block">
                            <div class="file-info">
                                <h3><?=$original_name_unencoded;?></h3>                                
                                <p><?=$formattedSize;?></p>
                            </div>
                            <!--<a href="<?=$file->url;?>" download="<?=$original_name_unencoded;?>" class="download-button">download</a>-->
                            <a href="<?= 'download/'.$file->name; ?>" download="<?=$original_name_unencoded?>" class="download-button">download</a>

                        </div>

                    <?php
                    }
                    ?>

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...