Completed
Push — master ( af301e...15ef57 )
by Kunal
04:00
created

DropboxFile::open()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 28
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 28
ccs 0
cts 18
cp 0
rs 8.439
cc 6
eloc 11
nc 7
nop 0
crap 42
1
<?php
2
3
namespace Kunnu\Dropbox;
4
5
use Kunnu\Dropbox\Exceptions\DropboxClientException;
6
7
/**
8
 * DropboxFile
9
 */
10
class DropboxFile
11
{
12
    const MODE_READ = 'r';
13
14
    const MODE_WRITE = 'w';
15
16
    /**
17
     * Path of the file to upload
18
     *
19
     * @var string
20
     */
21
    protected $path;
22
23
    /**
24
     * The maximum bytes to read. Defaults to -1 (read all the remaining buffer).
25
     *
26
     * @var int
27
     */
28
    protected $maxLength = -1;
29
30
    /**
31
     * Seek to the specified offset before reading.
32
     * If this number is negative, no seeking will
33
     * occur and reading will start from the current.
34
     *
35
     * @var int
36
     */
37
    protected $offset = -1;
38
39
    /**
40
     * File Stream
41
     *
42
     * @var \GuzzleHttp\Psr7\Stream
43
     */
44
    protected $stream;
45
46
    /**
47
     * The type of access
48
     *
49
     * @var string
50
     */
51
    protected $mode;
52
53
    /**
54
     * Flag to see if we created an instance using a stream
55
     *
56
     * @var bool
57
     */
58
    private $isStream = false;
59
60
    /**
61
     * Create a new DropboxFile instance
62
     *
63
     * @param string $filePath Path of the file to upload
64
     * @param string $mode     The type of access
65
     */
66
    public function __construct($filePath, $mode = self::MODE_READ)
67
    {
68
        $this->path = $filePath;
69
        $this->mode = $mode;
70
    }
71
72
    /**
73
     * Create a new DropboxFile instance using a file stream
74
     *
75
     * @param        $fileName
76
     * @param        $resource
77
     * @param string $mode
78
     *
79
     * @return DropboxFile
80
     * @throws DropboxClientException
81
     */
82
    public static function createByStream($fileName, $resource, $mode = self::MODE_READ)
83
    {
84
        // create a new stream and set it to the dropbox file
85
        $stream = \GuzzleHttp\Psr7\stream_for($resource);
86
        if (!$stream) {
87
            throw new DropboxClientException('Failed to create DropboxFile instance. Unable to open the given resource.');
88
        }
89
90
        // Try to get the file path from the stream (we'll need this for uploading bigger files)
91
        $filePath = $stream->getMetadata('uri');
92
        if (!is_null($filePath)) {
93
            $fileName = $filePath;
94
        }
95
96
        $dropboxFile = new self($fileName, $mode);
97
        $dropboxFile->setStream($stream);
98
99
        return $dropboxFile;
100
    }
101
102
    /**
103
     * Create a new DropboxFile instance using a file path
104
     *
105
     * This behaves the same as the constructor but was added in order to
106
     * match the syntax of the static createByStream function
107
     *
108
     * @see DropboxFile::createByStream()
109
     *
110
     * @param $filePath
111
     * @param $mode
112
     *
113
     * @return DropboxFile
114
     */
115
    public static function createByPath($filePath, $mode)
116
    {
117
        return new self($filePath, $mode);
118
    }
119
120
    /**
121
     * Closes the stream when destructed.
122
     */
123
    public function __destruct()
124
    {
125
        $this->close();
126
    }
127
128
    /**
129
     * Close the file stream
130
     */
131
    public function close()
132
    {
133
        if ($this->stream) {
134
            $this->stream->close();
135
        }
136
    }
137
138
    /**
139
     * Set the offset to start reading
140
     * the data from the stream
141
     *
142
     * @param int $offset
143
     */
144
    public function setOffset($offset)
145
    {
146
        $this->offset = $offset;
147
    }
148
149
    /**
150
     * Set the Max Length till where to read
151
     * the data from the stream.
152
     *
153
     * @param int $maxLength
154
     */
155
    public function setMaxLength($maxLength)
156
    {
157
        $this->maxLength = $maxLength;
158
    }
159
160
    /**
161
     * Return the contents of the file
162
     *
163
     * @return string
164
     */
165
    public function getContents()
166
    {
167
        $stream = $this->getStream();
168
        // If an offset is provided
169
        if ($this->offset !== -1) {
170
            // Seek to the offset
171
            $stream->seek($this->offset);
172
        }
173
174
        // If a max length is provided
175
        if ($this->maxLength !== -1) {
176
            // Read from the offset till the maxLength
177
            return $stream->read($this->maxLength);
178
        }
179
180
        return $stream->getContents();
181
    }
182
183
    /**
184
     * Get the Open File Stream
185
     *
186
     * @return \GuzzleHttp\Psr7\Stream
187
     */
188
    public function getStream()
189
    {
190
        if (!$this->stream) {
191
            $this->open();
192
        }
193
        return $this->stream;
194
    }
195
196
    /**
197
     * Manually set the stream for this DropboxFile instance
198
     *
199
     * @param $stream
200
     */
201
    public function setStream($stream)
202
    {
203
        $this->isStream = true;
204
        $this->stream = $stream;
205
    }
206
207
    /**
208
     * Opens the File Stream
209
     *
210
     * @throws DropboxClientException
211
     *
212
     * @return void
213
     */
214
    public function open()
215
    {
216
        // File was created from a stream so don't open it again
217
        if ($this->isCreatedFromStream()) {
218
            return;
219
        }
220
221
        // File is not a remote file
222
        if (!$this->isRemoteFile($this->path)) {
223
            // File is not Readable
224
            if ($this->isNotReadable()) {
225
                throw new DropboxClientException('Failed to create DropboxFile instance. Unable to read resource: ' . $this->path . '.');
226
            }
227
228
            // File is not Writable
229
            if ($this->isNotWritable()) {
230
                throw new DropboxClientException('Failed to create DropboxFile instance. Unable to write resource: ' . $this->path . '.');
231
            }
232
        }
233
234
        // Create a stream
235
        $this->stream = \GuzzleHttp\Psr7\stream_for(fopen($this->path, $this->mode));
236
237
        // Unable to create stream
238
        if (!$this->stream) {
239
            throw new DropboxClientException('Failed to create DropboxFile instance. Unable to open resource: ' . $this->path . '.');
240
        }
241
    }
242
243
    /**
244
     * @return bool
245
     */
246
    protected function isCreatedFromStream()
247
    {
248
        return $this->stream && $this->isStream === true;
249
    }
250
251
    /**
252
     * Returns true if the path to the file is remote
253
     *
254
     * @param string $pathToFile
255
     *
256
     * @return boolean
257
     */
258
    protected function isRemoteFile($pathToFile)
259
    {
260
        return preg_match('/^(https?|ftp):\/\/.*/', $pathToFile) === 1;
261
    }
262
263
    /**
264
     * @return bool
265
     */
266
    protected function isNotReadable()
267
    {
268
        return self::MODE_READ === $this->mode && !is_readable($this->path);
269
    }
270
271
    /**
272
     * @return bool
273
     */
274
    protected function isNotWritable()
275
    {
276
        return self::MODE_WRITE === $this->mode && file_exists($this->path) && !is_writable($this->path);
277
    }
278
279
    /**
280
     * Get the name of the file
281
     *
282
     * @return string
283
     */
284
    public function getFileName()
285
    {
286
        return basename($this->path);
287
    }
288
289
    /**
290
     * Get the path of the file
291
     *
292
     * @return string
293
     */
294
    public function getFilePath()
295
    {
296
        return $this->path;
297
    }
298
299
    /**
300
     * Get the mode of the file stream
301
     *
302
     * @return string
303
     */
304
    public function getMode()
305
    {
306
        return $this->mode;
307
    }
308
309
    /**
310
     * Get the size of the file
311
     *
312
     * @return int
313
     */
314
    public function getSize()
315
    {
316
        return $this->getStream()->getSize();
317
    }
318
319
    /**
320
     * Get mimetype of the file
321
     *
322
     * @return string
323
     */
324
    public function getMimetype()
325
    {
326
        return \GuzzleHttp\Psr7\mimetype_from_filename($this->path) ?: 'text/plain';
327
    }
328
}
329