<?php
/**
 * VFM - veno file manager downloader
 *
 * PHP version >= 7.4
 *
 * @category  PHP
 * @package   VenoFileManager
 * @author    Nicola Franchini <support@veno.it>
 * @copyright 2013 Nicola Franchini
 * @license   https://veno.es/shop/help Veno Commercial License
 * @link      http://filemanager.veno.it/
 */
require_once __DIR__.'/class/class.setup.php';
$setUp = new SetUp();
if ($setUp->getConfig('debug_mode') === true) {
    error_reporting(E_ALL);
    ini_set('display_errors', 1);
}
require_once __DIR__.'/class/class.gatekeeper.php';
require_once __DIR__.'/class/class.downloader.php';
require_once __DIR__.'/class/class.utils.php';
require_once __DIR__.'/class/class.logger.php';
require_once __DIR__.'/class/class.template.php';

// Redirect blacklisted IPs.
Utils::checkIP();

$setUp = new SetUp();
$gateKeeper = new GateKeeper();
$downloader = new Downloader();
$logger = new Logger();

$timeconfig = $setUp->getConfig('default_timezone');
$timezone = (strlen($timeconfig ?? '') > 0) ? $timeconfig : "UTC";
date_default_timezone_set($timezone);

$script_url = $setUp->getConfig('script_url');

$getzip = filter_input(INPUT_GET, 'zip', FILTER_SANITIZE_SPECIAL_CHARS);
$getfile = filter_input(INPUT_GET, 'q', FILTER_SANITIZE_SPECIAL_CHARS);
$hash = filter_input(INPUT_GET, 'h', FILTER_SANITIZE_SPECIAL_CHARS);
$supah = filter_input(INPUT_GET, 'sh', FILTER_SANITIZE_SPECIAL_CHARS);
$json_file = filter_input(INPUT_GET, 'share', FILTER_SANITIZE_SPECIAL_CHARS);
$playmp3 = filter_input(INPUT_GET, 'audio', FILTER_SANITIZE_SPECIAL_CHARS);

$alt = $setUp->getConfig('salt');
$altone = $setUp->getConfig('session_name');

$android = false;
$useragent = strtolower($_SERVER['HTTP_USER_AGENT']);
if (stripos($useragent, 'android') !== false) {
    $android = true;
}

/**
 * Download single file (for non-logged users)
 */
if ($json_file && is_numeric($getfile)) {
    $filenum = $getfile;
    $share_json = '_content/share/'.$json_file.'.json';

    if (file_exists($share_json)) {
        $datarray = json_decode(file_get_contents($share_json), true);
        $time = $datarray['time'];
        $hash = $datarray['hash'];
        $lifetime = isset($datarray['lifetime']) ? (int)$datarray['lifetime'] : (int)$setUp->getConfig('lifetime');

        if (md5($time.$hash) !== $supah ) {
            Utils::setError('<i class="bi bi-slash-circle"></i> '.$setUp->getString("access_denied"));
            header('Location:'.$script_url);
            exit;
        }

        if ($downloader->checkTime($time, $lifetime)) {
            $pieces = explode(",", $datarray['attachments']);
            if (!count($pieces)) {
                unlink($share_json);
            }
            if (isset($pieces[$filenum])) {
                $getfile = $pieces[$filenum];
                if ($downloader->checkFile($getfile) == true) {
                    $headers = $downloader->getHeaders($getfile, $playmp3);

                    if ($setUp->getConfig('one_time_download')) {
                        unset($pieces[$filenum]);
                        $datarray['attachments'] = implode(',', $pieces);
                        file_put_contents($share_json, json_encode($datarray));
                    }
                    
                    if ($setUp->getConfig('direct_links')) {
                        ($headers['content_type'] == 'audio/mp3') ? $logger->logPlay($headers['trackfile']) : $logger->logDownload($headers['trackfile']);
                        header('Location:'.$script_url.base64_decode($getfile));
                        exit;
                    }
                    if ($downloader->download($headers['file'], $headers['filename'], $headers['file_size'], $headers['content_type'], $headers['disposition'], $android) === true) {
                        $logger->logDownload($headers['trackfile']);
                    }
                    exit;
                }
            }
        }
    }
}

/**
 * Download single file, play Audio or show PDF (for logged users)
 */
if ($getfile && $hash && $downloader->checkFile($getfile) == true && md5($alt.$getfile.$altone.$alt) === $hash) {
    $headers = $downloader->getHeaders($getfile, $playmp3);

    if (($gateKeeper->isUserLoggedIn() && $downloader->subDir($headers['dirname']) == true) || $gateKeeper->isLoginRequired() == false) {
        if ($setUp->getConfig('direct_links')) {
            ($headers['content_type'] == 'audio/mp3') ? $logger->logPlay($headers['trackfile']) : $logger->logDownload($headers['trackfile']);
            header('Location:'.$script_url.base64_decode($getfile));
            exit;
        }
        if ($headers['content_type'] == 'audio/mp3') {
            $logger->logPlay($headers['trackfile']);
        }
        if ($downloader->download($headers['file'], $headers['filename'], $headers['file_size'], $headers['content_type'], $headers['disposition'], $android) === true) {
            if ($headers['content_type'] !== 'audio/mp3') {
                $logger->logDownload($headers['trackfile']);
            }
        }
        exit;
    }
    Utils::setError('<i class="bi bi-slash-circle"></i> '.$setUp->getString("access_denied"));
    header('Location:'.$script_url);
    exit;
}

/**
 * Download zipped files (Migrated to Maennchen/ZipStream)
 */
if ($getzip) {
    $supahzip = filter_input(INPUT_GET, 'n', FILTER_SANITIZE_SPECIAL_CHARS);
    $zip_json = __DIR__.'/tmp/'.$getzip.'.json';

    if (file_exists($zip_json)) {
        $datarray = json_decode(file_get_contents($zip_json), true);
        $time = $datarray['time'];
        $hash = $datarray['hash'];
        $folder = $datarray['dir'];
        $files = $datarray['files'];

        if (md5($time.$hash) !== $supahzip ) {
            Utils::setError('<i class="bi bi-slash-circle"></i> '.$setUp->getString("access_denied"));
            header('Location:'.$script_url);
            exit;
        }

        if ($folder || $files) {
            @set_time_limit(0);
            session_write_close();
            
            // Carica il nuovo autoloader (Maennchen/ZipStream)
            include_once __DIR__.'/assets/zipstream-php/autoload.php';
            
            $cleanpath = dirname(__DIR__).'/'.ltrim($setUp->getConfig('starting_dir'), './');
            
            // Setup opzioni ZipStream
            $options = new \ZipStream\Option\Archive();
            $options->setSendHttpHeaders(true); // Invia gli header automaticamente
        }

        // Caso 1: Download di una cartella intera
        if ($folder) {
            $folder_to_zip = $cleanpath . $folder;
            $folderpathinfo = Utils::mbPathinfo($folder_to_zip);
            $archivename = Utils::checkMagicQuotes($folderpathinfo['filename']);

            if (ob_get_level()) {
                ob_end_clean();
            }

            $zip = new \ZipStream\ZipStream($archivename.'.zip', $options);

            // MODIFICA 1: Usare SELF_FIRST anziché LEAVES_ONLY per includere anche le cartelle nel ciclo
            $files_to_zip = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($folder_to_zip, RecursiveDirectoryIterator::SKIP_DOTS),
                RecursiveIteratorIterator::SELF_FIRST
            );

            foreach ($files_to_zip as $name => $file) {
                $filePath = $file->getRealPath();
                
                // Calcoliamo il path relativo all'interno dello zip.
                // Usiamo str_replace per convertire eventuali backslash di Windows (\)
                // in slash standard (/) richiesti dal formato ZIP.
                $relativePath = $files_to_zip->getSubPathName();
                $relativePath = str_replace('\\', '/', $relativePath);
                $archivePath = $archivename . '/' . $relativePath;

                if ($file->isDir()) {
                    // MODIFICA 2: Aggiunge la entry della directory nello ZIP. 
                    // Nello standard ZIP si ottiene appendendo uno slash '/' alla fine del nome 
                    // e passandogli una stringa vuota come contenuto.
                    $zip->addFile($archivePath . '/', '');
                } else {
                    $zip->addFileFromPath($archivePath, $filePath);
                }
            }
            $zip->finish();
            $logger->logDownload($folder, true);
        }

        // Caso 2: Download di file multipli selezionati
        if ($files) {
            $archivename = 'zip-'.$time;
            if (ob_get_level()) {
                ob_end_clean();
            }

            $zip = new \ZipStream\ZipStream($archivename.'.zip', $options);

            foreach ($files as $file) {
                $filePath = $cleanpath . $file;
                if (file_exists($filePath)) {
                    // Aggiunge il file usando il path assoluto ma salvandolo con nome relativo nello zip
                    $zip->addFileFromPath($archivename . '/' . basename($file), $filePath);
                }
            }
            $zip->finish();
            $logger->logDownload($files);
        }

        unlink($zip_json);
        exit;
    }
}
Utils::setError($setUp->getString("link_expired"));
header('Location:'.$script_url);
exit;
