App Engine Python SDK version 1.8.8
[gae.git] / python / php / sdk / google / appengine / ext / cloud_storage_streams / CloudStorageStreamWrapper.php
bloba605022109bb681fb4612a506f4f580103e4c61b
1 <?php
2 /**
3 * Copyright 2007 Google Inc.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 /**
18 * A user space stream wrapper for reading and writing to Google Cloud Storage.
20 * See: http://www.php.net/manual/en/class.streamwrapper.php
24 namespace google\appengine\ext\cloud_storage_streams;
26 require_once 'google/appengine/api/cloud_storage/CloudStorageTools.php';
27 require_once 'google/appengine/ext/cloud_storage_streams/CloudStorageClient.php';
28 require_once 'google/appengine/ext/cloud_storage_streams/CloudStorageDeleteClient.php';
29 require_once 'google/appengine/ext/cloud_storage_streams/CloudStorageDirectoryClient.php';
30 require_once 'google/appengine/ext/cloud_storage_streams/CloudStorageReadClient.php';
31 require_once 'google/appengine/ext/cloud_storage_streams/CloudStorageRenameClient.php';
32 require_once 'google/appengine/ext/cloud_storage_streams/CloudStorageUrlStatClient.php';
33 require_once 'google/appengine/ext/cloud_storage_streams/CloudStorageWriteClient.php';
34 require_once 'google/appengine/util/array_util.php';
36 use google\appengine\api\cloud_storage\CloudStorageTools;
37 use google\appengine\util as util;
39 /**
40 * Allowed stream_context options.
41 * "anonymous": Boolean, if set then OAuth tokens will not be generated.
42 * "acl": The ACL to apply when creating an object.
43 * "Content-Type": The content type of the object being written.
45 final class CloudStorageStreamWrapper {
47 // The client instance that we're using to communicate with GS.
48 private $client;
50 // Must be public according to PHP documents - We capture the contents when
51 // constructing objects.
52 public $context;
54 const STREAM_OPEN_FOR_INCLUDE = 0x80;
56 private static $valid_read_modes = ['r', 'rb', 'rt'];
57 private static $valid_write_modes = ['w', 'wb', 'wt'];
59 /**
60 * Constructs a new stream wrapper.
62 public function __construct() {
65 /**
66 * Destructs an existing stream wrapper.
68 public function __destruct() {
71 /**
72 * Close an open directory handle.
74 public function dir_closedir() {
75 assert(isset($this->client));
76 $this->client->close();
77 $this->client = null;
80 /**
81 * Open a directory handle.
83 public function dir_opendir($path, $options) {
84 if (!$this->getBucketAndObjectFromPath($path, $bucket, $path)) {
85 trigger_error(sprintf("Invalid Google Cloud Storage path: %s", $path),
86 E_USER_ERROR);
87 return false;
90 $this->client = new CloudStorageDirectoryClient($bucket,
91 $path,
92 $this->context);
93 return $this->client->initialise();
96 /**
97 * Read entry from the directory handle.
99 * @return string representing the next filename, of false if there is no
100 * next file.
102 public function dir_readdir() {
103 assert(isset($this->client));
104 return $this->client->dir_readdir();
108 * Reset the output returned from dir_readdir.
110 * @return bool true if the stream can be rewound, false otherwise.
112 public function dir_rewinddir() {
113 assert(isset($this->client));
114 return $this->client->dir_rewinddir();
117 public function mkdir($path, $mode, $options) {
118 if (!$this->getBucketAndObjectFromPath($path, $bucket, $object) ||
119 !isset($object)) {
120 if (($options | STREAM_REPORT_ERRORS) != 0) {
121 trigger_error(sprintf("Invalid Google Cloud Storage path: %s", $path),
122 E_USER_ERROR);
124 return false;
126 $client = new CloudStorageDirectoryClient($bucket,
127 $object,
128 $this->context);
129 return $client->mkdir($options);
132 public function rmdir($path, $options) {
133 if (!$this->getBucketAndObjectFromPath($path, $bucket, $object) ||
134 !isset($object)) {
135 if (($options | STREAM_REPORT_ERRORS) != 0) {
136 trigger_error(sprintf("Invalid Google Cloud Storage path: %s", $path),
137 E_USER_ERROR);
139 return false;
141 $client = new CloudStorageDirectoryClient($bucket,
142 $object,
143 $this->context);
144 return $client->rmdir($options);
148 * Rename a cloud storage object.
150 * @return TRUE if the object was renamed, FALSE otherwise
152 public function rename($from, $to) {
153 if (!$this->getBucketAndObjectFromPath($from, $from_bucket, $from_object) ||
154 !isset($from_object)) {
155 trigger_error(sprintf("Invalid Google Cloud Storage path: %s", $from),
156 E_USER_ERROR);
157 return false;
159 if (!$this->getBucketAndObjectFromPath($to, $to_bucket, $to_object) ||
160 !isset($to_object)) {
161 trigger_error(sprintf("Invalid Google Cloud Storage path: %s", $to),
162 E_USER_ERROR);
163 return false;
165 $client = new CloudStorageRenameClient($from_bucket,
166 $from_object,
167 $to_bucket,
168 $to_object,
169 $this->context);
170 return $client->rename();
174 * Retrieve the underlaying resource of the stream, called in response to
175 * stream_select().
177 * As GS streams have no underlying resource, we can only return false
179 public function stream_cast() {
180 return false;
184 * All resources that were locked, or allocated, by the wrapper should be
185 * released.
187 * No value is returned.
189 public function stream_close() {
190 assert(isset($this->client));
191 $this->client->close();
192 $this->client = null;
196 * Tests for end-of-file on a file pointer.
198 * @return TRUE if the read/write position is at the end of the stream and if
199 * no more data is available to be read, or FALSE otherwise
201 public function stream_eof() {
202 assert(isset($this->client));
203 return $this->client->eof();
207 * Flushes the output.
209 * @return TRUE if the cached data was successfully stored (or if there was
210 * no data to store), or FALSE if the data could not be stored.
212 public function stream_flush() {
213 assert(isset($this->client));
214 return $this->client->flush();
217 public function stream_metadata($path, $option, $value) {
218 return false;
221 public function stream_open($path, $mode, $options, &$opened_path) {
222 if (!$this->getBucketAndObjectFromPath($path, $bucket, $object) ||
223 !isset($object)) {
224 if (($options & STREAM_REPORT_ERRORS) != 0) {
225 trigger_error(sprintf("Invalid Google Cloud Storage path: %s", $path),
226 E_USER_ERROR);
228 return false;
231 if (($options & self::STREAM_OPEN_FOR_INCLUDE) != 0) {
232 $allowed_buckets = explode(",", GAE_INCLUDE_GS_BUCKETS);
233 $include_allowed = false;
234 foreach ($allowed_buckets as $bucket_name) {
235 $bucket_name = trim($bucket_name);
236 if ($bucket_name === $bucket) {
237 $include_allowed = true;
238 break;
241 if (!$include_allowed) {
242 if (($options & STREAM_REPORT_ERRORS) != 0) {
243 trigger_error(
244 sprintf("Not allowed to include/require from bucket '%s'",
245 $bucket),
246 E_USER_ERROR);
248 return false;
252 if (in_array($mode, self::$valid_read_modes)) {
253 $this->client = new CloudStorageReadClient($bucket,
254 $object,
255 $this->context);
256 } else if (in_array($mode, self::$valid_write_modes)) {
257 $this->client = new CloudStorageWriteClient($bucket,
258 $object,
259 $this->context);
260 } else {
261 if (($options & STREAM_REPORT_ERRORS) != 0) {
262 trigger_error(sprintf("Invalid mode: %s", $mode), E_USER_ERROR);
264 return false;
267 return $this->client->initialize();
271 * Read from a stream, return string of bytes.
273 public function stream_read($count) {
274 assert(isset($this->client));
275 return $this->client->read($count);
278 public function stream_seek($offset, $whence) {
279 assert(isset($this->client));
280 return $this->client->seek($offset, $whence);
283 public function stream_set_option($option, $arg1, $arg2) {
284 assert(isset($this->client));
285 return false;
288 public function stream_stat() {
289 assert(isset($this->client));
290 return $this->client->stat();
293 public function stream_tell() {
294 assert(isset($this->client));
295 return $this->client->tell();
299 * Return the number of bytes written.
301 public function stream_write($data) {
302 assert(isset($this->client));
303 return $this->client->write($data);
307 * Deletes a file. Called in response to unlink($filename).
309 public function unlink($path) {
310 if (!$this->getBucketAndObjectFromPath($path, $bucket, $object) ||
311 !isset($object)) {
312 trigger_error(sprintf("Invalid Google Cloud Storage path: %s", $path),
313 E_USER_ERROR);
314 return false;
317 $this->client = new CloudStorageDeleteClient($bucket,
318 $object,
319 $this->context);
320 return $this->client->delete();
323 public function url_stat($path, $flags) {
324 if (!$this->getBucketAndObjectFromPath($path, $bucket, $object)) {
325 if (($flags & STREAM_URL_STAT_QUIET) != 0) {
326 trigger_error(sprintf("Invalid Google Cloud Storage path: %s", $path),
327 E_USER_ERROR);
328 return false;
332 $client = new CloudStorageUrlStatClient($bucket,
333 $object,
334 $this->context,
335 $flags);
336 return $client->stat();
340 * Parse the supplied path and extract the bucket and object names from it.
341 * It is possible that there is no object name in the path and a null will be
342 * returned in the $object parameters if this is the case.
344 private function getBucketAndObjectFromPath($path, &$bucket, &$object) {
345 // Decompose the $path into the GCS url components and check
346 $url_parts = parse_url($path);
348 if ($url_parts === false) {
349 return false;
351 if ($url_parts['scheme'] !== 'gs' || empty($url_parts['host'])) {
352 trigger_error(sprintf("Invalid Google Cloud Storage path: %s", $path),
353 E_USER_ERROR);
354 return false;
356 $bucket = $url_parts['host'];
357 $object = null;
358 $path = util\findByKeyOrNull($url_parts, 'path');
359 if (isset($path) && $path !== "/") {
360 $object = $path;
363 // Validate bucket & object names.
364 try {
365 CloudStorageTools::getFilename($bucket, $object);
366 } catch (\InvalidArgumentException $e) {
367 return false;
370 return true;