пользовательский multipart / form-data обработчик - PullRequest
9 голосов
/ 06 апреля 2011

Я ищу включающий скрипт / класс, который разбирает multipart/form-data и заполняет $_POST (+ raw) и $_FILES из него.Обычно PHP делает это сам.Но поскольку автоматическая обработка для меня недостаточна и делает php://input недоступным [1] Я, вероятно, буду использовать что-то подобное, чтобы предотвратить это:

RewriteRule .* - [E=CONTENT_TYPE:noparsing/for-you-php]
Не работает.Фактическое решение требует mod_headers и RequestHeader set ...

Процедура извлечения может быть не такой сложной.Но я бы предпочел использовать хорошо проверенное решение.И в первую очередь я бы предпочел реализацию, которая использует fgets для разбиения и имитирует обработку $_FILES тесно и эффективно.Поиск конца двоичных полезных нагрузок показался бы мне довольно сложным, в частности, когда вам нужно удалить \r\n, но могут встретиться клиенты, которые отправляют только \n (не разрешено, но возможно).

I 'Я уверен, что нечто подобное существует.Но мне трудно гуглить.Кто-нибудь знает реализацию?(PEAR :: mimeDecode можно взломать, чтобы получить вид работы с данными формы, но это проблема с памятью.)

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


В декоративных целях так выглядит запрос POST:

POST / HTTP/1.1
Host: localhost:8000
Content-Length: 17717
Content-Type: multipart/form-data; boundary=----------3wCuBwquE9P7A4OEylndVx

И после последовательности \r\n\r\nсоставная часть / полезная нагрузка выглядит следующим образом:

------------3wCuBwquE9P7A4OEylndVx
Content-Disposition: form-data; name="_charset_"

windows-1252
------------3wCuBwquE9P7A4OEylndVx
Content-Disposition: form-data; name=" text field \\ 1 \";inject=1"

text1 te twj sakfkl
------------3wCuBwquE9P7A4OEylndVx
Content-Disposition: form-data; name="file"; filename="dial.png"
Content-Type: image/png

IPNG Z @@@MIHDR@@B`@@B;HF@@@-'.e@@@AsRGB@.N\i@@@FbKGD@?@?@? ='S@@@     
@@@GtIMEGYAAU,#}BRU@@@YtEXtComment@Created with GIMPWANW@@ @IDATxZl]w|

Ответы [ 3 ]

4 голосов
/ 09 апреля 2011

Уже поздно, и я не могу проверить это в данный момент, но следующее должно делать то, что вы хотите:

<code>//$boundary = null;

if (is_resource($input = fopen('php://input', 'rb')) === true)
{

    while ((feof($input) !== true) && (($line = fgets($input)) !== false))
    {
        if (isset($boundary) === true)
        {
            $content = null;

            while ((feof($input) !== true) && (($line = fgets($input)) !== false))
            {
                $line = trim($line);

                if (strlen($line) > 0)
                {
                    $content .= $line . ' ';
                }

                else if (empty($line) === true)
                {
                    if (stripos($content, 'name=') !== false)
                    {
                        $name = trim(stripcslashes(preg_replace('~.*name="?(.+)"?.*~i', '$1', $content)));

                        if (stripos($content, 'Content-Type:') !== false)
                        {
                            $tmpname = tempnam(sys_get_temp_dir(), '');

                            if (is_resource($temp = fopen($tmpname, 'wb')) === true)
                            {
                                while ((feof($input) !== true) && (($line = fgets($input)) !== false) && (strpos($line, $boundary) !== 0))
                                {
                                    fwrite($temp, preg_replace('~(?:\r\n|\n)$~', '', $line));
                                }

                                fclose($temp);
                            }

                            $FILES[$name] = array
                            (
                                'name' => trim(stripcslashes(preg_replace('~.*filename="?(.+)"?.*~i', '$1', $content))),
                                'type' => trim(preg_replace('~.*Content-Type: ([^\s]*).*~i', '$1', $content)),
                                'size' => sprintf('%u', filesize($tmpname)),
                                'tmp_name' => $tmpname,
                                'error' => UPLOAD_ERR_OK,
                            );
                        }

                        else
                        {
                            $result = null;

                            while ((feof($input) !== true) && (($line = fgets($input)) !== false) && (strpos($line, $boundary) !== 0))
                            {
                                $result .= preg_replace('~(?:\r\n|\n)$~', '', $line);
                            }

                            if (array_key_exists($name, $POST) === true)
                            {
                                if (is_array($POST[$name]) === true)
                                {
                                    $POST[$name][] = $result;
                                }

                                else
                                {
                                    $POST[$name] = array($POST[$name], $result);
                                }
                            }

                            else
                            {
                                $POST[$name] = $result;
                            }
                        }
                    }

                    if (strpos($line, $boundary) === 0)
                    {
                        //break;
                    }
                }
            }
        }

        else if ((is_null($boundary) === true) && (strpos($line, 'boundary=') !== false))
        {
            $boundary = "--" . trim(preg_replace('~.*boundary="?(.+)"?.*~i', '$1', $line));
        }
    }

    fclose($input);
}

echo '<pre>';
print_r($POST);
echo '
';эхо«;echo '
';
print_r($FILES);
echo '
';
3 голосов
/ 08 октября 2012

Может быть, новая директива php.ini enable_post_data_reading может помочь, но, похоже, она была добавлена ​​в PHP 5.4, у меня все еще есть более ранняя версия, поэтому я не смог ее протестировать :(

С Руководство по PHP :

enable_post_data_reading логический

Отключение эта опция вызывает $ _POST и $ _FILES не нужно заполнять. Единственный способ прочитать постданные затем перейдите через упаковщик потока ввода php: //. Это может быть полезно для запросы прокси или обрабатывать данные POST в памяти эффективно мода.

0 голосов
/ 13 апреля 2011

Чтение комментариев, а как насчет кодирования данных перед тем, как они отправляются вместо этого?Заставьте клиента отправлять данные POST в UTF8 или даже в URL-кодированном виде, тогда потерянные символы ASCII будут передаваться без написания вашего собственного обработчика POST, который вполне может содержать собственные ошибки ...

...