1 <?php
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
17
18 namespace OpenCloud\ObjectStore\Resource;
19
20 use Guzzle\Http\EntityBody;
21 use Guzzle\Http\Message\Response;
22 use Guzzle\Http\Url;
23 use OpenCloud\Common\Constants\Header as HeaderConst;
24 use OpenCloud\Common\Exceptions;
25 use OpenCloud\Common\Lang;
26 use OpenCloud\ObjectStore\Constants\UrlType;
27
28 29 30 31 32 33 34
35 class DataObject extends AbstractResource
36 {
37 const METADATA_LABEL = 'Object';
38
39 40 41
42 private $container;
43
44 45 46
47 protected $name;
48
49 50 51
52 protected $content;
53
54 55 56 57
58 protected $directory = false;
59
60 61 62
63 protected $contentType;
64
65 66 67
68 protected $contentLength;
69
70 71 72
73 protected $lastModified;
74
75 76 77
78 protected $etag;
79
80 81 82 83 84 85 86
87 public function __construct(Container $container, $data = null)
88 {
89 $this->setContainer($container);
90
91 parent::__construct($container->getService());
92
93
94 if (!empty($data->subdir)) {
95 $this->setName($data->subdir)->setDirectory(true);
96
97 return;
98 }
99
100 $this->populate($data);
101 }
102
103 104 105 106 107
108 public function populate($info, $setObjects = true)
109 {
110 parent::populate($info, $setObjects);
111
112 if (isset($info->bytes)) {
113 $this->setContentLength($info->bytes);
114 }
115 if (isset($info->last_modified)) {
116 $this->setLastModified($info->last_modified);
117 }
118 if (isset($info->content_type)) {
119 $this->setContentType($info->content_type);
120 }
121 if (isset($info->hash)) {
122 $this->setEtag($info->hash);
123 }
124 }
125
126 127 128 129 130 131
132 public function populateFromResponse(Response $response)
133 {
134 $this->content = $response->getBody();
135
136 $headers = $response->getHeaders();
137
138 return $this->setMetadata($headers, true)
139 ->setContentType((string) $headers[HeaderConst::CONTENT_TYPE])
140 ->setLastModified((string) $headers[HeaderConst::LAST_MODIFIED])
141 ->setContentLength((string) $headers[HeaderConst::CONTENT_LENGTH])
142 ->setEtag((string) $headers[HeaderConst::ETAG]);
143 }
144
145 public function refresh()
146 {
147 $response = $this->getService()->getClient()
148 ->get($this->getUrl())
149 ->send();
150
151 return $this->populateFromResponse($response);
152 }
153
154 155 156 157
158 public function setContainer(Container $container)
159 {
160 $this->container = $container;
161
162 return $this;
163 }
164
165 166 167
168 public function getContainer()
169 {
170 return $this->container;
171 }
172
173 174 175 176
177 public function setName($name)
178 {
179 $this->name = $name;
180
181 return $this;
182 }
183
184 185 186
187 public function getName()
188 {
189 return $this->name;
190 }
191
192 193 194 195
196 public function setDirectory($directory)
197 {
198 $this->directory = $directory;
199
200 return $this;
201 }
202
203 204 205
206 public function getDirectory()
207 {
208 return $this->directory;
209 }
210
211 212 213
214 public function isDirectory()
215 {
216 return (bool) $this->directory;
217 }
218
219 220 221 222
223 public function setContent($content)
224 {
225 $this->etag = null;
226 $this->contentType = null;
227 $this->content = EntityBody::factory($content);
228
229 return $this;
230 }
231
232 233 234
235 public function getContent()
236 {
237 return $this->content;
238 }
239
240 241 242 243
244 public function setContentType($contentType)
245 {
246 $this->contentType = $contentType;
247
248 return $this;
249 }
250
251 252 253
254 public function getContentType()
255 {
256 return $this->contentType ? : $this->content->getContentType();
257 }
258
259 260 261 262
263 public function setContentLength($contentLength)
264 {
265 $this->contentLength = $contentLength;
266
267 return $this;
268 }
269
270 271 272
273 public function getContentLength()
274 {
275 return $this->contentLength !== null ? $this->contentLength : $this->content->getContentLength();
276 }
277
278 279 280 281
282 public function setEtag($etag)
283 {
284 $this->etag = $etag;
285
286 return $this;
287 }
288
289 290 291
292 public function getEtag()
293 {
294 return $this->etag ? : $this->content->getContentMd5();
295 }
296
297 public function setLastModified($lastModified)
298 {
299 $this->lastModified = $lastModified;
300
301 return $this;
302 }
303
304 public function getLastModified()
305 {
306 return $this->lastModified;
307 }
308
309 public function primaryKeyField()
310 {
311 return 'name';
312 }
313
314 public function getUrl($path = null, array $params = array())
315 {
316 if (!$this->name) {
317 throw new Exceptions\NoNameError(Lang::translate('Object has no name'));
318 }
319
320 return $this->container->getUrl($this->name);
321 }
322
323 public function update($params = array())
324 {
325 $metadata = is_array($this->metadata) ? $this->metadata : $this->metadata->toArray();
326 $metadata = self::stockHeaders($metadata);
327
328
329 $metadata += array(
330 HeaderConst::CONTENT_TYPE => $this->contentType,
331 HeaderConst::LAST_MODIFIED => $this->lastModified,
332 HeaderConst::CONTENT_LENGTH => $this->contentLength,
333 HeaderConst::ETAG => $this->etag
334 );
335
336 return $this->container->uploadObject($this->name, $this->content, $metadata);
337 }
338
339 340 341 342
343 public function copy($destination)
344 {
345 return $this->getService()
346 ->getClient()
347 ->createRequest('COPY', $this->getUrl(), array(
348 'Destination' => (string) $destination
349 ))
350 ->send();
351 }
352
353 public function delete($params = array())
354 {
355 return $this->getService()->getClient()->delete($this->getUrl())->send();
356 }
357
358 359 360 361 362 363 364 365 366 367 368 369
370 public function getTemporaryUrl($expires, $method)
371 {
372 $method = strtoupper($method);
373 $expiry = time() + (int) $expires;
374
375
376 if ($method != 'GET' && $method != 'PUT') {
377 throw new Exceptions\InvalidArgumentError(sprintf(
378 'Bad method [%s] for TempUrl; only GET or PUT supported',
379 $method
380 ));
381 }
382
383
384 if (!($secret = $this->getService()->getAccount()->getTempUrlSecret())) {
385 throw new Exceptions\ObjectError('Cannot produce temporary URL without an account secret.');
386 }
387
388
389 $url = $this->getUrl();
390 $urlPath = urldecode($url->getPath());
391 $body = sprintf("%s\n%d\n%s", $method, $expiry, $urlPath);
392 $hash = hash_hmac('sha1', $body, $secret);
393
394 return sprintf('%s?temp_url_sig=%s&temp_url_expires=%d', $url, $hash, $expiry);
395 }
396
397 398 399 400 401 402
403 public function purge($email = null)
404 {
405 if (!$cdn = $this->getContainer()->getCdn()) {
406 return false;
407 }
408
409 $url = clone $cdn->getUrl();
410 $url->addPath($this->name);
411
412 $headers = ($email !== null) ? array('X-Purge-Email' => $email) : array();
413
414 return $this->getService()
415 ->getClient()
416 ->delete($url, $headers)
417 ->send();
418 }
419
420 421 422 423
424 public function getPublicUrl($type = UrlType::CDN)
425 {
426 $cdn = $this->container->getCdn();
427
428 switch ($type) {
429 case UrlType::CDN:
430 $uri = $cdn->getCdnUri();
431 break;
432 case UrlType::SSL:
433 $uri = $cdn->getCdnSslUri();
434 break;
435 case UrlType::STREAMING:
436 $uri = $cdn->getCdnStreamingUri();
437 break;
438 case UrlType::IOS_STREAMING:
439 $uri = $cdn->getIosStreamingUri();
440 break;
441 }
442
443 return (isset($uri)) ? Url::factory($uri)->addPath($this->name) : false;
444 }
445
446 protected static function headerIsValidMetadata($header)
447 {
448 $pattern = sprintf('#^%s-%s-Meta-#i', self::GLOBAL_METADATA_PREFIX, self::METADATA_LABEL);
449
450 return preg_match($pattern, $header);
451 }
452 }
453