1212 * that resembles PHP's `$_POST` and `$_FILES` superglobals.
1313 *
1414 * @internal
15+ * @link https://tools.ietf.org/html/rfc7578
16+ * @link https://tools.ietf.org/html/rfc2046#section-5.1.1
1517 */
1618final class MultipartParser
1719{
@@ -43,23 +45,34 @@ private function parse()
4345 return $ this ->request ;
4446 }
4547
46- $ this ->parseBuffer ( $ matches [1 ], (string )$ this ->request ->getBody ());
48+ $ this ->parseBody ( ' -- ' . $ matches [1 ], (string )$ this ->request ->getBody ());
4749
4850 return $ this ->request ;
4951 }
5052
51- private function parseBuffer ($ boundary , $ buffer )
53+ private function parseBody ($ boundary , $ buffer )
5254 {
53- $ chunks = explode ('-- ' . $ boundary , $ buffer );
54- array_pop ($ chunks );
55+ $ len = strlen ($ boundary );
56+
57+ // ignore everything before initial boundary (SHOULD be empty)
58+ $ start = strpos ($ buffer , $ boundary . "\r\n" );
59+
60+ while ($ start !== false ) {
61+ // search following boundary (preceded by newline)
62+ // ignore last if not followed by boundary (SHOULD end with "--")
63+ $ start += $ len + 2 ;
64+ $ end = strpos ($ buffer , "\r\n" . $ boundary , $ start );
65+ if ($ end === false ) {
66+ break ;
67+ }
5568
56- foreach ( $ chunks as $ chunk ) {
57- $ chunk = $ this ->stripTrailingEOL ( $ chunk );
58- $ this -> parseChunk ( $ chunk ) ;
69+ // parse one part and continue searching for next
70+ $ this ->parsePart ( substr ( $ buffer , $ start , $ end - $ start ) );
71+ $ start = $ end ;
5972 }
6073 }
6174
62- private function parseChunk ($ chunk )
75+ private function parsePart ($ chunk )
6376 {
6477 $ pos = strpos ($ chunk , "\r\n\r\n" );
6578 if ($ pos === false ) {
@@ -157,10 +170,13 @@ private function parseHeaders($header)
157170 $ headers = array ();
158171
159172 foreach (explode ("\r\n" , trim ($ header )) as $ line ) {
160- list ($ key , $ values ) = explode (': ' , $ line , 2 );
161- $ key = trim ($ key );
162- $ key = strtolower ($ key );
163- $ values = explode ('; ' , $ values );
173+ $ parts = explode (': ' , $ line , 2 );
174+ if (!isset ($ parts [1 ])) {
175+ continue ;
176+ }
177+
178+ $ key = strtolower (trim ($ parts [0 ]));
179+ $ values = explode ('; ' , $ parts [1 ]);
164180 $ values = array_map ('trim ' , $ values );
165181 $ headers [$ key ] = $ values ;
166182 }
@@ -179,15 +195,6 @@ private function getParameterFromHeader(array $header, $parameter)
179195 return null ;
180196 }
181197
182- private function stripTrailingEOL ($ chunk )
183- {
184- if (substr ($ chunk , -2 ) === "\r\n" ) {
185- return substr ($ chunk , 0 , -2 );
186- }
187-
188- return $ chunk ;
189- }
190-
191198 private function extractPost ($ postFields , $ key , $ value )
192199 {
193200 $ chunks = explode ('[ ' , $ key );
0 commit comments