public function __construct($bucket, $object, $context, $flags)
 {
     parent::__construct($bucket, $object, $context);
     $this->quiet = ($flags & STREAM_URL_STAT_QUIET) == STREAM_URL_STAT_QUIET;
     if (isset($object)) {
         // Drop the leading '/' from the object name.
         $this->prefix = substr($object, 1);
     }
 }
 public function __construct($bucket_name, $object_prefix, $context)
 {
     parent::__construct($bucket_name, $object_prefix, $context);
     // Ignore the leading slash
     if (isset($object_prefix)) {
         if (!util\endsWith($object_prefix, '/')) {
             $object_prefix .= '/';
         }
         $this->prefix = substr($object_prefix, 1);
     }
 }
 /**
  * Class constructor.
  * @param string $bucket_name The name of the bucket.
  * @param string $object_name The name of the object.
  * @param mixed $context The stream context for this operation.
  */
 public function __construct($bucket_name, $object_name, $context)
 {
     // $object_name should end with a trailing slash.
     if (!StringUtil::endsWith($object_name, parent::DELIMITER)) {
         $object_name = $object_name . parent::DELIMITER;
     }
     // $prefix is the $object_name without leading slash.
     if (strlen($object_name) > 1) {
         $this->prefix = substr($object_name, 1);
     }
     parent::__construct($bucket_name, $object_name, $context);
 }
 /**
  * Override the makeHttpRequest function so we can implement caching.
  * If caching is enabled then we try and retrieve a matching request for the
  * object name and range from memcache.
  * If we find a result in memcache, and optimistic caching is enabled then
  * we return that result immediately without checking if the object has
  * changed in GCS. Otherwise, we will issue a 'If-None-Match' request with
  * the ETag of the object to ensure it is still current.
  *
  * Optimisitic caching is best suited when the application is soley updating
  * objects in cloud storage, as the cache can be invalidated when the object
  * is updated by the application.
  */
 protected function makeHttpRequest($url, $method, $headers, $body = null)
 {
     if (!$this->context_options['enable_cache']) {
         return parent::makeHttpRequest($url, $method, $headers, $body);
     }
     $cache_key = sprintf(parent::MEMCACHE_KEY_FORMAT, $url, $headers['Range']);
     $cache_obj = $this->memcache_client->get($cache_key);
     if (false !== $cache_obj) {
         if ($this->context_options['enable_optimistic_cache']) {
             return $cache_obj;
         } else {
             $cache_etag = $this->getHeaderValue('ETag', $cache_obj['headers']);
             if (array_key_exists('If-Match', $headers)) {
                 // We will perform a If-None-Match to validate the cache object, only
                 // if it has the same ETag value as what we are asking for.
                 if ($headers['If-Match'] === $cache_etag) {
                     unset($headers['If-Match']);
                 } else {
                     // We are asking for a different object that what is in the cache.
                     $cache_etag = null;
                 }
             }
         }
         if (isset($cache_etag)) {
             $headers['If-None-Match'] = $cache_etag;
         }
     }
     $result = parent::makeHttpRequest($url, $method, $headers, $body);
     if (false === $result) {
         return false;
     }
     $status_code = $result['status_code'];
     if (HttpResponse::NOT_MODIFIED === $result['status_code']) {
         return $cache_obj;
     }
     if (in_array($status_code, self::$valid_status_codes)) {
         $this->memcache_client->set($cache_key, $result, 0, $this->context_options['read_cache_expiry_seconds']);
     }
     return $result;
 }
 /**
  * Test if a given bucket is writable. We will cache results in memcache as
  * this is an expensive operation. This might lead to incorrect results being
  * returned for this call for a short period while the result remains in the
  * cache.
  */
 private function isBucketWritable($bucket)
 {
     $cache_key_name = sprintf(parent::WRITABLE_MEMCACHE_KEY_FORMAT, $bucket);
     $memcache = new \Memcache();
     $result = $memcache->get($cache_key_name);
     if ($result) {
         return $result['is_writable'];
     }
     // We determine if the bucket is writable by trying to start a resumable
     // upload. GCS will cleanup the abandoned upload after 7 days, and it will
     // not be charged to the bucket owner.
     $token_header = $this->getOAuthTokenHeader(parent::WRITE_SCOPE);
     if ($token_header === false) {
         return false;
     }
     $headers = array_merge(parent::$upload_start_header, $token_header);
     $url = parent::createObjectUrl($bucket, parent::WRITABLE_TEMP_FILENAME);
     $http_response = $this->makeHttpRequest($url, "POST", $headers);
     if ($http_response === false) {
         return false;
     }
     $status_code = $http_response['status_code'];
     $is_writable = $status_code == HttpResponse::CREATED;
     $memcache->set($cache_key_name, ['is_writable' => $is_writable], null, $this->context_options['writable_cache_expiry_seconds']);
     return $is_writable;
 }