Forráskód Böngészése

Update Request.php

walkor 3 éve
szülő
commit
a779166998
1 módosított fájl, 118 hozzáadás és 129 törlés
  1. 118 129
      src/Protocols/Http/Request.php

+ 118 - 129
src/Protocols/Http/Request.php

@@ -47,6 +47,11 @@ class Request
     public $properties = [];
 
     /**
+     * @var int
+     */
+    public static $maxFileUploads = 1024;
+
+    /**
      * Http buffer.
      *
      * @var string
@@ -61,27 +66,6 @@ class Request
     protected $_data = null;
 
     /**
-     * Header cache.
-     *
-     * @var array
-     */
-    protected static $_headerCache = [];
-
-    /**
-     * Get cache.
-     *
-     * @var array
-     */
-    protected static $_getCache = [];
-
-    /**
-     * Post cache.
-     *
-     * @var array
-     */
-    protected static $_postCache = [];
-
-    /**
      * Enable cache.
      *
      * @var bool
@@ -410,6 +394,7 @@ class Request
      */
     protected function parseHeaders()
     {
+        static $cache = [];
         $this->_data['headers'] = [];
         $raw_head = $this->rawHead();
         $end_line_position = \strpos($raw_head, "\r\n");
@@ -418,8 +403,8 @@ class Request
         }
         $head_buffer = \substr($raw_head, $end_line_position + 2);
         $cacheable = static::$_enableCache && !isset($head_buffer[2048]);
-        if ($cacheable && isset(static::$_headerCache[$head_buffer])) {
-            $this->_data['headers'] = static::$_headerCache[$head_buffer];
+        if ($cacheable && isset($cache[$head_buffer])) {
+            $this->_data['headers'] = $cache[$head_buffer];
             return;
         }
         $head_data = \explode("\r\n", $head_buffer);
@@ -439,9 +424,9 @@ class Request
             }
         }
         if ($cacheable) {
-            static::$_headerCache[$head_buffer] = $this->_data['headers'];
-            if (\count(static::$_headerCache) > 128) {
-                unset(static::$_headerCache[key(static::$_headerCache)]);
+            $cache[$head_buffer] = $this->_data['headers'];
+            if (\count($cache) > 128) {
+                unset($cache[key($cache)]);
             }
         }
     }
@@ -453,21 +438,22 @@ class Request
      */
     protected function parseGet()
     {
+        static $cache = [];
         $query_string = $this->queryString();
         $this->_data['get'] = [];
         if ($query_string === '') {
             return;
         }
         $cacheable = static::$_enableCache && !isset($query_string[1024]);
-        if ($cacheable && isset(static::$_getCache[$query_string])) {
-            $this->_data['get'] = static::$_getCache[$query_string];
+        if ($cacheable && isset($cache[$query_string])) {
+            $this->_data['get'] = $cache[$query_string];
             return;
         }
         \parse_str($query_string, $this->_data['get']);
         if ($cacheable) {
-            static::$_getCache[$query_string] = $this->_data['get'];
-            if (\count(static::$_getCache) > 256) {
-                unset(static::$_getCache[key(static::$_getCache)]);
+            $cache[$query_string] = $this->_data['get'];
+            if (\count($cache) > 256) {
+                unset($cache[key($cache)]);
             }
         }
     }
@@ -479,31 +465,32 @@ class Request
      */
     protected function parsePost()
     {
-        $body_buffer = $this->rawBody();
+        static $cache = [];
         $this->_data['post'] = $this->_data['files'] = [];
-        if ($body_buffer === '') {
-            return;
-        }
-        $cacheable = static::$_enableCache && !isset($body_buffer[1024]);
-        if ($cacheable && isset(static::$_postCache[$body_buffer])) {
-            $this->_data['post'] = static::$_postCache[$body_buffer];
-            return;
-        }
         $content_type = $this->header('content-type', '');
         if (\preg_match('/boundary="?(\S+)"?/', $content_type, $match)) {
             $http_post_boundary = '--' . $match[1];
             $this->parseUploadFiles($http_post_boundary);
             return;
         }
+        $body_buffer = $this->rawBody();
+        if ($body_buffer === '') {
+            return;
+        }
+        $cacheable = static::$_enableCache && !isset($body_buffer[1024]);
+        if ($cacheable && isset($cache[$body_buffer])) {
+            $this->_data['post'] = $cache[$body_buffer];
+            return;
+        }
         if (\preg_match('/\bjson\b/i', $content_type)) {
             $this->_data['post'] = (array)\json_decode($body_buffer, true);
         } else {
             \parse_str($body_buffer, $this->_data['post']);
         }
         if ($cacheable) {
-            static::$_postCache[$body_buffer] = $this->_data['post'];
-            if (\count(static::$_postCache) > 256) {
-                unset(static::$_postCache[key(static::$_postCache)]);
+            $cache[$body_buffer] = $this->_data['post'];
+            if (\count($cache) > 256) {
+                unset($cache[key($cache)]);
             }
         }
     }
@@ -517,99 +504,101 @@ class Request
     protected function parseUploadFiles($http_post_boundary)
     {
         $http_post_boundary = \trim($http_post_boundary, '"');
-        $http_body = $this->rawBody();
-        $http_body = \substr($http_body, 0, \strlen($http_body) - (\strlen($http_post_boundary) + 4));
-        $boundary_data_array = \explode($http_post_boundary . "\r\n", $http_body);
-        if ($boundary_data_array[0] === '' || $boundary_data_array[0] === "\r\n") {
-            unset($boundary_data_array[0]);
-        }
-        $index = -1;
-        $files = [];
-        $post_str = '';
-        foreach ($boundary_data_array as $boundary_data_buffer) {
-            list($boundary_header_buffer, $boundary_value) = \explode("\r\n\r\n", $boundary_data_buffer, 2);
-            // Remove \r\n from the end of buffer.
-            $boundary_value = \substr($boundary_value, 0, -2);
-            $index++;
-            foreach (\explode("\r\n", $boundary_header_buffer) as $item) {
-                list($header_key, $header_value) = \explode(": ", $item);
-                $header_key = \strtolower($header_key);
-                switch ($header_key) {
-                    case "content-disposition":
-                        // Is file data.
-                        if (\preg_match('/name="(.*?)"; filename="(.*?)"/i', $header_value, $match)) {
-                            $error = 0;
-                            $tmp_file = '';
-                            $size = \strlen($boundary_value);
-                            $tmp_upload_dir = HTTP::uploadTmpDir();
-                            if (!$tmp_upload_dir) {
-                                $error = UPLOAD_ERR_NO_TMP_DIR;
-                            } else if ($boundary_value === '') {
-                                $error = UPLOAD_ERR_NO_FILE;
-                            } else {
-                                $tmp_file = \tempnam($tmp_upload_dir, 'workerman.upload.');
-                                if ($tmp_file === false || false == \file_put_contents($tmp_file, $boundary_value)) {
-                                    $error = UPLOAD_ERR_CANT_WRITE;
-                                }
-                            }
-                            if (!isset($files[$index])) {
-                                $files[$index] = [];
-                            }
-                            // Parse upload files.
-                            $files[$index] += [
-                                'key' => $match[1],
-                                'name' => $match[2],
-                                'tmp_name' => $tmp_file,
-                                'size' => $size,
-                                'error' => $error,
-                                'type' => null,
-                            ];
-                            break;
-                        } // Is post field.
-                        else {
-                            // Parse $_POST.
-                            if (\preg_match('/name="(.*?)"$/', $header_value, $match)) {
-                                $k = $match[1];
-                                $post_str .= \urlencode($k) . "=" . \urlencode($boundary_value) . '&';
+        $buffer = $this->_buffer;
+        $boday_position = strpos($buffer, "\r\n\r\n") + 4;
+        $offset = $boday_position + strlen($http_post_boundary) + 2;
+        $max_count = static::$maxFileUploads;
+        while ($max_count-- > 0 && $offset) {
+            $offset = $this->parseUploadFile($http_post_boundary, $offset);
+        }
+    }
+
+    /**
+     * @param $boundary
+     * @param $section_start_offset
+     * @return int
+     */
+    protected function parseUploadFile($boundary, $section_start_offset)
+    {
+        $file = [];
+        $boundary = "\r\n$boundary";
+        $section_end_offset = \strpos($this->_buffer, $boundary, $section_start_offset);
+        if (!$section_end_offset) {
+            return 0;
+        }
+        $content_lines_end_offset = \strpos($this->_buffer, "\r\n\r\n", $section_start_offset);
+        if (!$content_lines_end_offset || $content_lines_end_offset + 4 > $section_end_offset) {
+            return 0;
+        }
+        $content_lines_str = \substr($this->_buffer, $section_start_offset, $content_lines_end_offset - $section_start_offset);
+        $content_lines = \explode("\r\n", trim($content_lines_str . "\r\n"));
+        $boundary_value = \substr($this->_buffer, $content_lines_end_offset + 4, $section_end_offset - $content_lines_end_offset - 4);
+        $upload_key = false;
+        foreach ($content_lines as $content_line) {
+            if (!\strpos($content_line, ': ')) {
+                return 0;
+            }
+            [$key, $value] = \explode(': ', $content_line);
+            switch (strtolower($key)) {
+                case "content-disposition":
+                    // Is file data.
+                    if (\preg_match('/name="(.*?)"; filename="(.*?)"/i', $value, $match)) {
+                        $error = 0;
+                        $tmp_file = '';
+                        $size = \strlen($boundary_value);
+                        $tmp_upload_dir = HTTP::uploadTmpDir();
+                        if (!$tmp_upload_dir) {
+                            $error = UPLOAD_ERR_NO_TMP_DIR;
+                        } else if ($boundary_value === '') {
+                            $error = UPLOAD_ERR_NO_FILE;
+                        } else {
+                            $tmp_file = \tempnam($tmp_upload_dir, 'workerman.upload.');
+                            if ($tmp_file === false || false == \file_put_contents($tmp_file, $boundary_value)) {
+                                $error = UPLOAD_ERR_CANT_WRITE;
                             }
                         }
+                        $upload_key = $match[1];
+                        // Parse upload files.
+                        $file = [
+                            'name' => $match[2],
+                            'tmp_name' => $tmp_file,
+                            'size' => $size,
+                            'error' => $error,
+                            'type' => null,
+                        ];
                         break;
-                    case "content-type":
-                        // add file_type
-                        if (!isset($files[$index])) {
-                            $files[$index] = [];
+                    } // Is post field.
+                    else {
+                        // Parse $_POST.
+                        if (\preg_match('/name="(.*?)"$/', $value, $match)) {
+                            $k = $match[1];
+                            $post_str = \urlencode($k) . "=" . \urlencode($boundary_value);
+                            $post = [];
+                            parse_str($post_str, $post);
+                            if ($post) {
+                                $this->_data['post'] = \array_merge_recursive($this->_data['post'], $post);
+                            }
                         }
-                        $files[$index]['type'] = \trim($header_value);
-                        break;
-                }
-            }
-        }
-        $files_unique = [];
-        foreach ($files as $index => $file) {
-            if (!isset($file['key'])) {
-                unset($files[$index]);
-                continue;
-            }
-            $key = $file['key'];
-            if (\substr($key, -2) === '[]') {
-                $key = $index;
+                        return $section_end_offset + \strlen($boundary) + 2;
+                    }
+                    break;
+                case "content-type":
+                    $file['type'] = \trim($value);
+                    break;
             }
-            $files_unique[$key] = $file;
-        }
-        foreach ($files_unique as $file) {
-            $key = $file['key'];
-            unset($file['key']);
-            $str = \urlencode($key) . "=1";
-            $result = [];
-            \parse_str($str, $result);
-            \array_walk_recursive($result, function (&$value) use ($file) {
-                $value = $file;
-            });
-            $this->_data['files'] = \array_merge_recursive($this->_data['files'], $result);
         }
-        if ($post_str) {
-            parse_str($post_str, $this->_data['post']);
+        if ($upload_key === false) {
+            return 0;
         }
+        $str = \urlencode($upload_key) . "=1";
+        $result = [];
+        \parse_str($str, $result);
+        \array_walk_recursive($result, function (&$value) use ($file) {
+            $value = $file;
+        });
+        $this->_data['files'] = \array_merge_recursive($this->_data['files'], $result);
+
+        return $section_end_offset + \strlen($boundary) + 2;
     }
 
     /**