Exemplo n.º 1
0
    /**
     * Download logic
     *
     * @access public
     * @since 1.0
     */
    function download()
    {
        // Import and Initialize some joomla API variables
        jimport('joomla.filesystem.file');
        $app = JFactory::getApplication();
        $db = JFactory::getDBO();
        $user = JFactory::getUser();
        $task = JRequest::getVar('task', 'download');
        $session = JFactory::getSession();
        $method = JRequest::getVar('method', 'download');
        if ($method != 'view' && $method != 'download') {
            die('unknown download method:' . $method);
        }
        // *******************************************************************************************************************
        // Single file download (via HTTP request) or multi-file downloaded (via a folder structure in session or in DB table)
        // *******************************************************************************************************************
        if ($task == 'download_tree') {
            // TODO: maybe move this part in module
            $cart_id = JRequest::getVar('cart_id', 0);
            if (!$cart_id) {
                // Get zTree data and parse JSON string
                $tree_var = JRequest::getVar('tree_var', "");
                if ($session->has($tree_var, 'flexicontent')) {
                    $ztree_nodes_json = $session->get($tree_var, false, 'flexicontent');
                }
                $nodes = json_decode($ztree_nodes_json);
            } else {
                $cart_token = JRequest::getVar('cart_token', '');
                $query = ' SELECT * FROM #__flexicontent_downloads_cart WHERE id=' . $cart_id;
                $db->setQuery($query);
                $cart = $db->loadObject();
                if ($db->getErrorNum()) {
                    JFactory::getApplication()->enqueueMessage(__FUNCTION__ . '(): SQL QUERY ERROR:<br/>' . nl2br($db->getErrorMsg()), 'error');
                }
                if (!$cart) {
                    echo JText::_('cart id no ' . $cart_id . ', was not found');
                    jexit();
                }
                $cart_token_matches = $cart_token == $cart->token;
                // no access will be checked
                $nodes = json_decode($cart->json);
            }
            // Some validation check
            if (!is_array($nodes)) {
                $app->enqueueMessage("Tree structure is empty or invalid", 'notice');
                $this->setRedirect('index.php', '');
                return;
            }
            $app = JFactory::getApplication();
            $tmp_ffname = 'fcmd_uid_' . $user->id . '_' . date('Y-m-d__H-i-s');
            $targetpath = JPath::clean($app->getCfg('tmp_path') . DS . $tmp_ffname);
            $tree_files = $this->_traverseFileTree($nodes, $targetpath);
            //echo "<pre>"; print_r($tree_files); jexit();
            if (empty($tree_files)) {
                $app->enqueueMessage("No files selected for download", 'notice');
                $this->setRedirect('index.php', '');
                return;
            }
        } else {
            $file_node = new stdClass();
            $file_node->fieldid = JRequest::getInt('fid', 0);
            $file_node->contentid = JRequest::getInt('cid', 0);
            $file_node->fileid = JRequest::getInt('id', 0);
            $coupon_id = JRequest::getInt('conid', 0);
            $coupon_token = JRequest::getString('contok', '');
            if ($coupon_id) {
                $_nowDate = 'UTC_TIMESTAMP()';
                $_nullDate = $db->Quote($db->getNullDate());
                $query = ' SELECT *' . ', CASE WHEN ' . '   expire_on = ' . $_nullDate . '   OR   expire_on > ' . $_nowDate . '  THEN 0 ELSE 1 END AS has_expired' . ', CASE WHEN ' . '   hits_limit = -1   OR   hits < hits_limit' . '  THEN 0 ELSE 1 END AS has_reached_limit' . ' FROM #__flexicontent_download_coupons' . ' WHERE id=' . $coupon_id . ' AND token=' . $db->Quote($coupon_token);
                $db->setQuery($query);
                $coupon = $db->loadObject();
                if ($db->getErrorNum()) {
                    echo __FUNCTION__ . '(): SQL QUERY ERROR:<br/>' . nl2br($db->getErrorMsg());
                    jexit();
                }
                if ($coupon) {
                    $slink_valid_coupon = !$coupon->has_reached_limit && !$coupon->has_expired;
                    if (!$slink_valid_coupon) {
                        $query = ' DELETE FROM #__flexicontent_download_coupons WHERE id=' . $coupon->id;
                        $db->setQuery($query);
                        $db->execute();
                    }
                }
                $file_node->coupon = !empty($coupon) ? $coupon : false;
                // NULL will not be catched by isset()
            }
            $tree_files = array($file_node);
        }
        // **************************************************
        // Create and Execute SQL query to retrieve file info
        // **************************************************
        // Create SELECT OR JOIN / AND clauses for checking Access
        $access_clauses['select'] = '';
        $access_clauses['join'] = '';
        $access_clauses['and'] = '';
        $using_access = empty($cart_token_matches) && empty($slink_valid_coupon);
        if ($using_access) {
            // note CURRENTLY multi-download feature does not use coupons
            $access_clauses = $this->_createFieldItemAccessClause($get_select_access = true, $include_file = true);
        }
        // ***************************
        // Get file data for all files
        // ***************************
        $fields_props = array();
        $fields_conf = array();
        $valid_files = array();
        $email_recipients = array();
        foreach ($tree_files as $file_node) {
            // Get file variable shortcuts (reforce being int)
            $field_id = (int) $file_node->fieldid;
            $content_id = (int) $file_node->contentid;
            $file_id = (int) $file_node->fileid;
            if (!isset($fields_conf[$field_id])) {
                $q = 'SELECT attribs, name, field_type FROM #__flexicontent_fields WHERE id = ' . (int) $field_id;
                $db->setQuery($q);
                $fld = $db->loadObject();
                $fields_conf[$field_id] = new JRegistry($fld->attribs);
                $fields_props[$field_id] = $fld;
            }
            $field_type = $fields_props[$field_id]->field_type;
            $query = 'SELECT f.id, f.filename, f.filename_original, f.altname, f.secure, f.url, f.hits' . ', i.title as item_title, i.introtext as item_introtext, i.fulltext as item_fulltext, u.email as item_owner_email' . ', i.access as item_access, i.language as item_language, ie.type_id as item_type_id' . ', CASE WHEN CHAR_LENGTH(i.alias) THEN CONCAT_WS(\':\', i.id, i.alias) ELSE i.id END as itemslug' . ', CASE WHEN CHAR_LENGTH(c.alias) THEN CONCAT_WS(\':\', c.id, c.alias) ELSE c.id END as catslug' . ', dh.id as history_id' . $access_clauses['select'] . ' FROM #__flexicontent_files AS f ' . ($field_type == 'file' ? ' LEFT JOIN #__flexicontent_fields_item_relations AS rel ON rel.field_id = ' . $field_id : '') . ' LEFT JOIN #__flexicontent_fields AS fi ON fi.id = ' . $field_id . ' LEFT JOIN #__content AS i ON i.id = ' . $content_id . ' LEFT JOIN #__categories AS c ON c.id = i.catid' . ' LEFT JOIN #__flexicontent_items_ext AS ie ON ie.item_id = i.id' . ' LEFT JOIN #__flexicontent_types AS ty ON ie.type_id = ty.id' . ' LEFT JOIN #__users AS u ON u.id = i.created_by' . ' LEFT JOIN #__flexicontent_download_history AS dh ON dh.file_id = f.id AND dh.user_id = ' . (int) $user->id . $access_clauses['join'] . ' WHERE i.id = ' . $content_id . ' AND fi.id = ' . $field_id . ' AND f.id = ' . $file_id . ' AND f.published= 1' . $access_clauses['and'];
            $db->setQuery($query);
            $file = $db->loadObject();
            if ($db->getErrorNum()) {
                echo __FUNCTION__ . '(): SQL QUERY ERROR:<br/>' . nl2br($db->getErrorMsg());
                jexit();
            }
            //echo "<pre>". print_r($file, true) ."</pre>"; exit;
            // **************************************************************
            // Check if file was found AND IF user has required Access Levels
            // **************************************************************
            if (empty($file) || $using_access && (!$file->has_content_access || !$file->has_field_access || !$file->has_file_access)) {
                if (empty($file)) {
                    $msg = JText::_('FLEXI_FDC_FAILED_TO_FIND_DATA');
                    // Failed to match DB data to the download URL data
                } else {
                    $msg = JText::_('FLEXI_ALERTNOTAUTH');
                    if (!empty($file_node->coupon)) {
                        if ($file_node->coupon->has_expired) {
                            $msg .= JText::_('FLEXI_FDC_COUPON_HAS_EXPIRED');
                        } else {
                            if ($file_node->coupon->has_reached_limit) {
                                $msg .= JText::_('FLEXI_FDC_COUPON_REACHED_USAGE_LIMIT');
                            } else {
                                $msg = "unreachable code in download coupon handling";
                            }
                        }
                    } else {
                        if (isset($file_node->coupon)) {
                            $msg .= "<br/> <small>" . JText::_('FLEXI_FDC_COUPON_NO_LONGER_USABLE') . "</small>";
                        }
                        $msg .= '' . (!$file->has_content_access ? "<br/><br/> " . JText::_('FLEXI_FDC_NO_ACCESS_TO') . " -- " . JText::_('FLEXI_FDC_CONTENT_CONTAINS') . " " . JText::_('FLEXI_FDC_WEBLINK') . "<br/><small>(" . JText::_('FLEXI_FDC_CONTENT_EXPLANATION') . ")</small>" : '') . (!$file->has_field_access ? "<br/><br/> " . JText::_('FLEXI_FDC_NO_ACCESS_TO') . " -- " . JText::_('FLEXI_FDC_FIELD_CONTAINS') . " " . JText::_('FLEXI_FDC_WEBLINK') : '') . (!$file->has_file_access ? "<br/><br/> " . JText::_('FLEXI_FDC_NO_ACCESS_TO') . " -- " . JText::_('FLEXI_FDC_FILE') . " " : '');
                    }
                    $msg .= "<br/><br/> " . JText::sprintf('FLEXI_FDC_FILE_DATA', $file_id, $content_id, $field_id);
                    $app->enqueueMessage($msg, 'notice');
                }
                // Only abort for single file download
                if ($task != 'download_tree') {
                    $this->setRedirect('index.php', '');
                    return;
                }
            }
            // ****************************************************
            // (for non-URL) Create file path and check file exists
            // ****************************************************
            if (!$file->url) {
                $basePath = $file->secure ? COM_FLEXICONTENT_FILEPATH : COM_FLEXICONTENT_MEDIAPATH;
                $file->abspath = str_replace(DS, '/', JPath::clean($basePath . DS . $file->filename));
                if (!JFile::exists($file->abspath)) {
                    $msg = JText::_('FLEXI_REQUESTED_FILE_DOES_NOT_EXIST_ANYMORE');
                    $app->enqueueMessage($msg, 'notice');
                    // Only abort for single file download
                    if ($task != 'download_tree') {
                        $this->setRedirect('index.php', '');
                        return;
                    }
                }
            }
            // *********************************************************************
            // Increment hits counter of file, and hits counter of file-user history
            // *********************************************************************
            $filetable = JTable::getInstance('flexicontent_files', '');
            $filetable->hit($file_id);
            if (empty($file->history_id)) {
                $query = ' INSERT #__flexicontent_download_history ' . ' SET user_id = ' . (int) $user->id . '  , file_id = ' . $file_id . '  , last_hit_on = NOW()' . '  , hits = 1';
            } else {
                $query = ' UPDATE #__flexicontent_download_history ' . ' SET last_hit_on = NOW()' . '  , hits = hits + 1' . ' WHERE id = ' . (int) $file->history_id;
            }
            $db->setQuery($query);
            $db->execute();
            // **************************************************************************************************
            // Increment hits on download coupon or delete the coupon if it has expired due to date or hits limit
            // **************************************************************************************************
            if (!empty($file_node->coupon)) {
                if (!$file_node->coupon->has_reached_limit && !$file_node->coupon->has_expired) {
                    $query = ' UPDATE #__flexicontent_download_coupons' . ' SET hits = hits + 1' . ' WHERE id=' . $file_node->coupon->id;
                    $db->setQuery($query);
                    $db->execute();
                }
            }
            // **************************
            // Special case file is a URL
            // **************************
            if ($file->url) {
                // Check for empty URL
                $url = $file->filename_original ? $file->filename_original : $file->filename;
                if (empty($url)) {
                    $msg = "File URL is empty: " . $file->url;
                    $app->enqueueMessage($msg, 'error');
                    return false;
                }
                // skip url-based file if downloading multiple files
                if ($task == 'download_tree') {
                    $msg = "Skipped URL based file: " . $url;
                    $app->enqueueMessage($msg, 'notice');
                    continue;
                }
                // redirect to the file download link
                @header("Location: " . $url . "");
                $app->close();
            }
            // *********************************************************************
            // Set file (tree) node and assign file into valid files for downloading
            // *********************************************************************
            $file->node = $file_node;
            $valid_files[$file_id] = $file;
            $file->hits++;
            $per_downloads = $fields_conf[$field_id]->get('notifications_hits_step', 20);
            if ($fields_conf[$field_id]->get('send_notifications') && $file->hits % $per_downloads == 0) {
                // Calculate (once per file) some text used for notifications
                $file->__file_title__ = $file->altname && $file->altname != $file->filename ? $file->altname . ' [' . $file->filename . ']' : $file->filename;
                $item = new stdClass();
                $item->access = $file->item_access;
                $item->type_id = $file->item_type_id;
                $item->language = $file->item_language;
                $file->__item_url__ = JRoute::_(FlexicontentHelperRoute::getItemRoute($file->itemslug, $file->catslug, 0, $item));
                // Parse and identify language strings and then make language replacements
                $notification_tmpl = $fields_conf[$field_id]->get('notification_tmpl');
                if (empty($notification_tmpl)) {
                    $notification_tmpl = JText::_('FLEXI_HITS') . ": " . $file->hits;
                    $notification_tmpl .= '%%FLEXI_FDN_FILE_NO%% __file_id__:  "__file_title__" ' . "\n";
                    $notification_tmpl .= '%%FLEXI_FDN_FILE_IN_ITEM%% "__item_title__":' . "\n";
                    $notification_tmpl .= '__item_url__';
                }
                $result = preg_match_all("/\\%\\%([^%]+)\\%\\%/", $notification_tmpl, $translate_matches);
                $translate_strings = $result ? $translate_matches[1] : array();
                foreach ($translate_strings as $translate_string) {
                    $notification_tmpl = str_replace('%%' . $translate_string . '%%', JText::_($translate_string), $notification_tmpl);
                }
                $file->notification_tmpl = $notification_tmpl;
                // Send to hard-coded email list
                $send_all_to_email = $fields_conf[$field_id]->get('send_all_to_email');
                if ($send_all_to_email) {
                    $emails = preg_split("/[\\s]*;[\\s]*/", $send_all_to_email);
                    foreach ($emails as $email) {
                        $email_recipients[$email][] = $file;
                    }
                }
                // Send to item owner
                $send_to_current_item_owner = $fields_conf[$field_id]->get('send_to_current_item_owner');
                if ($send_to_current_item_owner) {
                    $email_recipients[$file->item_owner_email][] = $file;
                }
                // Send to email assigned to email field in same content item
                $send_to_email_field = (int) $fields_conf[$field_id]->get('send_to_email_field');
                if ($send_to_email_field) {
                    $q = 'SELECT value ' . ' FROM #__flexicontent_fields_item_relations ' . ' WHERE field_id = ' . $send_to_email_field . ' AND item_id=' . $content_id;
                    $db->setQuery($q);
                    $email_values = $db->loadColumn();
                    foreach ($email_values as $i => $email_value) {
                        if (@unserialize($email_value) !== false || $email_value === 'b:0;') {
                            $email_values[$i] = unserialize($email_value);
                        } else {
                            $email_values[$i] = array('addr' => $email_value, 'text' => '');
                        }
                        $addr = @$email_values[$i]['addr'];
                        if ($addr) {
                            $email_recipients[$addr][] = $file;
                        }
                    }
                }
            }
        }
        //echo "<pre>". print_r($valid_files, true) ."</pre>";
        //echo "<pre>". print_r($email_recipients, true) ."</pre>";
        //sjexit();
        if (!empty($email_recipients)) {
            ob_start();
            $sendermail = $app->getCfg('mailfrom');
            $sendermail = JMailHelper::cleanAddress($sendermail);
            $sendername = $app->getCfg('sitename');
            $subject = JText::_('FLEXI_FDN_FILE_DOWNLOAD_REPORT');
            $message_header = JText::_('FLEXI_FDN_FILE_DOWNLOAD_REPORT_BY') . ': ' . $user->name . ' [' . $user->username . ']';
            // ****************************************************
            // Send email notifications about file being downloaded
            // ****************************************************
            // Personalized email per subscribers
            foreach ($email_recipients as $email_addr => $files_arr) {
                $to = JMailHelper::cleanAddress($email_addr);
                $_message = $message_header;
                foreach ($files_arr as $filedata) {
                    $_mssg_file = $filedata->notification_tmpl;
                    $_mssg_file = str_ireplace('__file_id__', $filedata->id, $_mssg_file);
                    $_mssg_file = str_ireplace('__file_title__', $filedata->__file_title__, $_mssg_file);
                    $_mssg_file = str_ireplace('__item_title__', $filedata->item_title, $_mssg_file);
                    //$_mssg_file = str_ireplace('__item_title_linked__', $filedata->password, $_mssg_file);
                    $_mssg_file = str_ireplace('__item_url__', $filedata->__item_url__, $_mssg_file);
                    $count = 0;
                    $_mssg_file = str_ireplace('__file_hits__', $filedata->hits, $_mssg_file, $count);
                    if ($count == 0) {
                        $_mssg_file = JText::_('FLEXI_HITS') . ": " . $file->hits . "\n" . $_mssg_file;
                    }
                    $_message .= "\n\n" . $_mssg_file;
                }
                //echo "<pre>". $_message ."</pre>";
                $from = $sendermail;
                $fromname = $sendername;
                $recipient = array($to);
                $html_mode = false;
                $cc = null;
                $bcc = null;
                $attachment = null;
                $replyto = null;
                $replytoname = null;
                $send_result = FLEXI_J16GE ? JFactory::getMailer()->sendMail($from, $fromname, $recipient, $subject, $_message, $html_mode, $cc, $bcc, $attachment, $replyto, $replytoname) : JUtility::sendMail($from, $fromname, $recipient, $subject, $_message, $html_mode, $cc, $bcc, $attachment, $replyto, $replytoname);
            }
            ob_end_clean();
        }
        // * Required for IE, otherwise Content-disposition is ignored
        if (ini_get('zlib.output_compression')) {
            ini_set('zlib.output_compression', 'Off');
        }
        if ($task == 'download_tree') {
            // Create target (top level) folder
            JFolder::create($targetpath, 0755);
            // Copy Files
            foreach ($valid_files as $file) {
                JFile::copy($file->abspath, $file->node->targetpath);
            }
            // Create text/html file with ITEM title / descriptions
            // TODO replace this with a TEMPLATE file ...
            $desc_filename = $targetpath . DS . "_descriptions";
            $handle_txt = fopen($desc_filename . ".txt", "w");
            $handle_htm = fopen($desc_filename . ".htm", "w");
            fprintf($handle_htm, '
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-gb" lang="en-gb" dir="ltr" >
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />		
</head>
<body>
');
            foreach ($valid_files as $file) {
                fprintf($handle_txt, "%s", $file->item_title . "\n\n");
                fprintf($handle_txt, "%s", flexicontent_html::striptagsandcut($file->item_introtext) . "\n\n");
                if (strlen($file->item_fulltext)) {
                    fprintf($handle_txt, "%s", flexicontent_html::striptagsandcut($file->item_fulltext) . "\n\n");
                }
                fprintf($handle_htm, "%s", "<h2>" . $file->item_title . "</h2>");
                fprintf($handle_htm, "%s", "<blockquote>" . $file->item_introtext . "</blockquote><br/>");
                if (strlen($file->item_fulltext)) {
                    fprintf($handle_htm, "%s", "<blockquote>" . $file->item_fulltext . "</blockquote><br/>");
                }
                fprintf($handle_htm, "<hr/><br/>");
            }
            fclose($handle_txt);
            fclose($handle_htm);
            // Get file list recursively, and calculate archive filename
            $fileslist = JFolder::files($targetpath, '.', $recurse = true, $fullpath = true);
            $archivename = $tmp_ffname . '.zip';
            $archivepath = JPath::clean($app->getCfg('tmp_path') . DS . $archivename);
            // ******************
            // Create the archive
            // ******************
            /*$app = JFactory::getApplication('administrator');
            		$files = array();
            		foreach ($fileslist as $i => $filename) {
            			$files[$i]=array();
            			$files[$i]['name'] = preg_replace("%^(\\\|/)%", "", str_replace($targetpath, "", $filename) );  // STRIP PATH for filename inside zip
            			$files[$i]['data'] = implode('', file($filename));   // READ contents into string, here we use full path
            			$files[$i]['time'] = time();
            		}
            		
            		$packager = JArchive::getAdapter('zip');
            		if (!$packager->create($archivepath, $files)) {
            			$msg = JText::_('FLEXI_OPERATION_FAILED'). ": compressed archive could not be created";
            			$app->enqueueMessage($msg, 'notice');
            			$this->setRedirect('index.php', '');
            			return;
            		}*/
            $za = new flexicontent_zip();
            $res = $za->open($archivepath, ZipArchive::CREATE);
            if ($res !== true) {
                $msg = JText::_('FLEXI_OPERATION_FAILED') . ": compressed archive could not be created";
                $app->enqueueMessage($msg, 'notice');
                $this->setRedirect('index.php', '');
                return;
            }
            $za->addDir($targetpath, "");
            $za->close();
            // *********************************
            // Remove temporary folder structure
            // *********************************
            if (!JFolder::delete($targetpath)) {
                $msg = "Temporary folder " . $targetpath . " could not be deleted";
                $app->enqueueMessage($msg, 'notice');
            }
            // Delete old files (they can not be deleted during download time ...)
            $tmp_path = JPath::clean($app->getCfg('tmp_path'));
            $matched_files = JFolder::files($tmp_path, 'fcmd_uid_.*', $recurse = false, $fullpath = true);
            foreach ($matched_files as $archive_file) {
                //echo "Seconds passed:". (time() - filemtime($tmp_folder)) ."<br>". "$filename was last modified: " . date ("F d Y H:i:s.", filemtime($tmp_folder)) . "<br>";
                if (time() - filemtime($archive_file) > 3600) {
                    JFile::delete($archive_file);
                }
            }
            // Delete old tmp folder (in case that the some archiving procedures were interrupted thus their tmp folder were not deleted)
            $matched_folders = JFolder::folders($tmp_path, 'fcmd_uid_.*', $recurse = false, $fullpath = true);
            foreach ($matched_folders as $tmp_folder) {
                //echo "Seconds passed:". (time() - filemtime($tmp_folder)) ."<br>". "$filename was last modified: " . date ("F d Y H:i:s.", filemtime($tmp_folder)) . "<br>";
                JFolder::delete($tmp_folder);
            }
            $dlfile = new stdClass();
            $dlfile->filename = 'cart_files_' . date('m-d-Y_H-i-s') . '.zip';
            // a friendly name instead of  $archivename
            $dlfile->abspath = $archivepath;
        } else {
            $dlfile = reset($valid_files);
        }
        // Get file filesize and extension
        $dlfile->size = filesize($dlfile->abspath);
        $dlfile->ext = strtolower(JFile::getExt($dlfile->filename));
        // Set content type of file (that is an archive for multi-download)
        $ctypes = array("pdf" => "application/pdf", "exe" => "application/octet-stream", "rar" => "application/zip", "zip" => "application/zip", "txt" => "text/plain", "doc" => "application/msword", "xls" => "application/vnd.ms-excel", "ppt" => "application/vnd.ms-powerpoint", "gif" => "image/gif", "png" => "image/png", "jpeg" => "image/jpg", "jpg" => "image/jpg", "mp3" => "audio/mpeg");
        $dlfile->ctype = isset($ctypes[$dlfile->ext]) ? $ctypes[$dlfile->ext] : "application/force-download";
        // *****************************************
        // Output an appropriate Content-Type header
        // *****************************************
        header("Pragma: public");
        // required
        header("Expires: 0");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Cache-Control: private", false);
        // required for certain browsers
        header("Content-Type: " . $dlfile->ctype);
        //quotes to allow spaces in filenames
        $download_filename = strlen($dlfile->filename_original) ? $dlfile->filename_original : $dlfile->filename;
        if ($method == 'view') {
            header("Content-Disposition: inline; filename=\"" . $download_filename . "\";");
        } else {
            header("Content-Disposition: attachment; filename=\"" . $download_filename . "\";");
        }
        header("Content-Transfer-Encoding: binary");
        header("Content-Length: " . $dlfile->size);
        // *******************************
        // Finally read file and output it
        // *******************************
        if (!FLEXIUtilities::funcIsDisabled('set_time_limit')) {
            @set_time_limit(0);
        }
        $chunksize = 1 * (1024 * 1024);
        // 1MB, highest possible for fread should be 8MB
        if (1 || $dlfile->size > $chunksize) {
            $handle = @fopen($dlfile->abspath, "rb");
            while (!feof($handle)) {
                print @fread($handle, $chunksize);
                ob_flush();
                flush();
            }
            fclose($handle);
        } else {
            // This is good for small files, it will read an output the file into
            // memory and output it, it will cause a memory exhausted error on large files
            ob_clean();
            flush();
            readfile($dlfile->abspath);
        }
        // ****************************************************
        // In case of multi-download clear the session variable
        // ****************************************************
        //if ($task=='download_tree') $session->set($tree_var, false,'flexicontent');
        // Done ... terminate execution
        $app->close();
    }