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 ($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: