开发者

xsendfile only works from index

I'm trying to send a file to the user using xsendfile within the code igniter framework.

It is all installed correctly, my problem is that it only seems to work from the route, e开发者_运维问答ven though every page comes from index.php anyway.

This is my function:

function _output_file($name, $root_location, $public_location = FALSE)
{
    if (function_exists('apache_get_modules') && in_array('mod_xsendfile', apache_get_modules())) {
        header ('Content-Description: File Transfer');
        header ('Content-Type: application/octet-stream');
        if (strstr($_SERVER["HTTP_USER_AGENT"], "MSIE") != FALSE) {
            header ('Content-Disposition: attachment; filename='.urlencode($name));
        } else {
            header ('Content-Disposition: attachment; filename="'.$name.'"');
        }
        //86400 is one day
        header ('Expires: '.gmdate('D, d M Y H:i:s', (TIME_NOW + 86400)));
        header ('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header ('Pragma: public');
        header ('X-Sendfile: '.$root_location);
        exit;
    } else {
        redirect(site_url($public_location));
    }
}

If I place this at the top of my index.php and load the root it works fine, but if I try to access it from domain.com/controller/function it returns a 404 error.

It is definitely using the index.php file since if I replace the function call with die("test"); this displays to the screen.

I believe it's something to do with what permissions xsendfile has to access the file, but since it's working from the root index.php I would have thought it would have complete permissions, presumably it's based on what the request url is, which I find strange.

So.... does anyone have any suggestions as to how I can get xsendfile to work through codeigniter, from a url such as "domain.com/files/get/12"?


XSendFile has some specific security-related path quirks... and depending on your server configuration, these issues can sometimes occur over HTTPS even when HTTP seems to be working correctly.

If you run into mysterious 404s while using mod_xsendfile and you can confirm that the files being served really do exist, then you probably need to configure XSendFilePath in your Apache confs.

Add the following to the appropriate conf (httpd.conf, ssl.conf, httpd-ssl.conf, etc) and/or inside the appropriate VirtualHost declaration (if using vhosts)...

XSendFilePath /Absolute/Path/To/Your/Working/Directory/

Note: You cannot add this to an .htaccess file. It must be placed into an Apache conf.

Generally, xsendfile will try to figure out the working directory automatically, but sometimes it can't. This directive tells it explicitly what directory (or directories) should be accessible through xsendfile. Chances are that a mysterious 404 means that your directory isn't passing the whitelist check for some reason. This will fix that.

And don't forget to reboot apache after you change the config.


Prefixing a method name with an underscore makes it inaccessible through the URL.

From the documentation:

Private Functions

In some cases you may want certain functions hidden from public access. To make a function private, simply add an underscore as the name prefix and it will not be served via a URL request. For example, if you were to have a function like this:

private function _utility()
{
    // some code
}

Trying to access it via the URL, like this, will not work: example.com/index.php/blog/_utility/


It seems this answer never got a reponse, in the end I just created a file in my root called "getfile.php", it's not perfect but it gets the job done for now, here it is for anyone that may find it useful.

<?php
define('BASEPATH', 'just done to stop direct access being disallowed');

function show_getfile_error()
{
    echo 'You do not have permission to download this file, if you think this is a mistake please get in contact.';
    exit;
}

include('applications/config/database.php');
$mysqli = new mysqli($db['default']['hostname'], $db['default']['username'], $db['default']['password'], $db['default']['database']);
if(!preg_match('%^[0-9]+$%', $_GET['key']))
{
    show_getfile_error();
}
else
{
    $query = mysqli_query($mysqli, 'SELECT * FROM getfiles WHERE getfile_key = '.(int)$_GET['key']);

    $result = mysqli_fetch_array($query, MYSQLI_ASSOC);

    if(!$result || $result['getfile_ip'] != $_SERVER['REMOTE_ADDR'])
    {
        show_getfile_error();
    }

    header ('Content-Description: File Transfer');
    header ('Content-Type: application/octet-stream');
    if (strstr($_SERVER["HTTP_USER_AGENT"], "MSIE") != FALSE) {
        header ('Content-Disposition: attachment; filename='.urlencode($result['getfile_name']));
    } else {
        header ('Content-Disposition: attachment; filename="'.$result['getfile_name'].'"');
    }
    //86400 is one day
    header ('Expires: '.gmdate('D, d M Y H:i:s', (TIME_NOW + 86400)));
    header ('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header ('Pragma: public');
    header ('X-Sendfile: '.$result['getfile_location']);
}
?>


I have come across the 404 error today. If the path you pass to the header contains any components that lie outside of the root folder that index.php is in, then you get a 404. Make sure the path is relative to index.php, not an absolute path.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜