We are moving our forum in GitHub Discussions. For questions about Phalcon v3/v4 you can visit here and for Phalcon v5 here.

Download a file [SOLVED]

Hello, I'm really lost trying to get a file download. I have my files for download in this file estructure:

    /user_documents <- here

My files in /user_documents have numbers for names: 1, 2, 3.. And the real name is store in the database. The thing is I don't know how to get to a file like /var/user_documents/1 so I'm able to read it. I don't know if I need to set some routes or permissions there.

When I read it I want to use this code I saw in the forum for downloading it, but I don't know if it's the right way either:

header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header('Content-Description: File Transfer');
header('Content-type: ' . $filetype);
header('Content-length: ' . $filesize);
header('Content-Disposition: attachment; filename="'.$filename.'"');


If all the files are in one directory, then the URL could be something like this:


Your "fileController.php" file can then have a "downloadAction" method that gets passed "1" as the parameter. You can then do your database stuff and run the code you posted above.


In my /public/index.php file I have included the following

//define path to application directory
    || define('ROOT_PATH' , realpath(dirname(__FILE__)).'/../');

//define path to var directory
    || define('VAR_PATH' , ROOT_PATH.'var');

//define path to library directory
    || define('LIBRARY_PATH' , ROOT_PATH.'library');

So if you added the same in there, I assume you could read the file via:


And if you are going to use user_documents directory often, you could as well use DEFINE and create a variable for that as well.


Yes quasipickle, I've figure it out to that. metialb that worked for me perfect. Thanks.

I copy here the last code for downloading I use:

// Based on Armand Niculescu download.php - Copyright 2012 - MediaDivision.com
public function downloadAction($UsAtCod, $mode = "attachment")
        $res = UserAttachment::findFirst("UsAtCod={$UsAtCod}");
        $filename = $res->UsAtFilename;

        $file_name = pathinfo($filename, PATHINFO_FILENAME);
        $file_ext = pathinfo($filename, PATHINFO_EXTENSION);

        $file_path = VAR_PATH . "/user_documents/{$UsAtCod}";

            $file_size  = filesize($file_path);
            $file = @fopen($file_path, "rb");

            if ($file){
                // set the headers, prevent caching
                header("Pragma: public");
                header("Expires: -1");
                header("Cache-Control: public, must-revalidate, post-check=0, pre-check=0");

                // set appropriate headers for attachment or streamed file
                if ($mode == "attachment")
                    header("Content-Disposition: attachment; filename=\"{$filename}\"");
                    header("Content-Disposition: inline; filename=\"{$filename}\"");

                // set the mime type based on extension, add yours if needed.
                $ctype_default = "application/octet-stream";
                $content_types = array(
                        "exe" => "application/octet-stream",
                        "zip" => "application/zip",
                        "mp3" => "audio/mpeg",
                        "mpg" => "video/mpeg",
                        "avi" => "video/x-msvideo",
                        "pdf"  => "application/pdf",

                $ctype = isset($content_types[$file_ext]) ? $content_types[$file_ext] : $ctype_default;
                header("Content-Type: {$ctype}");

                // check if http_range is sent by browser (or download manager)
                if(isset($_SERVER['HTTP_RANGE'])) {
                    list($size_unit, $range_orig) = explode('=', $_SERVER['HTTP_RANGE'], 2);

                    if ($size_unit == 'bytes') {
                        // multiple ranges could be specified at the same time, but for simplicity only serve the first range
                        list($range, $extra_ranges) = explode(',', $range_orig, 2);
                    } else {
                        $range = '';
                        header('HTTP/1.1 416 Requested Range Not Satisfiable');

                } else
                    $range = '';

                // figure out download piece from range (if set)
                list($seek_start, $seek_end) = explode('-', $range, 2);

                // set start and end based on range (if set), else set defaults
                // also check for invalid ranges.

                $seek_end   = (empty($seek_end)) ? ($file_size - 1) : min(abs(intval($seek_end)),($file_size - 1));
                $seek_start = (empty($seek_start) || $seek_end < abs(intval($seek_start))) ? 0 : max(abs(intval($seek_start)), 0);

                // Only send partial content header if downloading a piece of the file (IE workaround)
                if ($seek_start > 0 || $seek_end < ($file_size - 1)) {
                    header('HTTP/1.1 206 Partial Content');
                    header('Content-Range: bytes ' . $seek_start . '-' . $seek_end . '/' . $file_size);
                    header('Content-Length: ' . ($seek_end - $seek_start + 1));
                } else
                    header("Content-Length: {$file_size}");

                header('Accept-Ranges: bytes');

                fseek($file, $seek_start);

                while(!feof($file)) {
                    print(@fread($file, 1024 * 8));


                    if (connection_status() != 0) {

                // file save was a success
            } else {
                // file couldn't be opened
                header("HTTP/1.0 500 Internal Server Error");
        } else
            // file does not exist
            header("HTTP/1.0 404 Not Found");




I am glad I could help. Regarding your code, if you have the freedom of controlling/modifying your server, you might wanna check https://tn123.org/mod_xsendfile/ -- I think it works better and definitely needs less lines of code than what you currently have in there.


Thanks metialb, I'll check on that :D

@ivanblue Would you please help me? I am creating excel files (xlsx) using phpspreadsheet and I would like to be able to download those files into my client's computer. I tried with your code but it does not working. I will appriciate your help. Thank you.

@ivanblue Would you please help me? I am creating excel files (xlsx) using phpspreadsheet and I would like to be able to download those files into my client's computer. I tried with your code but it does not working. I will appriciate your help. Thank you.

I'd suggest making a new thread, as this one is 5 years old.