1

I'm currently trying to download a file from my server with a PHP AJAX request. I've build it this way:

First I'm getting all files (in this example just one) and build a link:

$invoice_number_base = 'RE-2018-12-00000039-E';

//Get all generated PDF file names by tmp path and invoice number base
foreach ( glob( '/var/www/vhosts/localhost/httpdocs/wp-content/uploads/wpo_wcpdf/attachments/' . $invoice_number_base . '*.pdf' ) as $file ) { ?>
    <a target="_blank" class="admin_et_pb_button"
       onclick="showGenInvoice('<?php echo $file ?>')">
        <?php echo basename( $file ) ?>
    </a>
<?php }

This generates this link here:

<a target="_blank" class="admin_et_pb_button" onclick="showGenInvoice('/var/www/vhosts/localhost/httpdocs/wp-content/uploads/wpo_wcpdf/attachments/RE-2018-12-00000039-E.pdf')">RE-2018-12-00000039-E.pdf</a>

Now I've build my JS function to call the AJAX function when the user clicks the button:

function showGenInvoice(file) {

    var data = {
        'action': 'show_gen_invoice',
        'file': file
    };

    jQuery.post(ajaxurl, data, function () {
    }).fail(function () {
        alert('An error occured!')
    });
}

(The function has the parameter link which contains the path to each file on my server)

After this I've build the AJAX callback in WordPress:

/**
 * Get generated invoice from attachments folder so the invoices which are sent by email
 */
add_action( 'wp_ajax_show_gen_invoice', array( $this, 'show_gen_invoice' ) );
public function show_gen_invoice() {
    //Get file path from request
    $file = $_POST['file'];
    if ( is_admin() && file_exists( $file ) ) {
        header( 'Content-Description: File Transfer' );
        header( 'Content-Type: application/octet-stream' );
        header( 'Content-Disposition: attachment; filename="' . basename( $file ) . '"' );
        header( 'Expires: 0' );
        header( 'Cache-Control: must-revalidate' );
        header( 'Pragma: public' );
        header( 'Content-Length: ' . filesize( $file ) );
        ob_clean();
        flush();
        readfile( $file );
        wp_die();
    } else {
        wp_send_json_error( null, 500 );
        wp_die();
    }
}

But sadly no file gets downloaded when I hit the button. No error, just nothing happens. Whats wrong here?

Notice:

The folder where the file is located is protected and can't be reached with the normal page url and /uploads/...

Update

Please checkout my solution! It's usable when you want to download something from your server from the backend with PHP.

Mr. Jo
  • 4,946
  • 6
  • 41
  • 100
  • The jQuery POST request retrieves the file in the background and presumably provides it in the success callback. You're not doing anything in that callback to pass the response on to the user. – rickdenhaan Jan 05 '19 at 20:51
  • Okay, never did this before. How can I access the file now? – Mr. Jo Jan 05 '19 at 20:53
  • Possible duplicate of [JavaScript/jQuery to download file via POST with JSON data](https://stackoverflow.com/questions/3499597/javascript-jquery-to-download-file-via-post-with-json-data) – rickdenhaan Jan 05 '19 at 20:57
  • 1
    Why don't you use `get method` without using javascript for this at all? you are not doing anything of importance in both javascript & php code (the file is already there), the browser will keep the user on the same page if the file being downloaded is has attachment headers (nothing to display) – ahmad Jan 05 '19 at 21:11
  • But how should I use GET via URL to download this file? – Mr. Jo Jan 05 '19 at 21:15

1 Answers1

1

Thanks to ahamd for the hint. This is my solution for the problem:

The new link:

//Get invoices tmp path
$tmp_path = WPO_WCPDF()->main->get_tmp_path( 'attachments' );
//Get invoice number
$invoice_number_base = $invoice->get_number()->get_formatted(); ?>
<div class="wpo_wcpdf-generated-invoices-container">
    <?php
    //Get all generated PDF file names by tmp path and invoice number base
    foreach ( glob( $tmp_path . $invoice_number_base . '*.pdf' ) as $invoice ) { ?>
        <a target="_blank"
           class="admin_et_pb_button"
           href="post.php?invoice=<?php echo basename( $invoice ) ?>">
            <?php echo basename( $invoice ) ?>
        </a>
    <?php } ?>
</div>
<?php

The code to display the file in the browser:

/**
 * Add file download functionality to admin post
 */
add_action( 'admin_init', 'show_gen_invoice' );
function show_gen_invoice() {

    //Check if invoice is set and get value = the path of the invoice
    if ( isset( $_REQUEST['invoice'] ) ) {

        //Get invoices tmp path
        $tmp_path = WPO_WCPDF()->main->get_tmp_path( 'attachments' );

        //Get invoice basename
        $invoice = urldecode( $_REQUEST['invoice'] );

        if ( is_admin() && file_exists( $tmp_path . $invoice ) ) {
            $content = file_get_contents( $tmp_path . $invoice );
            header( 'Content-Type: application/pdf' );
            header( 'Content-Length: ' . filesize( $tmp_path . $invoice ) );
            header( 'Content-Disposition: inline; filename=' . $invoice );
            header( 'Cache-Control: private, max-age=0, must-revalidate' );
            header( 'Pragma: public' );
            ini_set( 'zlib.output_compression', '0' );
            flush();
            die( $content );
        }
    }
}

I've display the file now in the browser but if you want to download it directly you can use my working code above to download it.

I'm using now the admin_init hook to get my code into the post.php file where I can use $_REQUEST to get this file.

Mr. Jo
  • 4,946
  • 6
  • 41
  • 100