userland multipart / form-data handler

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

RewriteRule .* - [E=CONTENT_TYPE:noparsing/for-you-php]
Не работает. Для реального решения требуются mod_headers и RequestHeader set

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

Я уверен, что такое существует. Но мне сложно с этим бороться. Кто-нибудь знает реализацию? (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| 

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

 //$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 '</pre>'; echo '<hr />'; echo '<pre>'; print_r($FILES); echo '</pre>'; 

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

Из руководства PHP :

enable_post_data_reading boolean

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

Чтение комментариев, как насчет кодирования данных, прежде чем он будет POSTED вместо этого? Попросите клиента отправить данные POST в UTF8 или даже URLencoded, тогда символы ASCII, которые были потеряны, будут переданы без написания собственного обработчика POST, который вполне мог бы представить свои собственные ошибки …