Проблемы с CodeIgniter (и allow_types)

Доброе утро, ребята.

Я пытаюсь использовать Plupload вместе с CodeIgniter. Я попробовал uploadify перед Plupload, и он работал потрясающе, основная проблема с uploadify заключается в том, что он никогда не отправлял CSRF-код, независимо от того, что я использовал, это было действительно странно, поэтому я проверил Plupload и заставил его работать, как и ожидалось, за считанные минуты. Однако он хорошо работает ТОЛЬКО с загрузчиком HTML5, а не с загрузчиком Flash.

Просмотрев журналы, я нашел причину, по которой он не работал: при использовании класса загрузки файлов CodeIgniter.

Поскольку я выполняю массовую загрузку изображений, я настроил его так, чтобы разрешить «jpg,gif,png,jpeg», но обнаружил, что загрузчик отклоняет петицию о загрузке, так как я загружаю неправильный файл type_file (который, как я обнаружил, является октетом/потоком - втф?).

После процесса загрузки я обрабатывал изображение (создавал миниатюры, водяные знаки, обрезал и т. д.), поэтому, если я разрешил все типы файлов, обработка изображения вообще не будет работать.

Я думал о том, чтобы сделать что-то вроде загрузки файла (с разрешением октета/потока MIME TYPE), затем преобразовать его в изображение (с функциями imagecreatefromstring и file_get_contents), а затем обработать его индивидуально.

Если у вас есть другая идея, дайте мне знать


person demogar    schedule 01.09.2011    source источник


Ответы (1)


Прежде чем продолжить, я предлагаю вам отказаться от любого флеш-загрузчика и выбрать https://github.com/blueimp/jQuery-File-Upload, который всегда остается HTML5 и обратно совместим. В лучшем случае вы не увидите полосы загрузки, но Flash отсутствует, и вам не нужно вносить какие-либо изменения в CodeIgniter.

Следующее не очень доработано. На самом деле, я отказываюсь от поддержки загрузки Flash в своем приложении со следующей версии.

Любая загрузка, сделанная через Flash, будет получена сервером как application/octet-stream. Это перестает быть проблемой, когда в файле /application/config/mime.php вы добавляете «application/octet-stream» к интересующим вас типам файлов. Вот пример, посмотрите внизу файла.

В настоящее время проблема не в CSRF, а в том, что Flash имеет свои собственные файлы cookie, что означает, что это совершенно отдельный браузер. Прежде чем даже пытаться отправить CSRF, мы должны поместить во Flash идентификатор сеанса, который CodeIgniter использует для вашей идентификации. Вам также придется изменить /application/config/config.php

$config['sess_match_useragent'] = FALSE;

Если вы хотите использовать Uploadify3 (это также должно работать для Uploadify 2 и Plupload), вам сначала нужно добавить /application/libraries/MY_Session.php, чтобы можно было отправлять данные сеанса также через POST.

Просто используйте этот файл: https://github.com/woxxy/FoOlSlide/blob/a7522d747fe406da18ce18ae9763f083b89eb91e/application/libraries/MY_Session.php

Затем в вашем контроллере вы должны сделать возможным получение идентификатора сеанса в любое время.

function get_sess_id()
{
    $this->output->set_output(json_encode(array('session' => $this->session->get_js_session(), 'csrf' => $this->security->get_csrf_hash())));
}

Ваш контроллер загрузки должен быть довольно стандартной функцией загрузки. Убедитесь, что вы используете правильное имя при загрузке ("userfile").

Теперь самое худшее: файл просмотра. Я мог бы удалить некоторые детали, но я думаю, что некоторые дополнительные данные помогут вам кодировать их без необходимости слишком много искать в Uploadify3.

<script type="text/javascript">
    function updateSession()
    {
        jQuery.post('<?php echo site_url('/admin/series/get_sess_id'); ?>', 
        function(result){

            jQuery('#file_upload_flash').uploadifySettings( 'postData', {
                'ci_sessionz' : result.session, 
                '<?php echo $this->security->get_csrf_token_name(); ?>' : result.csrf, 
                'chapter_id' : <?php echo $chapter->id; ?>
            }, false );
            setTimeout('updateSession()', 6000);
        }, 'json');
    }

    jQuery(document).ready(function() {
        jQuery('#file_upload_flash').uploadify({
            'swf'  : '<?php echo site_url(); ?>assets/uploadify/uploadify.swf',
            'uploader'    : '<?php echo site_url('/admin/series/upload/compressed_chapter'); ?>',
            'cancelImage' : '<?php echo site_url(); ?>assets/uploadify/uploadify-cancel.png',
            'checkExisting' : false,
            'preventCaching' : false,
            'multi' : true,
            'buttonText' : '<?php echo _('Use flash upload'); ?>',
            'width': 200,
            'auto'      : true,
            'requeueErrors' : true,
            'uploaderType'    : 'flash',
            'postData' : {},
            'onSWFReady'  : function() {
                updateSession();
            },
            'onUploadSuccess' : function(file, data, response) {
                var files = jQuery.parseJSON(data);
                var fu = jQuery('#fileupload').data('fileupload');
                fu._adjustMaxNumberOfFiles(-files.length);
                fu._renderDownload(files)
                .appendTo(jQuery('#fileupload .files'))
                .fadeIn(function () {
                    jQuery(this).show();
                });
            }   
        });
    });

</script>
<div id="file_upload_flash"></div>

Теперь, если работы уже недостаточно... в Uploadify3 есть ошибка, из-за которой он не запускает один или два обратных вызова.

Вот исправленная версия кода: https://github.com/woxxy/FoOlSlide/blob/a7522d747fe406da18ce18ae9763f083b89eb91e/assets/uploadify/jquery.uploadify.js

Возможно, вы захотите минимизировать его.

Но что, если вы хотите использовать jQuery-File-Upload?

Тогда все, что вам нужно сделать, это немного адаптировать ваш контроллер. Вот пример (я также не буду чистить этот код, так как это, вероятно, все равно приведет к поломке контроллера загрузки)

function upload()
{
    $info = array();

    // compatibility for flash uploader and browser not supporting multiple upload
    if (is_array($_FILES['Filedata']) && !is_array($_FILES['Filedata']['tmp_name']))
    {
        $_FILES['Filedata']['tmp_name'] = array($_FILES['Filedata']['tmp_name']);
        $_FILES['Filedata']['name'] = array($_FILES['Filedata']['name']);
    }

    for ($file = 0; $file < count($_FILES['Filedata']['tmp_name']); $file++)
    {
        $valid = explode('|', 'png|zip|rar|gif|jpg|jpeg');
        if (!in_array(strtolower(substr($_FILES['Filedata']['name'][$file], -3)), $valid))
            continue;

        if (!in_array(strtolower(substr($_FILES['Filedata']['name'][$file], -3)), array('zip', 'rar')))
            $pages = $this->files_model->page($_FILES['Filedata']['tmp_name'][$file], $_FILES['Filedata']['name'][$file], $this->input->post('chapter_id'));
        else
            $pages = $this->files_model->compressed_chapter($_FILES['Filedata']['tmp_name'][$file], $_FILES['Filedata']['name'][$file], $this->input->post('chapter_id'));

        foreach ($pages as $page)
        {
            $info[] = array(
                'name' => $page->filename,
                'size' => $page->size,
                'url' => $page->page_url(),
                'thumbnail_url' => $page->page_url(TRUE),
                'delete_url' => site_url("admin/series/delete/page"),
                'delete_data' => $page->id,
                'delete_type' => 'POST'
            );
        }
    }

    // return a json array
    echo json_encode($info);
    return true;
}


function get_file_objects()
{
    // Generate JSON File Output (Required by jQuery File Upload)
    header('Content-type: application/json');
    header('Pragma: no-cache');
    header('Cache-Control: private, no-cache');
    header('Content-Disposition: inline; filename="files.json"');

    $id = $this->input->post('id');
    $chapter = new Chapter($id);
    $pages = $chapter->get_pages();
    $info = array();
    foreach ($pages as $page)
    {
        $info[] = array(
            'name' => $page['filename'],
            'size' => intval($page['size']),
            'url' => $page['url'],
            'thumbnail_url' => $page['thumb_url'],
            'delete_url' => site_url("admin/series/delete/page"),
            'delete_data' => $page['id'],
            'delete_type' => 'POST'
        );
    }

    echo json_encode($info);
    return true;
}

И добавьте больше потрясающего кода представления (на этот раз это почти стандартный код из загрузки jQuery)

<div id="fileupload">
    <link href="<?php echo site_url(); ?>assets/jquery-file-upload/jquery-ui.css" rel="stylesheet" id="theme" />
    <link href="<?php echo site_url(); ?>assets/jquery-file-upload/jquery.fileupload-ui.css" rel="stylesheet" />
    <?php echo form_open_multipart(""); ?>
    <div class="fileupload-buttonbar">
        <label class="fileinput-button">
            <span>Add files...</span>
            <input type="file" name="Filedata[]" multiple>
        </label>
        <button type="submit" class="start">Start upload</button>
        <button type="reset" class="cancel">Cancel upload</button>
        <button type="button" class="delete">Delete files</button>
    </div>
    <?php echo form_close(); ?>
    <div class="fileupload-content">
        <table class="files"></table>
        <div class="fileupload-progressbar"></div>
    </div>
</div>
<script id="template-upload" type="text/x-jquery-tmpl">
    <tr class="template-upload{{if error}} ui-state-error{{/if}}">
        <td class="preview"></td>
        <td class="name">${name}</td>
        <td class="size">${sizef}</td>
        {{if error}}
        <td class="error" colspan="2">Error:
            {{if error === 'maxFileSize'}}File is too big
            {{else error === 'minFileSize'}}File is too small
            {{else error === 'acceptFileTypes'}}Filetype not allowed
            {{else error === 'maxNumberOfFiles'}}Max number of files exceeded
            {{else}}${error}
            {{/if}}
        </td>
        {{else}}
        <td class="progress"><div></div></td>
        <td class="start"><button>Start</button></td>
        {{/if}}
        <td class="cancel"><button>Cancel</button></td>
    </tr>
</script>
<script id="template-download" type="text/x-jquery-tmpl">
    <tr class="template-download{{if error}} ui-state-error{{/if}}">
        {{if error}}
        <td></td>
        <td class="name">${name}</td>
        <td class="size">${sizef}</td>
        <td class="error" colspan="2">Error:
            {{if error === 1}}File exceeds upload_max_filesize (php.ini directive)
            {{else error === 2}}File exceeds MAX_FILE_SIZE (HTML form directive)
            {{else error === 3}}File was only partially uploaded
            {{else error === 4}}No File was uploaded
            {{else error === 5}}Missing a temporary folder
            {{else error === 6}}Failed to write file to disk
            {{else error === 7}}File upload stopped by extension
            {{else error === 'maxFileSize'}}File is too big
            {{else error === 'minFileSize'}}File is too small
            {{else error === 'acceptFileTypes'}}Filetype not allowed
            {{else error === 'maxNumberOfFiles'}}Max number of files exceeded
            {{else error === 'uploadedBytes'}}Uploaded bytes exceed file size
            {{else error === 'emptyResult'}}Empty file upload result
            {{else}}${error}
            {{/if}}
        </td>
        {{else}}
        <td class="preview">
            {{if thumbnail_url}}
            <a href="${url}" target="_blank"><img src="${thumbnail_url}"></a>
            {{/if}}
        </td>
        <td class="name">
            <a href="${url}"{{if thumbnail_url}} target="_blank"{{/if}}>${name}</a>
        </td>
        <td class="size">${sizef}</td>
        <td colspan="2"></td>
        {{/if}}
        <td class="delete">
            <button data-type="${delete_type}" data-url="${delete_url}" data-id="${delete_data}">Delete</button>
        </td>
    </tr>
</script>
<script src="<?php echo site_url(); ?>assets/js/jquery-ui.js"></script>
<script src="<?php echo site_url(); ?>assets/js/jquery.tmpl.js"></script>
<script src="<?php echo site_url(); ?>assets/jquery-file-upload/jquery.fileupload.js"></script>
<script src="<?php echo site_url(); ?>assets/jquery-file-upload/jquery.fileupload-ui.js"></script>
<script src="<?php echo site_url(); ?>assets/jquery-file-upload/jquery.iframe-transport.js"></script>

<script type="text/javascript">

    jQuery(function () {
        jQuery('#fileupload').fileupload({
            url: '<?php echo site_url('/admin/series/upload/compressed_chapter'); ?>',
            sequentialUploads: true,
            formData: [
                {
                    name: 'chapter_id',
                    value: <?php echo $chapter->id; ?>
                }
            ]
        });

        jQuery.post('<?php echo site_url('/admin/series/get_file_objects'); ?>', { id : <?php echo $chapter->id; ?> }, function (files) {
            var fu = jQuery('#fileupload').data('fileupload');
            fu._adjustMaxNumberOfFiles(-files.length);
            fu._renderDownload(files)
            .appendTo(jQuery('#fileupload .files'))
            .fadeIn(function () {
                jQuery(this).show();
            });

        });

        jQuery('#fileupload .files a:not([target^=_blank])').live('click', function (e) {
            e.preventDefault();
            jQuery('<iframe style="display:none;"></iframe>')
            .prop('src', this.href)
            .appendTo('body');
        });

    });

</script>
person Woxxy    schedule 01.09.2011
comment
Отличный ответ, очень подробный, и теперь я яснее понимаю всю проблему, стоящую за всем этим. Я, очевидно, предпочитаю загрузчик HTML5, но в некоторых случаях (старые браузеры) мне нужна поддержка Flash. Пытался использовать Uploadify 3, но он даже не запускает загрузчик. Я попробую все еще раз и дам вам знать. - person demogar; 03.09.2011