<?php

/*
 *
 * Upload class of Droppy - Online file sharing
 * Author: Proxibolt
 *
 */

require_once dirname(__FILE__) . '/encrypt.class.php';

/**
 * Class Upload
 */
class Upload
{
    /**
     * Upload constructor.
     */
    function __construct()
    {
        global
            $mysqli,
            $table_uploads,
            $table_files,
            $table_receivers,
            $blocked_types,
            $max_file_size,
            $max_upload_files,
            $upload_dir,
            $name_on_file,
            $site_url,
            $site_name,
            $expire,
            $text,
            $encrypt_files;

        // Make it accessible across this class
        $this->mysqli           = $mysqli;
        $this->table_uploads    = $table_uploads;
        $this->table_files      = $table_files;
        $this->table_receivers  = $table_receivers;
        $this->blocked_types    = $blocked_types;
        $this->max_file_size    = $max_file_size;
        $this->max_upload_files = $max_upload_files;
        $this->upload_dir       = $upload_dir;
        $this->name_on_file     = $name_on_file;
        $this->site_url         = $site_url;
        $this->site_name        = $site_name;
        $this->expire           = $expire;
        $this->text             = $text;
        $this->encrypt_files    = $encrypt_files;
    }

    /**
     * Function will check if the upload_id already exists
     * @param $upload_id
     * @return bool
     */
    function exists($upload_id)
    {
        $check_upload_hash = $this->mysqli->query("SELECT * FROM $this->table_uploads WHERE upload_id='$upload_id'");

        if($check_upload_hash->num_rows == 0) {
            //Upload does not exist
            return false;
        }
        else
        {
            //Upload does exist
            return true;
        }
    }

    /**
     * Function will create file list for the emails
     * @param $filename_array
     * @return string
     */
    function createFilelist($filename_array)
    {
        $file_names = '<ul>';
        foreach($filename_array as $name_file) {
            $file_names .= '<li>' . $name_file . '</li>';
        }
        $file_names .= '</ul>';

        return $file_names;
    }

    /**
     * Function will check if there are any illegal files
     * @param $filetype_array
     * @return bool
     */
    function notIllegal($filetype_array)
    {
        $total_illegal = 0;

        //Check for blocked types in array
        foreach($filetype_array as $filetype) {
            if(in_array($filetype, $this->blocked_types)) {
                $total_illegal++;
            }
        }

        if($total_illegal == 0) {
            //No illegal files have been found
            return true;
        }
        else
        {
            //Illegal file(s) have been found
            return false;
        }
    }

    /**
     * Function will check if the total upload is not larger than maximum
     * @param $file
     * @return bool
     */
    function notTooLarge($file)
    {
        $total_size = array_sum($file['size']);

        if($total_size < $this->max_file_size) {
            // The size is good
            return true;
        }
        else
        {
            // Not good, too large
            return false;
        }
    }

    /**
     * Function checks if the total amount of file is not larger than the maximum
     * @param $file
     * @return bool
     */
    function notTooMany($file)
    {
        $total_files = count($file['tmp_name']);

        //Check if the amount of files is not larger than the maximum allowed.
        if($total_files <= $this->max_upload_files || $this->max_upload_files == '') {
            return true;
        }
        else
        {
            return false;
        }
    }

    /**
     * Function will delete the upload from the database (Only database)
     * @param $upload_id
     * @return bool
     */
    function deleteUpload($upload_id)
    {
        $this->mysqli->query("DELETE FROM $this->table_uploads WHERE upload_id='$upload_id'");

        return true;
    }

    /**
     * Function will check if the upload is allowed to be uploaded
     * @param $file
     * @param $upload_id
     * @return bool
     */
    function checkAllowed($file, $upload_id)
    {
        $return = array();

        // Check if all the file types are allowed
        // Check if the total file is not larger than the maximum allowed
        // Check if the total file amount is not larger than the maximum allowed
        if($this->notIllegal($file['type']) && $this->notTooLarge($file) && $this->notTooMany($file))
        {
            // Everything ok
            return true;
        }
        else
        {
            // Upload has blocked file type
            $this->deleteUpload($upload_id);
            return false;
        }
    }

    /**
     * Function escapes filenames
     * @param $filename
     * @return mixed
     */
    function escapeChars($filename)
    {
        // adding - for spaces and union characters
        $find = array(' ', '&', '\r\n', '\n', '+',',');
        $filename = str_replace ($find, '-', $filename);

        return $filename;
    }

    /**
     * Function will process the file upload and store everything in the database
     * @param $file
     * @param $upload_id
     * @param $upload_language
     * @param $share
     * @param $msg
     * @param $password
     * @param $pwd
     * @param $destruct
     * @param $email_to
     * @param $email_from
     */
    function upload($file, $upload_id, $upload_language, $share, $msg, $password, $pwd, $destruct, $email_to, $email_from)
    {
        // The response array
        $return = array();

        // Setting the time the file needs to expire
        $time_expire = (time() + $this->expire);

        // Create random upload hash
        $upload_hash = md5(time() . rand() . rand());

        // Get the current unix time
        $time = time();

        // Get the IP address of the uploader
        if(isset($_SERVER['REMOTE_ADDR']) && !empty($_SERVER['REMOTE_ADDR'])) {
            $ip = $_SERVER['REMOTE_ADDR'];
        } else {
            $ip = 'not_set';
        }

        // This will check if the upload is made on mobile/tablet or computer
        $detect     = new Mobile_Detect;
        $encrypt    = new Encrypt();

        // Check if the upload_id does not already exist
        if(!$this->exists($upload_id))
        {
            // Store some general upload data in the return array
            $return['upload_id'] = $upload_id;
            $return['upload_type'] = $share;

            // Insert the first upload data into the table
            $this->mysqli->query("INSERT INTO $this->table_uploads (upload_id, email_from, message, secret_code, password, status, size, time, time_expire, ip, count, share, destruct, lang) VALUES ('$upload_id', '$email_from', '$msg', '$upload_hash', '$pwd', 'processing', '0', '$time', '$time_expire', '$ip', '0', '$share', '$destruct', '$upload_language')");

            // Check if allowed to be uploaded
            if($this->checkAllowed($file, $upload_id))
            {
                // Get some more info from the upload
                $total_size     = array_sum($file['size']); // Total size of all uploads
                $total_files    = count($file['tmp_name']); // Total amount of files for this upload

                // Place the files in the tmp/ directory
                foreach ($file['name'] as $f => $name) {
                    // Create random md5 hash
                    $hash = md5(time() . rand() . rand());
                    // Replace all the special characters with normal characters.
                    $name = $this->escapeChars($name);

                    // Check for errors, if there are any then return it.
                    if ($file['error'][$f] == 4) {
                        $response_array['upload_error'] = 'true';
                    }
                    if ($file['error'][$f] == 0) {
                        // No error found! Move uploaded files and insert data into database
                        $this->mysqli->query("INSERT INTO $this->table_files (upload_id, secret_code, file) VALUES ('$upload_id','$hash','$name')");
                        move_uploaded_file($file['tmp_name'][$f], dirname(__FILE__) . '/../../' . $this->upload_dir . 'tmp/' . $hash.'-'.$name);
                    }
                }

                // Get the files from the db
                $get_file_info = $this->mysqli->query("SELECT * FROM $this->table_files WHERE upload_id='$upload_id'");

                // If the total amount of files is larger than 1 Droppy will zip the files.
                if($total_files > 1) {
                    // Some information about the zip file
                    $ziplocation    = dirname(__FILE__) . '/../../' . $this->upload_dir . $this->name_on_file . '-' . $upload_id .'.zip';
                    $zipname        = $this->name_on_file . '-' . $upload_id . '.zip';

                    // Initialize ZipArchive
                    $zip = new ZipArchive();
                    // Open a new zip file
                    $zip->open($ziplocation, ZipArchive::CREATE);
                    // Add all files from this upload to a zip file
                    while($row = $get_file_info->fetch_assoc()) {
                        // Some general info about the file
                        $file_name  = $row['file'];
                        $secret     = $row['secret_code'];
                        $useragent  = $_SERVER['HTTP_USER_AGENT'];

                        // If is uploaded from mobile than add the random file id to the filename
                        // Most of the time mobiles upload a file with the same name, so that's why we will add a random id to it.
                        if($detect->isMobile() || $detect->isTablet()) {
                            $zip->addFile(dirname(__FILE__) . '/../../' . $this->upload_dir . 'tmp/' . $secret . '-' . $file_name, $secret . '_' . $file_name);
                        } else {
                            $zip->addFile(dirname(__FILE__) . '/../../' . $this->upload_dir . 'tmp/' . $secret . '-' . $file_name, $file_name);
                        }
                    }

                    // Finish the zip file by closing it.
                    $zip->close();

                    // Get the finalsize of the zip file
                    $final_size = filesize($ziplocation);

                    //Encrypt the file (If enabled)
                    if($this->encrypt_files == 1)
                    {
                        // Move to tmp for encrypting
                        $encrypt_location   = dirname(__FILE__) . '/../../uploads/tmp/encrypt_' . $zipname;
                        $move_encrypt       = rename($ziplocation, $encrypt_location);

                        //If move ok
                        if($move_encrypt) {
                            // Generate pass and store in the database
                            $passphrase = $encrypt->generatePass();
                            $encrypting = $encrypt->encryptfile($encrypt_location, $ziplocation, $passphrase);

                            //If encrypting ok
                            if($encrypting) {
                                $this->mysqli->query("UPDATE $this->table_uploads SET encrypt='$passphrase' WHERE upload_id='$upload_id'");

                                unlink($encrypt_location);
                            }
                        }
                    }
                }
                // If the total amount of files is just 1 it will be a single file upload
                else
                {
                    $file_info = $get_file_info->fetch_assoc();

                    // Move the file from the tmp directory to the main directory.
                    $tmp_location = dirname(__FILE__) . '/../../' . $this->upload_dir . 'tmp/' . $file_info['secret_code'].'-'.$file_info['file'];
                    $new_location = dirname(__FILE__) . '/../../' . $this->upload_dir . $file_info['secret_code'].'-'.$file_info['file'];

                    //Encrypt the file (If enabled)
                    if($this->encrypt_files == 1)
                    {
                        // Generate pass and store in the database
                        $passphrase = $encrypt->generatePass();

                        $encrypting = $encrypt->encryptfile($tmp_location, $new_location, $passphrase);

                        $this->mysqli->query("UPDATE $this->table_uploads SET encrypt='$passphrase' WHERE upload_id='$upload_id'");
                    }
                    else
                    {
                        // Move it
                        rename($tmp_location, $new_location);
                    }

                    // Get the finalsize of the zip file
                    $final_size = filesize($new_location);
                }

                // Removes the "not zipped" files from the server
                $get_file_info = $this->mysqli->query("SELECT * FROM $this->table_files WHERE upload_id='$upload_id'");
                while($row = $get_file_info->fetch_assoc()) {
                    $file_name      = $row['file'];
                    $secret         = $row['secret_code'];
                    $file_location  = dirname(__FILE__) . '/../../' . $this->upload_dir . 'tmp/' . $secret . '-' . $file_name;
                    unlink($file_location);
                }

                if(!isset($final_size) || $final_size == 0 || empty($final_size))
                {
                    // Stop running any further
                    exit;
                }

                // Insert the data of the upload into the database and set the status to "ready"
                $this->mysqli->query("UPDATE $this->table_uploads SET status='ready', size='$final_size', count='$total_files' WHERE upload_id='$upload_id'");

                // If the share type is email then send out an email all the recipients
                if($share == 'mail') {
                    // Create an email list
                    $email_list = '<ul>';
                    foreach($email_to as $recipient_email) {
                        $email_list .= '<li>' . $recipient_email . '</li>';
                    }
                    $email_list .= '</ul>';

                    // Send an email to every recipient
                    foreach($email_to as $emails_to) {
                        if(!empty($emails_to)) {
                            $emails_to = mysqli_real_escape_string($this->mysqli, $emails_to);

                            // Store the recipient in the database
                            if($emails_to != '' || $emails_to != null) {
                                $private_id = substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'), 0, 15);
                                $this->mysqli->query("INSERT INTO $this->table_receivers (upload_id, email, private_id) VALUES ('$upload_id','$emails_to','$private_id')");
                            }

                            $message_receiver = requestTemplate('receiver',$upload_language);
                            $receiver_subject = requestTemplate('receiver_subject',$upload_language);

                            // Shortcodes replacements
                            $tokens = array(
                                'email_to' => $emails_to,
                                'email_from' => $email_from,
                                'size' => round($final_size / 1048576, 2),
                                'site_name' => $this->site_name,
                                'upload_id' => $upload_id,
                                'message' => nl2br($_POST['message']),
                                'total_files' => $total_files,
                                'expire_time' => secs_to_h($this->expire),
                                'file_list' => $this->createFilelist($file['name']),
                                'password' => $password,
                                'email_list' => $email_list,
                                'download_btn' => '<a href="' . $this->site_url . $upload_id . '&p=' . $private_id . '" style="text-decoration: none;color: #FFF;background-color: #348eda;border: solid #348eda;border-width: 10px 20px;line-height: 2;font-weight: bold;margin-right: 10px;text-align: center;cursor: pointer;display: inline-block;border-radius: 25px;">' . $this->text['download'] . '</a>',
                                'download_url' => $this->site_url . $upload_id . '&p=' . $private_id,
                            );

                            $pattern = '{%s}';

                            $map = array();
                            foreach($tokens as $var => $value)
                            {
                                $map[sprintf($pattern, $var)] = $value;
                            }

                            $message_receiver = strtr($message_receiver, $map);
                            $receiver_subject = strtr($receiver_subject, $map);

                            emailSender($message_receiver,$receiver_subject,$emails_to,$email_from);

                            unset($tokens);
                        }
                    }

                    // Sending the email to the sender of the file
                    $tokens = array(
                        'email_from' => $email_from,
                        'size' => round($final_size / 1048576, 2),
                        'site_name' => $this->site_name,
                        'upload_id' => $upload_id,
                        'message' => nl2br($_POST['message']),
                        'total_files' => $total_files,
                        'expire_time' => secs_to_h($this->expire),
                        'password' => $password,
                        'file_list' => $this->createFilelist($file['name']),
                        'email_list' => $email_list,
                        'download_btn' => '<a href="' . $this->site_url . $upload_id . '&a=' . $upload_hash . '" style="text-decoration: none;color: #FFF;background-color: #348eda;border: solid #348eda;border-width: 10px 20px;line-height: 2;font-weight: bold;margin-right: 10px;text-align: center;cursor: pointer;display: inline-block;border-radius: 25px;">' . $this->text['download'] . '</a>',
                        'download_url' => $this->site_url . $upload_id . '&a=' . $upload_hash,
                    );

                    $pattern = '{%s}';

                    $map = array();
                    foreach($tokens as $var => $value)
                    {
                        $map[sprintf($pattern, $var)] = $value;
                    }

                    $message_sender = strtr(requestTemplate('sender',$upload_language), $map);
                    $sender_subject = strtr(requestTemplate('sender_subject',$upload_language), $map);

                    emailSender($message_sender,$sender_subject,$email_from);
                }
            }
            else
            {
                //Not allowed return result
                $return['upload_error'] = 'true';
            }
        }
        else
        {
            // Upload already exists
            $return['upload_error'] = 'true';
        }
    }

    function setPremiumUser($upload_id) {
        if(isset($droppy_premium) && $droppy_premium == 'true' && isset($_SESSION['droppy_premium'])) {
            $sessionemail = $_SESSION['droppy_premium'];
            $this->mysqli->query("UPDATE $this->table_uploads SET pm_email='$sessionemail' WHERE upload_id='$upload_id'");

            return true;
        }
        return false;
    }

    function delete($id) {
        global $site_name, $language;

        $get_upload = $this->mysqli->query("SELECT * FROM $this->table_uploads WHERE upload_id='$id'");
        while($uploads = $get_upload->fetch_assoc()) {
            $get_files = $this->mysqli->query("SELECT * FROM $this->table_files WHERE upload_id='$id'");
            $file_names = '<ul>';
            while($files = $get_files->fetch_assoc()) {
                $file_names .= '<li>' . $files['file'] . '</li>';
            }
            $file_names .= '</ul>';

            $get_receivers = $this->mysqli->query("SELECT * FROM $this->table_receivers WHERE upload_id='$id'");
            $email_list = '<ul>';
            while($emails = $get_receivers->fetch_assoc()) {
                $email_list .= '<li>' . $emails['email'] . '</li>';
            }
            $email_list .= '</ul>';

            if(empty($uploads['lang'])) {
                $upload_language = $language;
            }
            else
            {
                $upload_language = $uploads['lang'];
            }

            $tokens = array(
                'email_from' 	=> $uploads['email_from'],
                'size' 			=> round($uploads['size'] / 1048576, 2),
                'site_name' 	=> $site_name,
                'upload_id' 	=> $uploads['upload_id'],
                'message' 		=> $uploads['message'],
                'total_files' 	=> $uploads['count'],
                'expire_time' 	=> $uploads['expire_time'],
                'file_list' 	=> $file_names,
                'email_list' 	=> $email_list
            );

            $pattern = '{%s}';

            $map = array();
            foreach($tokens as $var => $value)
            {
                $map[sprintf($pattern, $var)] = $value;
            }

            $message_destruct = strtr(requestTemplate('destroyed',$upload_language), $map);
            $destroyed_subject = strtr(requestTemplate('destroyed_subject',$upload_language), $map);

            //Email user
            emailSender($message_destruct,$destroyed_subject,$uploads['email_from']);

            if($uploads['count'] > 1) {
                unlink('../' . $this->upload_dir . $this->name_on_file . '-' . $id . '.zip');
            }
            else
            {
                $get_files = $this->mysqli->query("SELECT * FROM $this->table_files WHERE upload_id='$id'");
                while($row = $get_files->fetch_assoc()) {
                    unlink('../' . $this->upload_dir . $row['secret_code'] . '-' . $row['file']);
                }
            }
        }
        $this->mysqli->query("UPDATE $this->table_uploads SET status='destroyed' WHERE upload_id='$id'");

        return true;
    }
}