Это сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Input multiple-2

По мотивам предыдущего поста. Чтобы Opera 9+ (а так же 3.5—6.05), Firefox 3.6+, Chrome 3.0.191.0+ и Safari 4.0.1+ позволили выбрать несколько файлов в диалоге загрузки файлов, нужно написать вот такой код:

<form enctype="multipart/form-data" method="post">
   <input type="file" min="1" max="9999" name="file[]" multiple="true" />
   <input type="submit" name="submit" />
</form>

Я указал «file[]» для того, чтобы PHP сразу разложил полученные файлы по массиву $_FILES. К сожалению, запрос от «Оперы» PHP понимает неверно, так как «Опера» шлёт такой запрос в формате multipart/mixed. К счастью, PHP в этом случае положит содержимое файлов одним MIME-куском прямо в $_POST[’file’][0], а там его уже можно разобрать (надеюсь, директива magic_quotes_gpc у вас отключена).

Я попробовал, это несложно. Для того, чтобы разобрать MIME-секцию, я использовал PECL-модуль mailparse (есть версия для Windows):

if (isset($_POST['file'], $_POST['file'][0])) {

    if ($idx = strpos($_POST['file'][0], "\n")) {
        $bound = substr($_POST['file'][0], 2, $idx-2);

        $body  = "MIME-Version: 1.0\nContent-type: multipart/form-data; boundary={$bound}\n\n".
                 $_POST['file'][0];

        unset($_POST['file'][0]);
        $f = &$_FILES['file'];

        $f['name'] = $f['type'] = $f['tmp_name'] = $f['error'] = $f['size'];

        $msg = mailparse_msg_create();

        if (mailparse_msg_parse($msg, $body)) {
            $i = 0;

            foreach(mailparse_msg_get_structure($msg) as $st) {

                $section = mailparse_msg_get_part($msg, $st);

                $data = mailparse_msg_get_part_data($section);

                if ($data['content-type'] == 'multipart/form-data') {
                    continue; 
                }
            
                ob_start();
                if (mailparse_msg_extract_part($section, $body)) {
                    $tmp = tempnam(sys_get_temp_dir(), 'php');
                    file_put_contents($tmp, ob_get_clean());

                    $f['name'][$i] = $data['disposition-filename'];
                    $f['type'][$i] = $data['content-type'];
                    $f['tmp_name'][$i] = $tmp;
                    $f['error'][$i] = 0;
                    $f['size'][$i] = filesize($tmp);

                    $i++;
                } else {
                    ob_end_clean();
                }
            }
        }
        unset($f);

        mailparse_msg_free($msg);
    }
}

var_dump($_FILES); // результат помещатся в $_FILES, не забудьте удалить временные файлы после обработки!

У меня ожидается, что содержимое файлов будет передано как параметр «file[]» (в $_POST это будет $_POST[’file’][0]), но пример несложно переделать на любое другое имя или сделать это имя параметром.

Ctrl →Presto 2.4
5 комментариев
masterspammer.livejournal.com 2009

Сайт лежал и комментарии пропали :-(

Про разбор формы — я вот так делал: http://masterspammer.livejournal.com/30260.html

den-rad.livejournal.com 2009

Хорошее решение. В случае с админ интерфейсом и интранетом можно наплевать на Оперу

Евгений Степанищев (bolknote.ru) 2009

Восстановили сайт из бакапа что ли? Чёрт.

sontar.livejournal.com 2009

Как быть, если поле input-поле файла уже часть массива?
<input type=«file» name=«myform[myfile]» ...

Евгений Степанищев (bolknote.ru) 2009

Комментарий для sontar.livejournal.com:

<input type=«file» name=«myform[myfile][]» />