Разделение кода многофайлового загрузчика CodeIgniter DropZone на MVC?

Я новичок в CodeIgniter и пытаюсь преобразовать работающий многофайловый загрузчик DropZone в MVC CodeIgniter. формат. Я видел здесь несколько других примеров, но мне нужно получить рекомендации для моего конкретного кода.

Я знаю, как разместить страницу загрузки/формы в представлении и загрузить через контроллер. Однако мне нужна помощь в коде обработчика формы.

Страница загрузки/формы:

<head>
<script type="text/javascript" src="js/jquery-2.1.1.js"></script>
<!-- Add Dropzone -->
<link rel="stylesheet" type="text/css" href="css/dropzone.css" />
<script type="text/javascript" src="js/dropzone.js"></script>
</head>
<body>
<div class="image_upload_div">
<form action="upload_thumbnails.php" class="dropzone">
</form>
</div>  

<script type="text/javascript">
//Disabling autoDiscover
Dropzone.autoDiscover = false;
$(function() {
    //Dropzone class
    var myDropzone = new Dropzone(".dropzone");
    myDropzone.on("queuecomplete", function() {
        //Redirect URL
        //window.location.href = 'http://php.net';
    });
});
</script>
</body>

Какие части кода обработчика формы должны быть в модели и в контроллере? Это раздел, с которым я борюсь.

Код обработчика формы:

if(!empty($_FILES)){    

  function createThumbnail($filename) {
    $final_width_of_image = 200;
    $path_to_image_directory = 'uploads/';
    $path_to_thumbs_directory = 'uploads/thumbs/';

    if(preg_match('/[.](jpg)$/', $filename)) {
        $im = imagecreatefromjpeg($path_to_image_directory . $filename);
    } else if (preg_match('/[.](gif)$/', $filename)) {
        $im = imagecreatefromgif($path_to_image_directory . $filename);
    } else if (preg_match('/[.](png)$/', $filename)) {
        $im = imagecreatefrompng($path_to_image_directory . $filename);
    }

    $ox = imagesx($im);
    $oy = imagesy($im);
    $nx = $final_width_of_image;
    $ny = floor($oy * ($final_width_of_image / $ox));
    $nm = imagecreatetruecolor($nx, $ny);
    if(!imagecopyresized($nm, $im, 0,0,0,0,$nx,$ny,$ox,$oy)){
        header("HTTP/1.0 500 Internal Server Error");
        echo 'Thumbnail Not created';
        exit(); 
    }
    if(!file_exists($path_to_thumbs_directory)) {
        if(!mkdir($path_to_thumbs_directory)) {
            header("HTTP/1.0 500 Internal Server Error");
            echo 'Thumbnail Not Created';
            exit();
        } 
    }
    // Save new thumbnail image
    imagejpeg($nm, $path_to_thumbs_directory . $filename);

  }

//database configuration
$dbHost = 'localhost';
$dbUsername = 'insertnamehere';
$dbPassword = 'insertpwhere';
$dbName = 'ci_local';
//connect with the database
$conn = new mysqli($dbHost, $dbUsername, $dbPassword, $dbName);
if($mysqli->connect_errno){
    echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
}

$targetDir = "uploads/";
$fileName = $_FILES['file']['name'];
$targetFile = $targetDir.$fileName;

if(move_uploaded_file($_FILES['file']['tmp_name'],$targetFile)){
    // NEW
    //createThumbnail($file['file']['name']);
    createThumbnail($fileName);
    // NEW

    //insert file information into db table
    $conn->query("INSERT INTO files (file_name, uploaded) VALUES('".$fileName."','".date("Y-m-d H:i:s")."')");
} else {
    echo "Ooops";
}

}

Любые рекомендации будут высоко оценены.


person 12AX7    schedule 11.12.2017    source источник
comment
Почему вы не используете библиотеку загрузки codeigniter и систему баз данных? Вот для чего нужны рамки!   -  person Alex    schedule 12.12.2017
comment
Библиотека загрузки CI предназначена для загрузки отдельных файлов. Я использую DropZone для перетаскивания многофайловых загрузок и просто перечислил обычный пример HTML, ища, в частности, как получить тот же самый код wkg в формате CI (MVC).   -  person 12AX7    schedule 12.12.2017
comment
DropZone делает это асинхронно, используя разные экземпляры скрипта. Вам не нужно работать с несколькими файлами одновременно (и здесь вы этого тоже не делаете)! Даже если бы вам пришлось, вы все равно могли бы использовать цикл foreach и библиотеку загрузки CI. Кроме того, я могу легко испортить вашу базу данных с помощью инструкции sql в качестве имени файла, поскольку вы не экранируете свои строки. Это еще одна причина использовать фреймворк по назначению с построителем запросов, он сделает это за вас! Не говоря уже о том, что библиотека загрузки CI также сделает имена файлов безопасными.   -  person Alex    schedule 12.12.2017
comment
Удачное замечание относительно экранирования строк в запросе - я просто пропустил это при использовании моего примера кода. Я пришел к выводу, что невозможно выполнить что-либо, кроме загрузки одного файла с помощью среды CI без использования специального кода. Можете ли вы показать пример использования цикла foreach и библиотеки загрузки CI для выполнения загрузки нескольких файлов?   -  person 12AX7    schedule 12.12.2017
comment
Пожалуйста, перечитайте первую часть моего предыдущего комментария. Dropzone — это Ajax, вы просто загружаете по одному, но он делает это в нескольких экземплярах, поэтому вы можете обрабатывать x количество файлов одновременно. Он не публикует все это в один экземпляр. Чтобы загрузить несколько файлов обычным способом, даже вам в приведенном выше коде придется использовать цикл foreach для прохода по массиву файлов. Тот факт, что вы не доказываете то, что я пытаюсь донести.   -  person Alex    schedule 12.12.2017
comment
При этом нет никакой реальной проблемы в том, чтобы не использовать библиотеку CI (просто сделайте эти имена файлов безопасными!). Я просто предпочитаю использовать все инструменты, которые предоставляет мне фреймворк, поэтому я не чувствую, что нахожусь в темных веках процедур.   -  person Alex    schedule 12.12.2017
comment
Спасибо за ваши ответы, так как они были очень полезны. Я определенно согласен с тем, что лучше использовать инфраструктуру CI, поскольку она предоставляет предварительно написанный код, поэтому нет необходимости изобретать велосипед.   -  person 12AX7    schedule 12.12.2017


Ответы (1)


Ваша функция createThumbnail — хороший пример того, что должно быть либо в модели, либо в библиотеке, либо в помощнике. Помощник просто содержит функции, тогда как библиотека или модель основаны на классах и, следовательно, могут обращаться к свойствам класса и иметь конструкторы. Я бы склонялся к тому, чтобы сделать его либо библиотекой, либо помощником, поскольку он не связан (таким образом, повторно используемым) с чем-либо конкретным или другими функциями.

Как правило, вы хотите возвращать или генерировать исключения только в любой функции, которая не находится в контроллере.

  1. Это позволяет вам установить выходные данные в один файл, а не искать в ваших моделях, библиотеках и т. д. если вы хотите изменить свой вывод в будущем (например, если вы планируете использовать AJAX).
  2. Также позволяет использовать кодовые базы, которые не являются тесно связанными и могут быть легко перенесены на другие установки, которые могут отличаться.
  3. Хорошо для удобочитаемости.

Модели

Все, что связано с базой данных, должно быть включено в модель, поскольку модели представляют логику данных или фактические данные, используемые вашим приложением. Вы действительно должны использовать встроенные функции базы данных Codeigniter вместо того, чтобы инициализировать базу данных и выполнять запрос самостоятельно. Ваши операторы вставки или обновления должны перейти в модель, связанную с контроллером.

Контроллеры

Ваш контроллер используется только для загрузки моделей и любых переменных, которые могут потребоваться для просмотра. Его также следует использовать для установки ответа, будь то флэш-сообщение или закодированный json. Во многих примерах он также используется для form_validation или проверки данных перед выполнением операций CRUD, которые существуют в связанной модели.

tl;dr все, что связано с базой данных, передается в модель, все, что можно повторно использовать и не тесно связано, отправляется в библиотеку, или, если это не имеет конкретного отношения к oop, передается в помощник (например, алгоритм сортировки массива), все, что угодно, из формы/ввода /view/response related поступает в контроллер.


Примерно вы можете сделать что-то вроде этого (код может не работать из коробки; я использую свою собственную реализацию, которая отличается от поведения dz по умолчанию, поскольку я также использую jquerys sortable... Я также не уверен в обработке ошибок, как я что с использованием другой техники):

// byte_helper.php

/**
 * Gets max upload size from post_max_size and upload_max_filesize
 * Returns whichever is smaller
 *
 * @return int
 */
function file_upload_max_size() {
    $max_size = convert_to_bytes(ini_get('post_max_size'));
    $upload_max = convert_to_bytes(ini_get('upload_max_filesize'));
    if ($upload_max > 0 && $upload_max < $max_size) {
        $max_size = $upload_max;
    }
    return $max_size;
}

/**
 * Converts KB (K) through GB (G) to bytes
 * 
 * @param string $from
 * @return int bytes
 */
function convert_to_bytes($from) {
    $number = filter_var($from, FILTER_SANITIZE_NUMBER_INT);
    $type = strtoupper(str_replace($number, '', $from));
    switch ($type) {
        case "KB":
        case "K":
            $number = $number * 1024;
            break;
        case "MB":
        case "M":
            $number = $number * pow(1024, 2);
            break;
        case "GB":
        case "G":
            $number = $number * pow(1024, 3);
            break;
    }
    return fix_integer_overflow($number);
}

/**
 * Fixes integer overflow
 * 
 * @param int $size
 * @return int
 */
function fix_integer_overflow($size) {
    if ($size < 0) {
        $size += 2.0 * (PHP_INT_MAX + 1);
    }
    return $size;
}

class Dropzone_controller extends CI_Controller {

    public function upload() {
        if (!$this->input->is_ajax_request()) {
            exit('No direct script access allowed');
        }
        $this->load->helper('byte');
        $config['upload_path'] = ''; // upload directory realpath
        $config['file_name'] = md5(time()); // I like to set my own filename
        $config['overwrite'] = true;
        $config['allowed_types'] = 'jpg|jpeg|png|gif';
        $config['max_size'] = file_upload_max_size();
        $config['file_ext_tolower'] = true;
        $this->load->library('upload', $config);
        if (!$this->upload->do_upload('file')) {
            $this->dz_error($this->upload->display_errors('', '<br>'));
        }
        $data = $this->upload->data();
        $full_path = realpath($data['full_path']); // CI uses weird slashes
        // here you can use imagelib to resize if you want, I personally
        // like to use verot's class upload for that
        $this->load->model('dropzone_model');
        if (!$this->dropzone_model->add_image($full_path)) {
            @unlink($full_path); // remove orphaned image
            $this->dz_error('Failed to add image to the database!');
        }
        $this->dz_success();
    }

    // https://stackoverflow.com/questions/27030652/how-to-display-error-message-of-jquery-dropzone
    private function dz_error($error) {
        $this->output
                ->set_header("HTTP/1.0 400 Bad Request")
                ->set_output($error)
                ->_display();
        exit;
    }

    private function dz_success() {
        // don't really need to do anything here?
    }

}

class Dropzone_model extends CI_Model {

    public function add_image($full_path) {
        return $this->db->insert('sometable', array('image' => $full_path));
    }

}
person Alex    schedule 11.12.2017
comment
Не могли бы вы показать базовый пример того, как будет выглядеть код (формат MVC CI) с использованием DropZone и загрузчика файлов CI? - person 12AX7; 12.12.2017
comment
Конечно, но это грубо - person Alex; 13.12.2017
comment
Обратите внимание, что все они должны быть отдельными файлами — помощник, модель и контроллер. - person Alex; 13.12.2017