public static function downloadFile($filePath, $fileName, $mime = '', $size = -1, $openMode = self::OPEN_MODE_ATTACHMENT) {

        if (!file_exists($filePath)) {
            throw new Exception\FileNotFoundException(null, 0, null, $filePath);
        }
        if (!is_readable($filePath)) {
            throw new Exception\FileNotFoundException(sprintf('File %s is not readable', $filePath), 0, null, $filePath);
        }

        // Fetching File
        $mtime = ($mtime = filemtime($filePath)) ? $mtime : gmtime();

        if ($mime === '') {
            header("Content-Type: application/force-download");
            header('Content-Type: application/octet-stream');
        }
        else {
            if(is_null($mime)) {
                $mime = self::detectMimeType($filePath, $fileName);
            }
            header('Content-Type: ' . $mime);
        }

        if (strstr(filter_input(INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_SANITIZE_STRING), "MSIE") != false) {
            header("Content-Disposition: ".$openMode."; filename=" . urlencode($fileName) . '; modification-date="' . date('r', $mtime) . '";');
        }
        else {
            header("Content-Disposition: ".$openMode."; filename=\"" . $fileName . '"; modification-date="' . date('r', $mtime) . '";');
        }

        if (function_exists('apache_get_modules') && in_array('mod_xsendfile', apache_get_modules())) {
            // Sending file via mod_xsendfile
            header("X-Sendfile: " . $filePath);
        }
        else {
            // Sending file directly via script
            // according memory_limit byt not higher than 1GB
            $memory_limit = ini_get('memory_limit');
            // get file size
            if ($size === -1) {
                $size = filesize($filePath);
            }

            if (intval($size + 1) > self::toBytes($memory_limit) && intval($size * 1.5) <= 1073741824) {
                // Setting memory limit
                ini_set('memory_limit', intval($size * 1.5));
            }

            @ini_set('zlib.output_compression', 0);
            header("Content-Length: " . $size);
            // Set the time limit based on an average D/L speed of 50kb/sec
            set_time_limit(min(7200, // No more than 120 minutes (this is really bad, but...)
                            ($size > 0) ? intval($size / 51200) + 60 // 1 minute more than what it should take to D/L at 50kb/sec
                                    : 1 // Minimum of 1 second in case size is found to be 0
            ));
            $chunksize = 1 * (1024 * 1024); // how many megabytes to read at a time
            if ($size > $chunksize) {
                // Chunking file for download
                $handle = fopen($filePath, 'rb');
                if ($handle === false) {
                    return false;
                }
                $buffer = '';
                while (!feof($handle)) {
                    $buffer = fread($handle, $chunksize);
                    echo $buffer;

                    // if somewhare before was ob_start()
                    if (ob_get_level() > 0) ob_flush();
                    flush();
                }
                fclose($handle);
            }
            else {
                // Streaming whole file for download
                readfile($filePath);
            }
        }
        return true;
    }