Completed
Push — feature/EVO-8294-fileUpload ( 397bbc...335fda )
by
unknown
07:53
created

RequestManager::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
/**
3
 * Handles REQUEST file specific actions
4
 */
5
6
namespace Graviton\FileBundle\Manager;
7
8
use Symfony\Component\HttpFoundation\File\UploadedFile;
9
use Symfony\Component\HttpFoundation\Request;
10
use Symfony\Component\HttpFoundation\File\File;
11
use Symfony\Component\Filesystem\Filesystem;
12
use Symfony\Component\HttpFoundation\RequestStack;
13
14
/**
15
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
16
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
17
 * @link     http://swisscom.ch
18
 */
19
class RequestManager
20
{
21
    /**
22
     * @var RequestStack
23
     */
24
    private $requestStack;
25
26
    /**
27
     * RequestManager constructor.
28
     *
29
     * @param RequestStack $requestStack To get the original request
30
     */
31
    public function __construct(RequestStack $requestStack)
32
    {
33
        $this->requestStack = $requestStack;
34
    }
35
36
37
    /**
38
     * Simple RAW http request parser.
39
     * Ideal for PUT requests where PUT is streamed but you still need the data.
40
     *
41
     * @param Request $request Sf data request
42
     * @return Request
43
     */
44
    public function updateFileRequest(Request $request)
45
    {
46
        $original = $this->requestStack->getMasterRequest();
47
        $input = $original ? $original->getContent() : false;
48
49
        if (!$input) {
50
            return $request;
51
        }
52
53
        $input = urldecode($input);
54
        $server = $request->server;
55
        $contentType = $server->get('CONTENT_TYPE', $server->get('HTTP_CONTENT_TYPE'));
56
        $data = [];
57
58
        // grab multipart boundary from content type header
59
        preg_match('/boundary=(.*)$/', $contentType, $matches);
60
61
        // content type is probably regular form-encoded
62
        if (!count($matches)) {
63
            $json = json_decode($input, true);
64
            // Check if content is binary, convert to file upload
65
            if (!$json && $request->files->count() == 0) {
66
                $file = $this->extractFileFromString($input, $contentType);
67
                if ($file) {
68
                    $request->files->add([$file]);
69
                }
70
            } elseif ($json) {
71
                $request->request->set('metadata', json_encode($json));
72
            }
73
            return $request;
74
        }
75
76
        $contentBlocks = preg_split("/-+$matches[1]/", $input);
77
78
        // determine content blocks usage
79
        foreach ($contentBlocks as $contentBlock) {
80
            if (empty($contentBlock)) {
81
                continue;
82
            }
83
            preg_match('/name=\"(.*?)\"[^"]/i', $contentBlock, $matches);
84
            $name = isset($matches[1]) ? $matches[1] : '';
85
            if ('upload' !== $name) {
86
                preg_match('/name=\"([^\"]*)\"[\n|\r]+([^\n\r].*)?\r$/s', $contentBlock, $matches);
87
                $contentBlock = array_key_exists(2, $matches) ? $matches[2]: $contentBlock;
88
            }
89
            $data[$name] = $contentBlock;
90
        }
91
92
        if (array_key_exists('metadata', $data)) {
93
            $request->request->set('metadata', $data['metadata']);
94
        }
95
        if (array_key_exists('upload', $data)) {
96
            $file = $this->extractFileFromString($data['upload']);
97
            $request->files->add([$file]);
98
        }
99
100
        return $request;
101
    }
102
103
104
    /**
105
     * Extracts file data from request content
106
     *
107
     * @param string $fileInfoString Information about uploaded files.
108
     * @param string $contentType    Optional type of string
109
     *
110
     * @return false|UploadedFile
111
     */
112
    private function extractFileFromString($fileInfoString, $contentType = '')
113
    {
114
        $str = (string) $fileInfoString;
115
        $tmpName = $fileName = microtime() . '_' . md5($str);
116
117
        if ((preg_match('~[^\x20-\x7E\t\r\n]~', $str) > 0) || $contentType) {
118
            $fileContent = $str;
119
        } else {
120
            // Original Name
121
            preg_match('/filename=\"(.*?)\"/i', $str, $matches);
122
            if (array_key_exists(1, $matches)) {
123
                $fileName = preg_replace('/\s+/', '-', $matches[1]);
124
            }
125
            $fileInfo = explode("\r\n\r\n", ltrim($str), 2);
126
            if (!array_key_exists(1, $fileInfo)) {
127
                return false;
128
            }
129
            $fileContent = substr($fileInfo[1], 0, -2);
130
        }
131
132
        $dir = ini_get('upload_tmp_dir');
133
        $dir = (empty($dir)) ? sys_get_temp_dir() : $dir;
134
        $tmpFile = $dir . DIRECTORY_SEPARATOR . $tmpName;
135
136
        // create temporary file;
137
        $filesystem = new Filesystem();
138
        $filesystem->dumpFile($tmpFile, $fileContent);
139
        $file = new File($tmpFile);
140
141
        return new UploadedFile(
142
            $file->getRealPath(),
143
            $fileName,
144
            $file->getMimeType(),
145
            $file->getSize()
146
        );
147
    }
148
}
149