Completed
Push — master ( d50b1e...b151aa )
by recca
01:53
created

Base::receiveChunkedFile()   B

Complexity

Conditions 4
Paths 2

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 18
cts 18
cp 1
rs 8.9197
c 0
b 0
f 0
cc 4
eloc 15
nc 2
nop 5
crap 4
1
<?php
2
3
namespace Recca0120\Upload\Apis;
4
5
use Illuminate\Http\Request;
6
use Recca0120\Upload\Filesystem;
7
use Illuminate\Http\JsonResponse;
8
use Recca0120\Upload\Contracts\Api;
9
use Symfony\Component\HttpFoundation\File\UploadedFile;
10
use Recca0120\Upload\Exceptions\ChunkedResponseException;
11
12
abstract class Base implements Api
13
{
14
    /**
15
     * TMPFILE_EXTENSION.
16
     *
17
     * @var string
18
     */
19
    const TMPFILE_EXTENSION = '.part';
20
21
    /**
22
     * $request.
23
     *
24
     * @var \Illuminate\Http\Request
25
     */
26
    protected $request;
27
28
    /**
29
     * $filesystem.
30
     *
31
     * @var \Recca0120\Upload\Filesystem
32
     */
33
    protected $filesystem;
34
35
    /**
36
     * $config.
37
     *
38
     * @var array
39
     */
40
    protected $config;
41
42
    /**
43
     * __construct.
44
     *
45
     * @param array $config
46
     * @param \Illuminate\Http\Request $request
47
     * @param \Recca0120\Upload\Filesystem $filesystem
48
     */
49 18
    public function __construct($config = [], Request $request = null, Filesystem $filesystem = null)
50
    {
51 18
        $this->request = $request ?: Request::capture();
52 18
        $this->filesystem = $filesystem ?: new Filesystem();
53
54 18
        $config['chunks'] = empty($config['chunks']) === false ? $config['chunks'] : sys_get_temp_dir().'/chunks';
55 18
        $config['storage'] = empty($config['storage']) === false ? $config['storage'] : 'storage/temp';
56 18
        $config['domain'] = empty($config['domain']) === false ? $config['domain'] : $this->request->root();
57 18
        $config['path'] = empty($config['path']) === false ? $config['path'] : 'storage/temp';
58
59 18
        foreach (['chunks', 'storage', 'domain', 'path'] as $key) {
60 18
            $config[$key] = rtrim($config[$key], '/').'/';
61 18
        }
62 18
        $this->config = $config;
63 18
    }
64
65
    /**
66
     * chunksPath.
67
     *
68
     * @return string
69
     */
70 7
    public function chunksPath()
71
    {
72 7
        return $this->config['chunks'];
73
    }
74
75
    /**
76
     * storagePath.
77
     *
78
     * @return string
79
     */
80 7
    public function storagePath()
81
    {
82 7
        return $this->config['storage'];
83
    }
84
85
    /**
86
     * domain.
87
     *
88
     * @return string
89
     */
90 1
    public function domain()
91
    {
92 1
        return $this->config['domain'];
93
    }
94
95
    /**
96
     * path.
97
     *
98
     * @return string
99
     */
100 1
    public function path()
101
    {
102 1
        return $this->config['path'];
103
    }
104
105
    /**
106
     * makeDirectory.
107
     *
108
     * @return $this
109
     */
110 7
    public function makeDirectory($path)
111
    {
112 7
        if ($this->filesystem->isDirectory($path) === false) {
113 1
            $this->filesystem->makeDirectory($path, 0777, true, true);
114 1
        }
115
116 7
        return $this;
117
    }
118
119
    /**
120
     * cleanDirectory.
121
     */
122 5
    public function cleanDirectory($path)
123
    {
124 5
        $time = time();
125 5
        $maxFileAge = 3600;
126 5
        $files = (array) $this->filesystem->files($path);
127 5
        foreach ($files as $file) {
128 1
            if ($this->filesystem->isFile($file) === true &&
129 1
                $this->filesystem->lastModified($file) < ($time - $maxFileAge)
130 1
            ) {
131 1
                $this->filesystem->delete($file);
132 1
            }
133 5
        }
134 5
    }
135
136
    /**
137
     * receiveChunkedFile.
138
     *
139
     * @param string $originalName
140
     * @param string|resource $input
141
     * @param int $start
142
     * @param bool $completed
143
     * @param array $options
144
     * @return \Symfony\Component\HttpFoundation\File\UploadedFile
145
     *
146
     * @throws \Recca0120\Upload\Exceptions\ChunkedResponseException
147
     */
148 4
    protected function receiveChunkedFile($originalName, $input, $start, $completed = false, $options = [])
149
    {
150 4
        $tmpfilename = $this->filesystem->tmpfilename(
151 4
            $originalName, $this->request->get('token')
152 4
        );
153 4
        $chunkFile = $this->chunksPath().$tmpfilename.static::TMPFILE_EXTENSION;
154 4
        $storageFile = $this->storagePath().$tmpfilename;
155 4
        $this->filesystem->appendStream($chunkFile, $input, $start);
156 4
        if ($completed === false) {
157 2
            throw new ChunkedResponseException(
158 2
                empty($options['headers']) === false ? $options['headers'] : []
159 2
            );
160
        }
161 2
        $this->filesystem->move($chunkFile, $storageFile);
162
163 2
        return $this->filesystem->createUploadedFile(
164 2
            $storageFile,
165 2
            $originalName,
166 2
            empty($options['mimeType']) === false ? $options['mimeType'] : $this->filesystem->mimeType($originalName),
167 2
            $this->filesystem->size($storageFile)
168 2
        );
169
    }
170
171
    /**
172
     * receive.
173
     *
174
     * @param string $inputName
175
     * @return \Symfony\Component\HttpFoundation\File\UploadedFile
176
     *
177
     * @throws \Recca0120\Upload\Exceptions\ChunkedResponseException
178
     */
179 6
    public function receive($inputName)
180
    {
181 6
        $chunksPath = $this->chunksPath();
182 6
        $storagePath = $this->storagePath();
183 6
        $uploadedFile = $this->makeDirectory($chunksPath)
184 6
            ->makeDirectory($storagePath)
185 6
            ->doReceive($inputName);
186 4
        $this->cleanDirectory($chunksPath);
187
188 4
        return $uploadedFile;
189
    }
190
191
    /**
192
     * doReceive.
193
     *
194
     * @param string $inputName
195
     * @return \Symfony\Component\HttpFoundation\File\UploadedFile
196
     *
197
     * @throws \Recca0120\Upload\Exceptions\ChunkedResponseException
198
     */
199
    abstract protected function doReceive($inputName);
200
201
    /**
202
     * deleteUploadedFile.
203
     *
204
     * @param \Symfony\Component\HttpFoundation\File\UploadedFile
205
     * @return $this
206
     */
207 1
    public function deleteUploadedFile(UploadedFile $uploadedFile)
208
    {
209 1
        $file = $uploadedFile->getPathname();
210 1
        if ($this->filesystem->isFile($file) === true) {
211 1
            $this->filesystem->delete($file);
212 1
        }
213
214 1
        return $this;
215
    }
216
217
    /**
218
     * completedResponse.
219
     *
220
     * @param \Illuminate\Http\JsonResponse $response
221
     * @return \Illuminate\Http\JsonResponse
222
     */
223 1
    public function completedResponse(JsonResponse $response)
224
    {
225 1
        return $response;
226
    }
227
}
228