WordPress.org

Ready to get started?Download WordPress

Forums

[resolved] Force download not working as expected (5 posts)

  1. Riccardo
    Member
    Posted 1 year ago #

    On PHP I usually I use these lines of code to force a download:

    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream', true, 200);
    header('Content-Disposition: attachment; filename="MY_FILENAME"');
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    ob_clean();
    ob_flush();
    flush();
    readfile('MY_FILE_PATH');
    exit();

    Now I tried to include the WordPress enviroment to it simply adding this on top of it:

    require_once(dirname(__FILE__) . '/wp-load.php');

    But now instead of instantly opening the browser download file dialog, the script runs for minutes (this lasts more for bigger files, it looks like the server is downloading the file) then only after this the browser shows the download file dialog where the user could clicks OK and starts the real download.

    If I comment out the WordPress include it works as expected.

    I have to use it for remote files, but it looks the same also on local files.

    I tried various combinations of output buffering cleaning, flushing and restarting too.

    Any hint on what feature of WordPress could cause this?

  2. bcworkz
    Member
    Posted 1 year ago #

    WP sends it's own headers which probably conflict with yours. I'm not sure why you're loading WP, but perhaps defining SHORTINIT as true before requiring wp-load.php will still work for you. It stops the WP load before headers are sent, but maybe also before the parts you need. Worth a try anyway.

    Another possibility is filter 'wp_headers' and return an empty array to suppress all WP headers. Or, have WP send your headers for you! Return an array that starts out as:

    array(
      'Content-Description' => 'File Transfer',
      'Content-Type' => 'application/octet-stream',
    //...

    Yeah, rather silly really, but illustrates how the array is normally used.

  3. Riccardo
    Member
    Posted 1 year ago #

    I hade the suspect that were the headers so I added a
    header_remove();
    before calling my setting of headers but without any positive result.

    I've also checked that headers are clean echoing
    get_headers()

    By the way, I tried defining the SHORTINIT constant as you suggested and in fact it works, the download it start immediatly.

    The problem is that I'm adding the WordPress enviroment because I need to use plugins functions to extract file data, but using SHORTINIT WordPress doesn't load plugins.

    Any other suggestion on what else could cause this problem on a forced download?

  4. bcworkz
    Member
    Posted 1 year ago #

    No idea on cause, but here's something else you might try. Instead of your script calling WP, have WP call your script. Your script could be hooked into the 'plugins_loaded' action. This obviously fires after the plugins are loaded, but before theme, query, rewrite and user stuff. If any of that is the cause of the issue, your script has the opportunity to run beforehand.

    There's also a lot that happens after SHORTINIT and before plugins are loaded, so it may not do any good, though it does narrow down what could be the cause. To have something to request to get things started, create a page, it could be one of those "Your download should start..." pages, or anything you like. Your action callback should check $_SERVER['REQUEST_URI'] or similar for this particular page so it doesn't run for every WP request.

  5. Riccardo
    Member
    Posted 1 year ago #

    After various tests I have finally found that the problem is caused by a nestling of different output buffers (in my case there were 3 levels of output buffering nested).

    So I have resolved substituting

    ob_clean();
    ob_flush();
    flush();

    with a while that loops until all OB levels are removed

    while(ob_get_level() > 0)
    {
        @ob_end_clean();
    }

Topic Closed

This topic has been closed to new replies.

About this Topic