Completed
Pull Request — master (#13)
by
unknown
06:13
created

WebDAVAdapter::applyPathPrefix()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace League\Flysystem\WebDAV;
4
5
use League\Flysystem\Adapter\AbstractAdapter;
6
use League\Flysystem\Adapter\Polyfill\NotSupportingVisibilityTrait;
7
use League\Flysystem\Adapter\Polyfill\StreamedCopyTrait;
8
use League\Flysystem\Adapter\Polyfill\StreamedTrait;
9
use League\Flysystem\Config;
10
use League\Flysystem\Util;
11
use LogicException;
12
use Sabre\DAV\Client;
13
use Sabre\DAV\Exception;
14
use Sabre\DAV\Exception\NotFound;
15
16
class WebDAVAdapter extends AbstractAdapter
17
{
18
    use StreamedTrait;
19
    use StreamedCopyTrait;
20
    use NotSupportingVisibilityTrait;
21
22
    /**
23
     * @var array
24
     */
25
    protected static $resultMap = [
26
        '{DAV:}getcontentlength' => 'size',
27
        '{DAV:}getcontenttype' => 'mimetype',
28
        'content-length' => 'size',
29
        'content-type' => 'mimetype',
30
    ];
31
32
    /**
33
     * @var Client
34
     */
35
    protected $client;
36
37
    /**
38
     * Constructor.
39
     *
40
     * @param Client $client
41
     * @param string $prefix
42
     */
43
    public function __construct(Client $client, $prefix = null)
44
    {
45
        $this->client = $client;
46
        $this->setPathPrefix($prefix);
47
    }
48
49
    /**
50
     * {@inheritdoc}
51
     */
52
    public function getMetadata($path)
53
    {
54
        $location = $this->applyPathPrefix($path);
55
56
        try {
57
            $result = $this->client->propFind($location, [
58
                '{DAV:}displayname',
59
                '{DAV:}getcontentlength',
60
                '{DAV:}getcontenttype',
61
                '{DAV:}getlastmodified',
62
            ]);
63
64
            return $this->normalizeObject($result, $path);
65
        } catch (Exception $e) {
66
            return false;
67
        }
68
    }
69
70
    /**
71
     * {@inheritdoc}
72
     */
73
    public function has($path)
74
    {
75
        return $this->getMetadata($path);
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81
    public function read($path)
82
    {
83
        $location = $this->applyPathPrefix($path);
84
85
        try {
86
            $response = $this->client->request('GET', $location);
87
88
            if ($response['statusCode'] !== 200) {
89
                return false;
90
            }
91
92
            return array_merge([
93
                'contents' => $response['body'],
94
                'timestamp' => strtotime(is_array($response['headers']['last-modified'])
95
                    ? current($response['headers']['last-modified'])
96
                    : $response['headers']['last-modified']),
97
                'path' => $path,
98
            ], Util::map($response['headers'], static::$resultMap));
99
        } catch (Exception $e) {
100
            return false;
101
        }
102
    }
103
104
    /**
105
     * {@inheritdoc}
106
     */
107
    public function write($path, $contents, Config $config)
108
    {
109
        $location = $this->applyPathPrefix($path);
110
        $response = $this->client->request('PUT', $location, $contents);
111
112
        if ($response['statusCode'] >= 400) {
113
            return false;
114
        }
115
116
        $result = compact('path', 'contents');
117
118
        if ($config->get('visibility')) {
119
            throw new LogicException(__CLASS__.' does not support visibility settings.');
120
        }
121
122
        return $result;
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128
    public function update($path, $contents, Config $config)
129
    {
130
        return $this->write($path, $contents, $config);
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136
    public function rename($path, $newpath)
137
    {
138
        $location = $this->applyPathPrefix($path);
139
        $newLocation = $this->applyPathPrefix($newpath);
140
141
        try {
142
            $response = $this->client->request('MOVE', '/'.ltrim($location, '/'), null, [
143
                'Destination' => '/'.ltrim($newLocation, '/'),
144
            ]);
145
146
            if ($response['statusCode'] >= 200 && $response['statusCode'] < 300) {
147
                return true;
148
            }
149
        } catch (NotFound $e) {
150
            // Would have returned false here, but would be redundant
151
        }
152
153
        return false;
154
    }
155
156
    /**
157
     * {@inheritdoc}
158
     */
159
    public function delete($path)
160
    {
161
        $location = $this->applyPathPrefix($path);
162
163
        try {
164
            $this->client->request('DELETE', $location);
165
166
            return true;
167
        } catch (NotFound $e) {
168
            return false;
169
        }
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175
    public function createDir($path, Config $config)
176
    {
177
        $location = $this->applyPathPrefix($path);
178
        $response = $this->client->request('MKCOL', $location);
179
180
        if ($response['statusCode'] !== 201) {
181
            return false;
182
        }
183
184
        return compact('path') + ['type' => 'dir'];
185
    }
186
187
    /**
188
     * {@inheritdoc}
189
     */
190
    public function deleteDir($dirname)
191
    {
192
        return $this->delete($dirname);
193
    }
194
195
    /**
196
     * {@inheritdoc}
197
     */
198
    public function listContents($directory = '', $recursive = false)
199
    {
200
        $location = $this->applyPathPrefix($directory);
201
        $response = $this->client->propFind($location . '/', [
202
            '{DAV:}displayname',
203
            '{DAV:}getcontentlength',
204
            '{DAV:}getcontenttype',
205
            '{DAV:}getlastmodified',
206
        ], 1);
207
208
        array_shift($response);
209
        $result = [];
210
211
        foreach ($response as $path => $object) {
212
            $path = $this->removePathPrefix($path);
213
            $object = $this->normalizeObject($object, $path);
214
            $result[] = $object;
215
216
            if ($recursive && $object['type'] === 'dir') {
217
                $result = array_merge($result, $this->listContents($object['path'], true));
218
            }
219
        }
220
221
        return $result;
222
    }
223
224
    /**
225
     * {@inheritdoc}
226
     */
227
    public function getSize($path)
228
    {
229
        return $this->getMetadata($path);
230
    }
231
232
    /**
233
     * {@inheritdoc}
234
     */
235
    public function getTimestamp($path)
236
    {
237
        return $this->getMetadata($path);
238
    }
239
240
    /**
241
     * {@inheritdoc}
242
     */
243
    public function getMimetype($path)
244
    {
245
        return $this->getMetadata($path);
246
    }
247
248
    /**
249
     * Normalise a WebDAV repsonse object.
250
     *
251
     * @param array  $object
252
     * @param string $path
253
     *
254
     * @return array
255
     */
256
    protected function normalizeObject(array $object, $path)
257
    {
258
        if (! isset($object['{DAV:}getcontentlength'])) {
259
            return ['type' => 'dir', 'path' => trim($path, '/')];
260
        }
261
262
        $result = Util::map($object, static::$resultMap);
263
264
        if (isset($object['{DAV:}getlastmodified'])) {
265
            $result['timestamp'] = strtotime($object['{DAV:}getlastmodified']);
266
        }
267
268
        $result['type'] = 'file';
269
        $result['path'] = trim($path, '/');
270
271
        return $result;
272
    }
273
274
    /**
275
     * @param string $path
276
     * @return string
277
     */
278
    public function applyPathPrefix($path)
279
    {
280
        $pathWithPrefix = parent::applyPathPrefix($path);
281
282
        return str_replace(' ', '%20', $pathWithPrefix);
283
    }
284
}
285