diff --git a/3rdparty b/3rdparty index 045dde529e..20066c9f65 160000 --- a/3rdparty +++ b/3rdparty @@ -1 +1 @@ -Subproject commit 045dde529e050316788a63cd0067a38bbc6921b0 +Subproject commit 20066c9f65fe9237895461ff3af2ac81218382aa diff --git a/apps/files_external/3rdparty/php-opencloud/LICENSE b/apps/files_external/3rdparty/php-opencloud/LICENSE deleted file mode 100644 index f7c56967e6..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/LICENSE +++ /dev/null @@ -1,16 +0,0 @@ - Copyright 2012-2013 Rackspace US, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - All contributions to this repository are covered under the same license, - terms, and conditions. \ No newline at end of file diff --git a/apps/files_external/3rdparty/php-opencloud/lib/Autoload.php b/apps/files_external/3rdparty/php-opencloud/lib/Autoload.php deleted file mode 100644 index 32e9dc24b7..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/Autoload.php +++ /dev/null @@ -1,296 +0,0 @@ -useIncludePath = $useIncludePath; - } - - /** - * Can be used to check if the autoloader uses the include path to check - * for classes. - * - * @return Boolean - */ - public function getUseIncludePath() - { - return $this->useIncludePath; - } - - /** - * Gets the configured namespaces. - * - * @return array A hash with namespaces as keys and directories as values - */ - public function getNamespaces() - { - return $this->namespaces; - } - - /** - * Gets the configured class prefixes. - * - * @return array A hash with class prefixes as keys and directories as values - */ - public function getPrefixes() - { - return $this->prefixes; - } - - /** - * Gets the directory(ies) to use as a fallback for namespaces. - * - * @return array An array of directories - */ - public function getNamespaceFallbacks() - { - return $this->namespaceFallbacks; - } - - /** - * Gets the directory(ies) to use as a fallback for class prefixes. - * - * @return array An array of directories - */ - public function getPrefixFallbacks() - { - return $this->prefixFallbacks; - } - - /** - * Registers the directory to use as a fallback for namespaces. - * - * @param array $dirs An array of directories - * - * @api - */ - public function registerNamespaceFallbacks(array $dirs) - { - $this->namespaceFallbacks = $dirs; - } - - /** - * Registers a directory to use as a fallback for namespaces. - * - * @param string $dir A directory - */ - public function registerNamespaceFallback($dir) - { - $this->namespaceFallbacks[] = $dir; - } - - /** - * Registers directories to use as a fallback for class prefixes. - * - * @param array $dirs An array of directories - * - * @api - */ - public function registerPrefixFallbacks(array $dirs) - { - $this->prefixFallbacks = $dirs; - } - - /** - * Registers a directory to use as a fallback for class prefixes. - * - * @param string $dir A directory - */ - public function registerPrefixFallback($dir) - { - $this->prefixFallbacks[] = $dir; - } - - /** - * Registers an array of namespaces - * - * @param array $namespaces An array of namespaces (namespaces as keys and locations as values) - * - * @api - */ - public function registerNamespaces(array $namespaces) - { - foreach ($namespaces as $namespace => $locations) { - $this->namespaces[$namespace] = (array) $locations; - } - } - - /** - * Registers a namespace. - * - * @param string $namespace The namespace - * @param array|string $paths The location(s) of the namespace - * - * @api - */ - public function registerNamespace($namespace, $paths) - { - $this->namespaces[$namespace] = (array) $paths; - } - - /** - * Registers an array of classes using the PEAR naming convention. - * - * @param array $classes An array of classes (prefixes as keys and locations as values) - * - * @api - */ - public function registerPrefixes(array $classes) - { - foreach ($classes as $prefix => $locations) { - $this->prefixes[$prefix] = (array) $locations; - } - } - - /** - * Registers a set of classes using the PEAR naming convention. - * - * @param string $prefix The classes prefix - * @param array|string $paths The location(s) of the classes - * - * @api - */ - public function registerPrefix($prefix, $paths) - { - $this->prefixes[$prefix] = (array) $paths; - } - - /** - * Registers this instance as an autoloader. - * - * @param Boolean $prepend Whether to prepend the autoloader or not - * - * @api - */ - public function register($prepend = false) - { - spl_autoload_register(array($this, 'loadClass'), true, $prepend); - } - - /** - * Fix for certain versions of PHP that have trouble with - * namespaces with leading separators. - * - * @access private - * @param mixed $className - * @return void - */ - private function makeBackwardsCompatible($className) - { - return (phpversion() < '5.3.3') ? ltrim($className, '\\') : $className; - } - - /** - * Loads the given class or interface. - * - * @param string $class The name of the class - * - * @return Boolean|null True, if loaded - */ - public function loadClass($class) - { - $class = $this->makeBackwardsCompatible($class); - - if ($file = $this->findFile($class)) { - require $file; - - return true; - } - } - - /** - * Finds the path to the file where the class is defined. - * - * @param string $class The name of the class - * - * @return string|null The path, if found - */ - public function findFile($class) - { - if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name - $namespace = substr($class, 0, $pos); - $className = substr($class, $pos + 1); - $normalizedClass = str_replace('\\', DIRECTORY_SEPARATOR, $namespace).DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $className).'.php'; - foreach ($this->namespaces as $ns => $dirs) { - if (0 !== strpos($namespace, $ns)) { - continue; - } - - foreach ($dirs as $dir) { - $file = $dir.DIRECTORY_SEPARATOR.$normalizedClass; - if (is_file($file)) { - return $file; - } - } - } - - foreach ($this->namespaceFallbacks as $dir) { - $file = $dir.DIRECTORY_SEPARATOR.$normalizedClass; - if (is_file($file)) { - return $file; - } - } - - } else { - // PEAR-like class name - $normalizedClass = str_replace('_', DIRECTORY_SEPARATOR, $class).'.php'; - foreach ($this->prefixes as $prefix => $dirs) { - if (0 !== strpos($class, $prefix)) { - continue; - } - - foreach ($dirs as $dir) { - $file = $dir.DIRECTORY_SEPARATOR.$normalizedClass; - if (is_file($file)) { - return $file; - } - } - } - - foreach ($this->prefixFallbacks as $dir) { - $file = $dir.DIRECTORY_SEPARATOR.$normalizedClass; - if (is_file($file)) { - return $file; - } - } - } - - if ($this->useIncludePath && $file = stream_resolve_include_path($normalizedClass)) { - return $file; - } - } -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Base.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Base.php deleted file mode 100644 index f80c9320e2..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Base.php +++ /dev/null @@ -1,301 +0,0 @@ - - * @author Jamie Hannaford - */ - -namespace OpenCloud\Common; - -use OpenCloud\Common\Lang; -use OpenCloud\Common\Exceptions\AttributeError; -use OpenCloud\Common\Exceptions\JsonError; -use OpenCloud\Common\Exceptions\UrlError; - -/** - * The root class for all other objects used or defined by this SDK. - * - * It contains common code for error handling as well as service functions that - * are useful. Because it is an abstract class, it cannot be called directly, - * and it has no publicly-visible properties. - */ -abstract class Base -{ - - private $http_headers = array(); - private $_errors = array(); - - /** - * Debug status. - * - * @var LoggerInterface - * @access private - */ - private $logger; - - /** - * Sets the Logger object. - * - * @param \OpenCloud\Common\Log\LoggerInterface $logger - */ - public function setLogger(Log\LoggerInterface $logger) - { - $this->logger = $logger; - } - - /** - * Returns the Logger object. - * - * @return \OpenCloud\Common\Log\AbstractLogger - */ - public function getLogger() - { - if (null === $this->logger) { - $this->setLogger(new Log\Logger); - } - return $this->logger; - } - - /** - * Returns the URL of the service/object - * - * The assumption is that nearly all objects will have a URL; at this - * base level, it simply throws an exception to enforce the idea that - * subclasses need to define this method. - * - * @throws UrlError - */ - public function url($subresource = '') - { - throw new UrlError(Lang::translate( - 'URL method must be overridden in class definition' - )); - } - -/** - * Populates the current object based on an unknown data type. - * - * @param array|object|string|integer $info - * @throws Exceptions\InvalidArgumentError - */ - public function populate($info, $setObjects = true) - { - if (is_string($info) || is_integer($info)) { - - // If the data type represents an ID, the primary key is set - // and we retrieve the full resource from the API - $this->{$this->primaryKeyField()} = (string) $info; - $this->refresh($info); - - } elseif (is_object($info) || is_array($info)) { - - foreach($info as $key => $value) { - - if ($key == 'metadata' || $key == 'meta') { - - if (empty($this->metadata) || !$this->metadata instanceof Metadata) { - $this->metadata = new Metadata; - } - - // Metadata - $this->$key->setArray($value); - - } elseif (!empty($this->associatedResources[$key]) && $setObjects === true) { - - // Associated resource - try { - $resource = $this->service()->resource($this->associatedResources[$key], $value); - $resource->setParent($this); - $this->$key = $resource; - } catch (Exception\ServiceException $e) {} - - } elseif (!empty($this->associatedCollections[$key]) && $setObjects === true) { - - // Associated collection - try { - $this->$key = $this->service()->resourceList($this->associatedCollections[$key], null, $this); - } catch (Exception\ServiceException $e) {} - - } else { - - // Normal key/value pair - $this->$key = $value; - } - } - } elseif (null !== $info) { - throw new Exceptions\InvalidArgumentError(sprintf( - Lang::translate('Argument for [%s] must be string or object'), - get_class() - )); - } - } - - /** - * Sets extended attributes on an object and validates them - * - * This function is provided to ensure that attributes cannot - * arbitrarily added to an object. If this function is called, it - * means that the attribute is not defined on the object, and thus - * an exception is thrown. - * - * @codeCoverageIgnore - * - * @param string $property the name of the attribute - * @param mixed $value the value of the attribute - * @return void - */ - public function __set($property, $value) - { - $this->setProperty($property, $value); - } - - /** - * Sets an extended (unrecognized) property on the current object - * - * If RAXSDK_STRICT_PROPERTY_CHECKS is TRUE, then the prefix of the - * property name must appear in the $prefixes array, or else an - * exception is thrown. - * - * @param string $property the property name - * @param mixed $value the value of the property - * @param array $prefixes optional list of supported prefixes - * @throws \OpenCloud\AttributeError if strict checks are on and - * the property prefix is not in the list of prefixes. - */ - public function setProperty($property, $value, array $prefixes = array()) - { - // if strict checks are off, go ahead and set it - if (!RAXSDK_STRICT_PROPERTY_CHECKS - || $this->checkAttributePrefix($property, $prefixes) - ) { - $this->$property = $value; - } else { - // if that fails, then throw the exception - throw new AttributeError(sprintf( - Lang::translate('Unrecognized attribute [%s] for [%s]'), - $property, - get_class($this) - )); - } - } - - /** - * Converts an array of key/value pairs into a single query string - * - * For example, array('A'=>1,'B'=>2) would become 'A=1&B=2'. - * - * @param array $arr array of key/value pairs - * @return string - */ - public function makeQueryString($array) - { - $queryString = ''; - - foreach($array as $key => $value) { - if ($queryString) { - $queryString .= '&'; - } - $queryString .= urlencode($key) . '=' . urlencode($this->to_string($value)); - } - - return $queryString; - } - - /** - * Checks the most recent JSON operation for errors - * - * This function should be called after any `json_*()` function call. - * This ensures that nasty JSON errors are detected and the proper - * exception thrown. - * - * Example: - * `$obj = json_decode($string);` - * `if (check_json_error()) do something ...` - * - * @return boolean TRUE if an error occurred, FALSE if none - * @throws JsonError - * - * @codeCoverageIgnore - */ - public function checkJsonError() - { - switch (json_last_error()) { - case JSON_ERROR_NONE: - return; - case JSON_ERROR_DEPTH: - $jsonError = 'JSON error: The maximum stack depth has been exceeded'; - break; - case JSON_ERROR_STATE_MISMATCH: - $jsonError = 'JSON error: Invalid or malformed JSON'; - break; - case JSON_ERROR_CTRL_CHAR: - $jsonError = 'JSON error: Control character error, possibly incorrectly encoded'; - break; - case JSON_ERROR_SYNTAX: - $jsonError = 'JSON error: Syntax error'; - break; - case JSON_ERROR_UTF8: - $jsonError = 'JSON error: Malformed UTF-8 characters, possibly incorrectly encoded'; - break; - default: - $jsonError = 'Unexpected JSON error'; - break; - } - - if (isset($jsonError)) { - throw new JsonError(Lang::translate($jsonError)); - } - } - - /** - * Returns a class that implements the HttpRequest interface. - * - * This can be stubbed out for unit testing and avoid making live calls. - */ - public function getHttpRequestObject($url, $method = 'GET', array $options = array()) - { - return new Request\Curl($url, $method, $options); - } - - /** - * Checks the attribute $property and only permits it if the prefix is - * in the specified $prefixes array - * - * This is to support extension namespaces in some services. - * - * @param string $property the name of the attribute - * @param array $prefixes a list of prefixes - * @return boolean TRUE if valid; FALSE if not - */ - private function checkAttributePrefix($property, array $prefixes = array()) - { - $prefix = strstr($property, ':', true); - - if (in_array($prefix, $prefixes)) { - return true; - } else { - return false; - } - } - - /** - * Converts a value to an HTTP-displayable string form - * - * @param mixed $x a value to convert - * @return string - */ - private function to_string($x) - { - if (is_bool($x) && $x) { - return 'True'; - } elseif (is_bool($x)) { - return 'False'; - } else { - return (string) $x; - } - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Collection.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Collection.php deleted file mode 100644 index e1bf80376e..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Collection.php +++ /dev/null @@ -1,320 +0,0 @@ - - * @author Jamie Hannaford - */ -class Collection extends Base -{ - - private $service; - private $itemclass; - private $itemlist = array(); - private $pointer = 0; - private $sortkey; - private $next_page_class; - private $next_page_callback; - private $next_page_url; - - /** - * A Collection is an array of objects - * - * Some assumptions: - * * The `Collection` class assumes that there exists on its service - * a factory method with the same name of the class. For example, if - * you create a Collection of class `Foobar`, it will attempt to call - * the method `parent::Foobar()` to create instances of that class. - * * It assumes that the factory method can take an array of values, and - * it passes that to the method. - * - * @param Service $service - the service associated with the collection - * @param string $itemclass - the Class of each item in the collection - * (assumed to be the name of the factory method) - * @param array $arr - the input array - */ - public function __construct($service, $itemclass, $array) - { - $this->service = $service; - - $this->getLogger()->info( - 'Collection:service={class}, class={itemClass}, array={array}', - array( - 'class' => get_class($service), - 'itemClass' => $itemclass, - 'array' => print_r($array, true) - ) - ); - - $this->next_page_class = $itemclass; - - if (false !== ($classNamePos = strrpos($itemclass, '\\'))) { - $this->itemclass = substr($itemclass, $classNamePos + 1); - } else { - $this->itemclass = $itemclass; - } - - if (!is_array($array)) { - throw new Exceptions\CollectionError( - Lang::translate('Cannot create a Collection without an array') - ); - } - - // save the array of items - $this->setItemList($array); - } - - /** - * Set the entire data array. - * - * @param array $array - */ - public function setItemList(array $array) - { - $this->itemlist = $array; - } - - /** - * Retrieve the entire data array. - * - * @return array - */ - public function getItemList() - { - return $this->itemlist; - } - - /** - * Returns the number of items in the collection - * - * For most services, this is the total number of items. If the Collection - * is paginated, however, this only returns the count of items in the - * current page of data. - * - * @return int - */ - public function count() - { - return count($this->itemlist); - } - - /** - * Pseudonym for count() - * - * @codeCoverageIgnore - */ - public function size() - { - return $this->count(); - } - - /** - * Retrieves the service associated with the Collection - * - * @return Service - */ - public function service() - { - return $this->service; - } - - /** - * Resets the pointer to the beginning, but does NOT return the first item - * - * @api - * @return void - */ - public function reset() - { - $this->pointer = 0; - } - - /** - * Resets the collection pointer back to the first item in the page - * and returns it - * - * This is useful if you're only interested in the first item in the page. - * - * @api - * @return Base the first item in the set - */ - public function first() - { - $this->reset(); - return $this->next(); - } - - /** - * Returns the next item in the page - * - * @api - * @return Base the next item or FALSE if at the end of the page - */ - public function next() - { - if ($this->pointer >= $this->count()) { - return false; - } - - $service = $this->service(); - - if (method_exists($service, $this->itemclass)) { - return $service->{$this->itemclass}($this->itemlist[$this->pointer++]); - } elseif (method_exists($service, 'resource')) { - return $service->resource($this->itemclass, $this->itemlist[$this->pointer++]); - } - // @codeCoverageIgnoreStart - return false; - // @codeCoverageIgnoreEnd - } - - /** - * sorts the collection on a specified key - * - * Note: only top-level keys can be used as the sort key. Note that this - * only sorts the data in the current page of the Collection (for - * multi-page data). - * - * @api - * @param string $keyname the name of the field to use as the sort key - * @return void - */ - public function sort($keyname = 'id') - { - $this->sortkey = $keyname; - usort($this->itemlist, array($this, 'sortCompare')); - } - - /** - * selects only specified items from the Collection - * - * This provides a simple form of filtering on Collections. For each item - * in the collection, it calls the callback function, passing it the item. - * If the callback returns `TRUE`, then the item is retained; if it returns - * `FALSE`, then the item is deleted from the collection. - * - * Note that this should not supersede server-side filtering; the - * `Collection::Select()` method requires that *all* of the data for the - * Collection be retrieved from the server before the filtering is - * performed; this can be very inefficient, especially for large data - * sets. This method is mostly useful on smaller-sized sets. - * - * Example: - * - * $services = $connection->ServiceList(); - * $services->Select(function($item){ return $item->region=='ORD';}); - * // now the $services Collection only has items from the ORD region - * - * - * `Select()` is *destructive*; that is, it actually removes entries from - * the collection. For example, if you use `Select()` to find items with - * the ID > 10, then use it again to find items that are <= 10, it will - * return an empty list. - * - * @api - * @param callable $testfunc a callback function that is passed each item - * in turn. Note that `Select()` performs an explicit test for - * `FALSE`, so functions like `strpos()` need to be cast into a - * boolean value (and not just return the integer). - * @returns void - * @throws DomainError if callback doesn't return a boolean value - */ - public function select($testfunc) - { - foreach ($this->getItemList() as $index => $item) { - $test = call_user_func($testfunc, $item); - if (!is_bool($test)) { - throw new Exceptions\DomainError( - Lang::translate('Callback function for Collection::Select() did not return boolean') - ); - } - if ($test === false) { - unset($this->itemlist[$index]); - } - } - } - - /** - * returns the Collection object for the next page of results, or - * FALSE if there are no more pages - * - * Generally, the structure for a multi-page collection will look like - * this: - * - * $coll = $obj->Collection(); - * do { - * while($item = $coll->Next()) { - * // do something with the item - * } - * } while ($coll = $coll->NextPage()); - * - * @api - * @return Collection if there are more pages of results, otherwise FALSE - */ - public function nextPage() - { - if (isset($this->next_page_url)) { - return call_user_func( - $this->next_page_callback, - $this->next_page_class, - $this->next_page_url - ); - } - // @codeCoverageIgnoreStart - return false; - // @codeCoverageIgnoreEnd - } - - /** - * for paginated collection, sets the callback function and URL for - * the next page - * - * The callback function should have the signature: - * - * function Whatever($class, $url, $parent) - * - * and the `$url` should be the URL of the next page of results - * - * @param callable $callback the name of the function (or array of - * object, function name) - * @param string $url the URL of the next page of results - * @return void - */ - public function setNextPageCallback($callback, $url) - { - $this->next_page_callback = $callback; - $this->next_page_url = $url; - } - - /** - * Compares two values of sort keys - */ - private function sortCompare($a, $b) - { - $key = $this->sortkey; - - // handle strings with strcmp() - if (is_string($a->$key)) { - return strcmp($a->$key, $b->$key); - } - - // handle others with logical comparisons - if ($a->$key == $b->$key) { - return 0; - } - - if ($a->$key < $b->$key) { - return -1; - } else { - return 1; - } - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncError.php deleted file mode 100644 index cbbacff38b..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncError.php +++ /dev/null @@ -1,5 +0,0 @@ - - */ - -namespace OpenCloud\Common\Exceptions; - -use Exception; - -class LoggingException extends Exception -{ -} \ No newline at end of file diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataCreateError.php deleted file mode 100644 index a119397392..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataCreateError.php +++ /dev/null @@ -1,5 +0,0 @@ - - * @version 2.0.0 - * @copyright Copyright 2012-2013 Rackspace US, Inc. - * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0 - */ - -/** - * Description of Role - * - * @link - * - * @codeCoverageIgnore - */ -class Role -{ -} \ No newline at end of file diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Tenant.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Tenant.php deleted file mode 100644 index 62783613c2..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Tenant.php +++ /dev/null @@ -1,22 +0,0 @@ - - * @version 2.0.0 - * @copyright Copyright 2012-2013 Rackspace US, Inc. - * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0 - */ - -/** - * Description of Tenant - * - * @link - * - * @codeCoverageIgnore - */ -class Tenant -{ - -} \ No newline at end of file diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/User.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/User.php deleted file mode 100644 index 9e3862d175..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/User.php +++ /dev/null @@ -1,73 +0,0 @@ - - * @author Jamie Hannaford - */ - -/** - * Represents a sub-user in Keystone. - * - * @link http://docs.rackspace.com/auth/api/v2.0/auth-client-devguide/content/User_Calls.html - * - * @codeCoverageIgnore - */ -class User extends PersistentObject -{ - - public static function factory($info) - { - $user = new self; - } - - /** - * Return detailed information about a specific user, by either user name or user ID. - * @param int|string $info - */ - public function get($info) - { - if (is_integer($info)) { - - } elseif (is_string($info)) { - - } else { - throw new Exception\IdentityException(sprintf( - 'A string-based username or an integer-based user ID is valid' - )); - } - } - - public function create() - { - - } - - public function update() - { - - } - - public function delete() - { - - } - - public function listAllCredentials() - { - - } - - public function getCredentials() - { - - } - - public function resetApiKey() - { - - } - -} \ No newline at end of file diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Lang.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Lang.php deleted file mode 100644 index 7bb1285973..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Lang.php +++ /dev/null @@ -1,21 +0,0 @@ -log(LogLevel::EMERGENCY, $message, $context); - } - - /** - * Action must be taken immediately. - * - * Example: Entire website down, database unavailable, etc. This should - * trigger the SMS alerts and wake you up. - * - * @param string $message - * @param array $context - * @return null - */ - public function alert($message, array $context = array()) - { - $this->log(LogLevel::ALERT, $message, $context); - } - - /** - * Critical conditions. - * - * Example: Application component unavailable, unexpected exception. - * - * @param string $message - * @param array $context - * @return null - */ - public function critical($message, array $context = array()) - { - $this->log(LogLevel::CRITICAL, $message, $context); - } - - /** - * Runtime errors that do not require immediate action but should typically - * be logged and monitored. - * - * @param string $message - * @param array $context - * @return null - */ - public function error($message, array $context = array()) - { - $this->log(LogLevel::ERROR, $message, $context); - } - - /** - * Exceptional occurrences that are not errors. - * - * Example: Use of deprecated APIs, poor use of an API, undesirable things - * that are not necessarily wrong. - * - * @param string $message - * @param array $context - * @return null - */ - public function warning($message, array $context = array()) - { - $this->log(LogLevel::WARNING, $message, $context); - } - - /** - * Normal but significant events. - * - * @param string $message - * @param array $context - * @return null - */ - public function notice($message, array $context = array()) - { - $this->log(LogLevel::NOTICE, $message, $context); - } - - /** - * Interesting events. - * - * Example: User logs in, SQL logs. - * - * @param string $message - * @param array $context - * @return null - */ - public function info($message, array $context = array()) - { - $this->log(LogLevel::INFO, $message, $context); - } - - /** - * Detailed debug information. - * - * @param string $message - * @param array $context - * @return null - */ - public function debug($message, array $context = array()) - { - $this->log(LogLevel::DEBUG, $message, $context); - } -} \ No newline at end of file diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LogLevel.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LogLevel.php deleted file mode 100644 index 64b0169b50..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LogLevel.php +++ /dev/null @@ -1,38 +0,0 @@ - - */ - -namespace OpenCloud\Common\Log; - -use OpenCloud\Common\Exceptions\LoggingException; - -/** - * Basic logger for OpenCloud which extends FIG's PSR-3 standard logger. - * - * @link https://github.com/php-fig/log - */ -class Logger extends AbstractLogger -{ - /** - * Is this debug class enabled or not? - * - * @var bool - */ - private $enabled = false; - - /** - * These are the levels which will always be outputted - regardless of - * user-imposed settings. - * - * @var array - */ - private $urgentLevels = array( - LogLevel::EMERGENCY, - LogLevel::ALERT, - LogLevel::CRITICAL - ); - - /** - * Logging options. - * - * @var array - */ - private $options = array( - 'outputToFile' => false, - 'logFile' => null, - 'dateFormat' => 'd/m/y H:I', - 'delimeter' => ' - ' - ); - - /** - * Determines whether a log level needs to be outputted. - * - * @param string $logLevel - * @return bool - */ - private function outputIsUrgent($logLevel) - { - return in_array($logLevel, $this->urgentLevels); - } - - /** - * Interpolates context values into the message placeholders. - * - * @param string $message - * @param array $context - * @return type - */ - private function interpolate($message, array $context = array()) - { - // build a replacement array with braces around the context keys - $replace = array(); - foreach ($context as $key => $val) { - $replace['{' . $key . '}'] = $val; - } - - // interpolate replacement values into the message and return - return strtr($message, $replace); - } - - /** - * Enable or disable the debug class. - * - * @param bool $enabled - * @return self - */ - public function setEnabled($enabled) - { - $this->enabled = $enabled; - return $this; - } - - /** - * Is the debug class enabled? - * - * @return bool - */ - public function getEnabled() - { - return $this->enabled; - } - - /** - * Set an array of options. - * - * @param array $options - */ - public function setOptions(array $options = array()) - { - foreach ($options as $key => $value) { - $this->setOption($key, $value); - } - } - - /** - * Get all options. - * - * @return array - */ - public function getOptions() - { - return $this->options; - } - - /** - * Set an individual option. - * - * @param string $key - * @param string $value - */ - public function setOption($key, $value) - { - if ($this->optionExists($key)) { - $this->options[$key] = $value; - } - } - - /** - * Get an individual option. - * - * @param string $key - * @return string|null - */ - public function getOption($key) - { - if ($this->optionExists($key)) { - return $this->options[$key]; - } - } - - /** - * Check whether an individual option exists. - * - * @param string $key - * @return bool - */ - private function optionExists($key) - { - return array_key_exists($key, $this->getOptions()); - } - - /** - * Outputs a log message if necessary. - * - * @param string $logLevel - * @param string $message - * @param string $context - */ - public function log($level, $message, array $context = array()) - { - if ($this->outputIsUrgent($level) - || $this->getEnabled() === true - || RAXSDK_DEBUG === true - ) { - $this->dispatch($message, $context); - } - } - - /** - * Used to format the line outputted in the log file. - * - * @param string $string - * @return string - */ - private function formatFileLine($string) - { - $format = $this->getOption('dateFormat') . $this->getOption('delimeter'); - return date($format) . $string; - } - - /** - * Dispatch a log output message. - * - * @param string $message - * @param array $context - * @throws LoggingException - */ - private function dispatch($message, $context) - { - $output = $this->interpolate($message, $context) . PHP_EOL; - - if ($this->getOption('outputToFile') === true) { - $file = $this->getOption('logFile'); - - if (!is_writable($file)) { - throw new LoggingException( - 'The log file either does not exist or is not writeable' - ); - } - - // Output to file - file_put_contents($file, $this->formatFileLine($output)); - } else { - - echo $output; - } - } - -} \ No newline at end of file diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LoggerInterface.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LoggerInterface.php deleted file mode 100644 index daef1b04da..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LoggerInterface.php +++ /dev/null @@ -1,134 +0,0 @@ - - */ - -namespace OpenCloud\Common; - -/** - * The Metadata class represents either Server or Image metadata - * - * @api - * @author Glen Campbell - */ -class Metadata extends Base -{ - - // array holding the names of keys that were set - private $_keylist = array(); - - /** - * This setter overrides the base one, since the metadata key can be - * anything - * - * @param string $key - * @param string $value - * @return void - */ - public function __set($key, $value) - { - // set the value and track the keys - if (!in_array($key, $this->_keylist)) { - $this->_keylist[] = $key; - } - - $this->$key = $value; - } - - /** - * Returns the list of keys defined - * - * @return array - */ - public function Keylist() - { - return $this->_keylist; - } - - /** - * Sets metadata values from an array, with optional prefix - * - * If $prefix is provided, then only array keys that match the prefix - * are set as metadata values, and $prefix is stripped from the key name. - * - * @param array $values an array of key/value pairs to set - * @param string $prefix if provided, a prefix that is used to identify - * metadata values. For example, you can set values from headers - * for a Container by using $prefix='X-Container-Meta-'. - * @return void - */ - public function setArray($values, $prefix = null) - { - if (empty($values)) { - return false; - } - - foreach ($values as $key => $value) { - if ($prefix) { - if (strpos($key, $prefix) === 0) { - $name = substr($key, strlen($prefix)); - $this->getLogger()->info( - Lang::translate('Setting [{name}] to [{value}]'), - array( - 'name' => $name, - 'value' => $value - ) - ); - $this->$name = $value; - } - } else { - $this->$key = $value; - } - } - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Nova.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Nova.php deleted file mode 100644 index fe4dcccc73..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Nova.php +++ /dev/null @@ -1,140 +0,0 @@ - - */ - -namespace OpenCloud\Common; - -use OpenCloud\OpenStack; -use OpenCloud\Common\Lang; -use OpenCloud\Compute\Flavor; - -/** - * Nova is an abstraction layer for the OpenStack compute service. - * - * Nova is used as a basis for several products, including Compute services - * as well as Rackspace's Cloud Databases. This class is, in essence, a vehicle - * for sharing common code between those other classes. - */ -abstract class Nova extends Service -{ - - private $_url; - - /** - * Called when creating a new Compute service object - * - * _NOTE_ that the order of parameters for this is *different* from the - * parent Service class. This is because the earlier parameters are the - * ones that most typically change, whereas the later ones are not - * modified as often. - * - * @param \OpenCloud\Identity $conn - a connection object - * @param string $serviceRegion - identifies the region of this Compute - * service - * @param string $urltype - identifies the URL type ("publicURL", - * "privateURL") - * @param string $serviceName - identifies the name of the service in the - * catalog - */ - public function __construct( - OpenStack $conn, - $serviceType, - $serviceName, - $serviceRegion, - $urltype - ) { - parent::__construct( - $conn, - $serviceType, - $serviceName, - $serviceRegion, - $urltype - ); - - $this->_url = Lang::noslash(parent::Url()); - - $this->getLogger()->info(Lang::translate('Initializing Nova...')); - } - - /** - * Returns a flavor from the service - * - * This is a factory method and should generally be called instead of - * creating a Flavor object directly. - * - * @api - * @param string $id - if supplied, the Flavor identified by this is - * retrieved - * @return Compute\Flavor object - */ - public function Flavor($id = null) - { - return new Flavor($this, $id); - } - - /** - * Returns a list of Flavor objects - * - * This is a factory method and should generally be called instead of - * creating a FlavorList object directly. - * - * @api - * @param boolean $details - if TRUE (the default), returns full details. - * Set to FALSE to retrieve minimal details and possibly improve - * performance. - * @param array $filter - optional key/value pairs for creating query - * strings - * @return Collection (or FALSE on an error) - */ - public function FlavorList($details = true, array $filter = array()) - { - if ($details) { - $url = $this->Url(Flavor::ResourceName().'/detail', $filter); - } else { - $url = $this->Url(Flavor::ResourceName(), $filter); - } - return $this->Collection('\OpenCloud\Compute\Flavor', $url); - } - - /** - * Gets a request from an HTTP source and ensures that the - * content type is always "application/json" - * - * This is a simple subclass of the parent::Request() method that ensures - * that all Compute requests use application/json as the Content-Type: - * - * @param string $url - the URL of the request - * @param string $method - the HTTP method ("GET" by default) - * @param array $headers - an associative array of headers to pass to - * the request - * @param string $body - optional body for POST or PUT requests - * @return \Rackspace\HttpResult object - */ - public function Request($url, $method = 'GET', array $headers = array(), $body = null) - { - $headers['Content-Type'] = RAXSDK_CONTENT_TYPE_JSON; - return parent::Request($url, $method, $headers, $body); - } - - /** - * Loads the available namespaces from the /extensions resource - */ - protected function load_namespaces() - { - $ext = $this->Extensions(); - foreach($ext as $obj) { - $this->_namespaces[] = $obj->alias; - } - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/PersistentObject.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/PersistentObject.php deleted file mode 100644 index 0257526d70..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/PersistentObject.php +++ /dev/null @@ -1,939 +0,0 @@ - - * @author Jamie Hannaford - */ - -namespace OpenCloud\Common; - -/** - * Represents an object that can be retrieved, created, updated and deleted. - * - * This class abstracts much of the common functionality between: - * - * * Nova servers; - * * Swift containers and objects; - * * DBAAS instances; - * * Cinder volumes; - * * and various other objects that: - * * have a URL; - * * can be created, updated, deleted, or retrieved; - * * use a standard JSON format with a top-level element followed by - * a child object with attributes. - * - * In general, you can create a persistent object class by subclassing this - * class and defining some protected, static variables: - * - * * $url_resource - the sub-resource value in the URL of the parent. For - * example, if the parent URL is `http://something/parent`, then setting this - * value to "another" would result in a URL for the persistent object of - * `http://something/parent/another`. - * - * * $json_name - the top-level JSON object name. For example, if the - * persistent object is represented by `{"foo": {"attr":value, ...}}`, then - * set $json_name to "foo". - * - * * $json_collection_name - optional; this value is the name of a collection - * of the persistent objects. If not provided, it defaults to `json_name` - * with an appended "s" (e.g., if `json_name` is "foo", then - * `json_collection_name` would be "foos"). Set this value if the collection - * name doesn't follow this pattern. - * - * * $json_collection_element - the common pattern for a collection is: - * `{"collection": [{"attr":"value",...}, {"attr":"value",...}, ...]}` - * That is, each element of the array is a \stdClass object containing the - * object's attributes. In rare instances, the objects in the array - * are named, and `json_collection_element` contains the name of the - * collection objects. For example, in this JSON response: - * `{"allowedDomain":[{"allowedDomain":{"name":"foo"}}]}`, - * `json_collection_element` would be set to "allowedDomain". - * - * The PersistentObject class supports the standard CRUD methods; if these are - * not needed (i.e. not supported by the service), the subclass should redefine - * these to call the `noCreate`, `noUpdate`, or `noDelete` methods, which will - * trigger an appropriate exception. For example, if an object cannot be created: - * - * function create($params = array()) - * { - * $this->noCreate(); - * } - */ -abstract class PersistentObject extends Base -{ - - private $service; - - private $parent; - - protected $id; - - /** - * Retrieves the instance from persistent storage - * - * @param mixed $service The service object for this resource - * @param mixed $info The ID or array/object of data - */ - public function __construct($service = null, $info = null) - { - if ($service instanceof Service) { - $this->setService($service); - } - - if (property_exists($this, 'metadata')) { - $this->metadata = new Metadata; - } - - $this->populate($info); - } - - /** - * Validates properties that have a namespace: prefix - * - * If the property prefix: appears in the list of supported extension - * namespaces, then the property is applied to the object. Otherwise, - * an exception is thrown. - * - * @param string $name the name of the property - * @param mixed $value the property's value - * @return void - * @throws AttributeError - */ - public function __set($name, $value) - { - $this->setProperty($name, $value, $this->getService()->namespaces()); - } - - /** - * Sets the service associated with this resource object. - * - * @param \OpenCloud\Common\Service $service - */ - public function setService(Service $service) - { - $this->service = $service; - return $this; - } - - /** - * Returns the service object for this resource; required for making - * requests, etc. because it has direct access to the Connection. - * - * @return \OpenCloud\Common\Service - */ - public function getService() - { - if (null === $this->service) { - throw new Exceptions\ServiceValueError( - 'No service defined' - ); - } - return $this->service; - } - - /** - * Legacy shortcut to getService - * - * @return \OpenCloud\Common\Service - */ - public function service() - { - return $this->getService(); - } - - /** - * Set the parent object for this resource. - * - * @param \OpenCloud\Common\PersistentObject $parent - */ - public function setParent(PersistentObject $parent) - { - $this->parent = $parent; - return $this; - } - - /** - * Returns the parent. - * - * @return \OpenCloud\Common\PersistentObject - */ - public function getParent() - { - if (null === $this->parent) { - $this->parent = $this->getService(); - } - return $this->parent; - } - - /** - * Legacy shortcut to getParent - * - * @return \OpenCloud\Common\PersistentObject - */ - public function parent() - { - return $this->getParent(); - } - - - - - /** - * API OPERATIONS (CRUD & CUSTOM) - */ - - /** - * Creates a new object - * - * @api - * @param array $params array of values to set when creating the object - * @return HttpResponse - * @throws VolumeCreateError if HTTP status is not Success - */ - public function create($params = array()) - { - // set parameters - if (!empty($params)) { - $this->populate($params, false); - } - - // debug - $this->getLogger()->info('{class}::Create({name})', array( - 'class' => get_class($this), - 'name' => $this->Name() - )); - - // construct the JSON - $object = $this->createJson(); - $json = json_encode($object); - $this->checkJsonError(); - - $this->getLogger()->info('{class}::Create JSON [{json}]', array( - 'class' => get_class($this), - 'json' => $json - )); - - // send the request - $response = $this->getService()->request( - $this->createUrl(), - 'POST', - array('Content-Type' => 'application/json'), - $json - ); - - // check the return code - // @codeCoverageIgnoreStart - if ($response->httpStatus() > 204) { - throw new Exceptions\CreateError(sprintf( - Lang::translate('Error creating [%s] [%s], status [%d] response [%s]'), - get_class($this), - $this->Name(), - $response->HttpStatus(), - $response->HttpBody() - )); - } - - if ($response->HttpStatus() == "201" && ($location = $response->Header('Location'))) { - // follow Location header - $this->refresh(null, $location); - } else { - // set values from response - $object = json_decode($response->httpBody()); - - if (!$this->checkJsonError()) { - $top = $this->jsonName(); - if (isset($object->$top)) { - $this->populate($object->$top); - } - } - } - // @codeCoverageIgnoreEnd - - return $response; - } - - /** - * Updates an existing object - * - * @api - * @param array $params array of values to set when updating the object - * @return HttpResponse - * @throws VolumeCreateError if HTTP status is not Success - */ - public function update($params = array()) - { - // set parameters - if (!empty($params)) { - $this->populate($params); - } - - // debug - $this->getLogger()->info('{class}::Update({name})', array( - 'class' => get_class($this), - 'name' => $this->Name() - )); - - // construct the JSON - $obj = $this->updateJson($params); - $json = json_encode($obj); - - $this->checkJsonError(); - - $this->getLogger()->info('{class}::Update JSON [{json}]', array( - 'class' => get_class($this), - 'json' => $json - )); - - // send the request - $response = $this->getService()->Request( - $this->url(), - 'PUT', - array(), - $json - ); - - // check the return code - // @codeCoverageIgnoreStart - if ($response->HttpStatus() > 204) { - throw new Exceptions\UpdateError(sprintf( - Lang::translate('Error updating [%s] with [%s], status [%d] response [%s]'), - get_class($this), - $json, - $response->HttpStatus(), - $response->HttpBody() - )); - } - // @codeCoverageIgnoreEnd - - return $response; - } - - /** - * Deletes an object - * - * @api - * @return HttpResponse - * @throws DeleteError if HTTP status is not Success - */ - public function delete() - { - $this->getLogger()->info('{class}::Delete()', array('class' => get_class($this))); - - // send the request - $response = $this->getService()->request($this->url(), 'DELETE'); - - // check the return code - // @codeCoverageIgnoreStart - if ($response->HttpStatus() > 204) { - throw new Exceptions\DeleteError(sprintf( - Lang::translate('Error deleting [%s] [%s], status [%d] response [%s]'), - get_class(), - $this->Name(), - $response->HttpStatus(), - $response->HttpBody() - )); - } - // @codeCoverageIgnoreEnd - - return $response; - } - - /** - * Returns an object for the Create() method JSON - * Must be overridden in a child class. - * - * @throws CreateError if not overridden - */ - protected function createJson() - { - throw new Exceptions\CreateError(sprintf( - Lang::translate('[%s] CreateJson() must be overridden'), - get_class($this) - )); - } - - /** - * Returns an object for the Update() method JSON - * Must be overridden in a child class. - * - * @throws UpdateError if not overridden - */ - protected function updateJson($params = array()) - { - throw new Exceptions\UpdateError(sprintf( - Lang::translate('[%s] UpdateJson() must be overridden'), - get_class($this) - )); - } - - /** - * throws a CreateError for subclasses that don't support Create - * - * @throws CreateError - */ - protected function noCreate() - { - throw new Exceptions\CreateError(sprintf( - Lang::translate('[%s] does not support Create()'), - get_class() - )); - } - - /** - * throws a DeleteError for subclasses that don't support Delete - * - * @throws DeleteError - */ - protected function noDelete() - { - throw new Exceptions\DeleteError(sprintf( - Lang::translate('[%s] does not support Delete()'), - get_class() - )); - } - - /** - * throws a UpdateError for subclasses that don't support Update - * - * @throws UpdateError - */ - protected function noUpdate() - { - throw new Exceptions\UpdateError(sprintf( - Lang::translate('[%s] does not support Update()'), - get_class() - )); - } - - /** - * Returns the default URL of the object - * - * This may have to be overridden in subclasses. - * - * @param string $subresource optional sub-resource string - * @param array $qstr optional k/v pairs for query strings - * @return string - * @throws UrlError if URL is not defined - */ - public function url($subresource = null, $queryString = array()) - { - // find the primary key attribute name - $primaryKey = $this->primaryKeyField(); - - // first, see if we have a [self] link - $url = $this->findLink('self'); - - /** - * Next, check to see if we have an ID - * Note that we use Parent() instead of Service(), since the parent - * object might not be a service. - */ - if (!$url && $this->$primaryKey) { - $url = Lang::noslash($this->getParent()->url($this->resourceName())) . '/' . $this->$primaryKey; - } - - // add the subresource - if ($url) { - $url .= $subresource ? "/$subresource" : ''; - if (count($queryString)) { - $url .= '?' . $this->makeQueryString($queryString); - } - return $url; - } - - // otherwise, we don't have a URL yet - throw new Exceptions\UrlError(sprintf( - Lang::translate('%s does not have a URL yet'), - get_class($this) - )); - } - - /** - * Waits for the server/instance status to change - * - * This function repeatedly polls the system for a change in server - * status. Once the status reaches the `$terminal` value (or 'ERROR'), - * then the function returns. - * - * The polling interval is set by the constant RAXSDK_POLL_INTERVAL. - * - * The function will automatically terminate after RAXSDK_SERVER_MAXTIMEOUT - * seconds elapse. - * - * @api - * @param string $terminal the terminal state to wait for - * @param integer $timeout the max time (in seconds) to wait - * @param callable $callback a callback function that is invoked with - * each repetition of the polling sequence. This can be used, for - * example, to update a status display or to permit other operations - * to continue - * @return void - */ - public function waitFor( - $terminal = 'ACTIVE', - $timeout = RAXSDK_SERVER_MAXTIMEOUT, - $callback = NULL, - $sleep = RAXSDK_POLL_INTERVAL - ) { - // find the primary key field - $primaryKey = $this->PrimaryKeyField(); - - // save stats - $startTime = time(); - - $states = array('ERROR', $terminal); - - while (true) { - - $this->refresh($this->$primaryKey); - - if ($callback) { - call_user_func($callback, $this); - } - - if (in_array($this->status(), $states) || (time() - $startTime) > $timeout) { - return; - } - // @codeCoverageIgnoreStart - sleep($sleep); - } - } - // @codeCoverageIgnoreEnd - - /** - * Refreshes the object from the origin (useful when the server is - * changing states) - * - * @return void - * @throws IdRequiredError - */ - public function refresh($id = null, $url = null) - { - $primaryKey = $this->PrimaryKeyField(); - - if (!$url) { - if ($id === null) { - $id = $this->$primaryKey; - } - - if (!$id) { - throw new Exceptions\IdRequiredError(sprintf( - Lang::translate('%s has no ID; cannot be refreshed'), - get_class()) - ); - } - - // retrieve it - $this->getLogger()->info(Lang::translate('{class} id [{id}]'), array( - 'class' => get_class($this), - 'id' => $id - )); - - $this->$primaryKey = $id; - $url = $this->url(); - } - - // reset status, if available - if (property_exists($this, 'status')) { - $this->status = null; - } - - // perform a GET on the URL - $response = $this->getService()->Request($url); - - // check status codes - // @codeCoverageIgnoreStart - if ($response->HttpStatus() == 404) { - throw new Exceptions\InstanceNotFound( - sprintf(Lang::translate('%s [%s] not found [%s]'), - get_class($this), - $this->$primaryKey, - $url - )); - } - - if ($response->HttpStatus() >= 300) { - throw new Exceptions\UnknownError( - sprintf(Lang::translate('Unexpected %s error [%d] [%s]'), - get_class($this), - $response->HttpStatus(), - $response->HttpBody() - )); - } - - // check for empty response - if (!$response->HttpBody()) { - throw new Exceptions\EmptyResponseError( - sprintf(Lang::translate('%s::Refresh() unexpected empty response, URL [%s]'), - get_class($this), - $url - )); - } - - // we're ok, reload the response - if ($json = $response->HttpBody()) { - - $this->getLogger()->info('refresh() JSON [{json}]', array('json' => $json)); - - $response = json_decode($json); - - if ($this->CheckJsonError()) { - throw new Exceptions\ServerJsonError(sprintf( - Lang::translate('JSON parse error on %s refresh'), - get_class($this) - )); - } - - $top = $this->JsonName(); - - if ($top && isset($response->$top)) { - $content = $response->$top; - } else { - $content = $response; - } - - $this->populate($content); - - } - // @codeCoverageIgnoreEnd - } - - - /** - * OBJECT INFORMATION - */ - - /** - * Returns the displayable name of the object - * - * Can be overridden by child objects; *must* be overridden by child - * objects if the object does not have a `name` attribute defined. - * - * @api - * @return string - * @throws NameError if attribute 'name' is not defined - */ - public function name() - { - if (property_exists($this, 'name')) { - return $this->name; - } else { - throw new Exceptions\NameError(sprintf( - Lang::translate('Name attribute does not exist for [%s]'), - get_class($this) - )); - } - } - - /** - * Sends the json string to the /action resource - * - * This is used for many purposes, such as rebooting the server, - * setting the root password, creating images, etc. - * Since it can only be used on a live server, it checks for a valid ID. - * - * @param $object - this will be encoded as json, and we handle all the JSON - * error-checking in one place - * @throws ServerIdError if server ID is not defined - * @throws ServerActionError on other errors - * @returns boolean; TRUE if successful, FALSE otherwise - */ - protected function action($object) - { - $primaryKey = $this->primaryKeyField(); - - if (!$this->$primaryKey) { - throw new Exceptions\IdRequiredError(sprintf( - Lang::translate('%s is not defined'), - get_class($this) - )); - } - - if (!is_object($object)) { - throw new Exceptions\ServerActionError(sprintf( - Lang::translate('%s::Action() requires an object as its parameter'), - get_class($this) - )); - } - - // convert the object to json - $json = json_encode($object); - $this->getLogger()->info('JSON [{string}]', array('json' => $json)); - - $this->checkJsonError(); - - // debug - save the request - $this->getLogger()->info(Lang::translate('{class}::action [{json}]'), array( - 'class' => get_class($this), - 'json' => $json - )); - - // get the URL for the POST message - $url = $this->url('action'); - - // POST the message - $response = $this->getService()->request($url, 'POST', array(), $json); - - // @codeCoverageIgnoreStart - if (!is_object($response)) { - throw new Exceptions\HttpError(sprintf( - Lang::translate('Invalid response for %s::Action() request'), - get_class($this) - )); - } - - // check for errors - if ($response->HttpStatus() >= 300) { - throw new Exceptions\ServerActionError(sprintf( - Lang::translate('%s::Action() [%s] failed; response [%s]'), - get_class($this), - $url, - $response->HttpBody() - )); - } - // @codeCoverageIgnoreStart - - return $response; - } - - /** - * Execute a custom resource request. - * - * @param string $path - * @param string $method - * @param string|array|object $body - * @return boolean - * @throws Exceptions\InvalidArgumentError - * @throws Exceptions\HttpError - * @throws Exceptions\ServerActionError - */ - public function customAction($url, $method = 'GET', $body = null) - { - if (is_string($body) && (json_decode($body) === null)) { - throw new Exceptions\InvalidArgumentError( - 'Please provide either a well-formed JSON string, or an object ' - . 'for JSON serialization' - ); - } else { - $body = json_encode($body); - } - - // POST the message - $response = $this->service()->request($url, $method, array(), $body); - - if (!is_object($response)) { - throw new Exceptions\HttpError(sprintf( - Lang::translate('Invalid response for %s::customAction() request'), - get_class($this) - )); - } - - // check for errors - // @codeCoverageIgnoreStart - if ($response->HttpStatus() >= 300) { - throw new Exceptions\ServerActionError(sprintf( - Lang::translate('%s::customAction() [%s] failed; response [%s]'), - get_class($this), - $url, - $response->HttpBody() - )); - } - // @codeCoverageIgnoreEnd - - $object = json_decode($response->httpBody()); - - $this->checkJsonError(); - - return $object; - } - - /** - * returns the object's status or `N/A` if not available - * - * @api - * @return string - */ - public function status() - { - return (isset($this->status)) ? $this->status : 'N/A'; - } - - /** - * returns the object's identifier - * - * Can be overridden by a child class if the identifier is not in the - * `$id` property. Use of this function permits the `$id` attribute to - * be protected or private to prevent unauthorized overwriting for - * security. - * - * @api - * @return string - */ - public function id() - { - return $this->id; - } - - /** - * checks for `$alias` in extensions and throws an error if not present - * - * @throws UnsupportedExtensionError - */ - public function checkExtension($alias) - { - if (!in_array($alias, $this->getService()->namespaces())) { - throw new Exceptions\UnsupportedExtensionError(sprintf( - Lang::translate('Extension [%s] is not installed'), - $alias - )); - } - - return true; - } - - /** - * returns the region associated with the object - * - * navigates to the parent service to determine the region. - * - * @api - */ - public function region() - { - return $this->getService()->Region(); - } - - /** - * Since each server can have multiple links, this returns the desired one - * - * @param string $type - 'self' is most common; use 'bookmark' for - * the version-independent one - * @return string the URL from the links block - */ - public function findLink($type = 'self') - { - if (empty($this->links)) { - return false; - } - - foreach ($this->links as $link) { - if ($link->rel == $type) { - return $link->href; - } - } - - return false; - } - - /** - * returns the URL used for Create - * - * @return string - */ - protected function createUrl() - { - return $this->getParent()->Url($this->ResourceName()); - } - - /** - * Returns the primary key field for the object - * - * The primary key is usually 'id', but this function is provided so that - * (in rare cases where it is not 'id'), it can be overridden. - * - * @return string - */ - protected function primaryKeyField() - { - return 'id'; - } - - /** - * Returns the top-level document identifier for the returned response - * JSON document; must be overridden in child classes - * - * For example, a server document is (JSON) `{"server": ...}` and an - * Instance document is `{"instance": ...}` - this function must return - * the top level document name (either "server" or "instance", in - * these examples). - * - * @throws DocumentError if not overridden - */ - public static function jsonName() - { - if (isset(static::$json_name)) { - return static::$json_name; - } - - throw new Exceptions\DocumentError(sprintf( - Lang::translate('No JSON object defined for class [%s] in JsonName()'), - get_class() - )); - } - - /** - * returns the collection JSON element name - * - * When an object is returned in a collection, it usually has a top-level - * object that is an array holding child objects of the object types. - * This static function returns the name of the top-level element. Usually, - * that top-level element is simply the JSON name of the resource.'s'; - * however, it can be overridden by specifying the $json_collection_name - * attribute. - * - * @return string - */ - public static function jsonCollectionName() - { - if (isset(static::$json_collection_name)) { - return static::$json_collection_name; - } else { - return static::$json_name . 's'; - } - } - - /** - * returns the JSON name for each element in a collection - * - * Usually, elements in a collection are anonymous; this function, however, - * provides for an element level name: - * - * `{ "collection" : [ { "element" : ... } ] }` - * - * @return string - */ - public static function jsonCollectionElement() - { - if (isset(static::$json_collection_element)) { - return static::$json_collection_element; - } - } - - /** - * Returns the resource name for the URL of the object; must be overridden - * in child classes - * - * For example, a server is `/servers/`, a database instance is - * `/instances/`. Must be overridden in child classes. - * - * @throws UrlError - */ - public static function resourceName() - { - if (isset(static::$url_resource)) { - return static::$url_resource; - } - - throw new Exceptions\UrlError(sprintf( - Lang::translate('No URL resource defined for class [%s] in ResourceName()'), - get_class() - )); - } - -} \ No newline at end of file diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Curl.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Curl.php deleted file mode 100644 index bb829afc5f..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Curl.php +++ /dev/null @@ -1,308 +0,0 @@ - - */ -class Curl extends Base implements HttpRequestInterface -{ - - private $url; - private $method; - private $handle; - private $retries = 0; - private $headers = array(); - private $returnheaders = array(); - - /** - * Initializes the CURL handle and HTTP method - * - * The constructor also sets a number of default values for options. - * - * @param string $url the URL to connect to - * @param string $method the HTTP method (default "GET") - * @param array $options optional hashed array of options => value pairs - */ - public function __construct($url, $method = 'GET', array $options = array()) - { - $this->url = $url; - $this->method = $method; - $this->handle = curl_init($url); - - // set our options - $this->setOption(CURLOPT_CUSTOMREQUEST, $method); - - foreach($options as $opt => $value) { - $this->getLogger()->info(Lang::translate('Setting option {key}={val}'), array( - 'key' => $opt, - 'val' => $value - )); - $this->setOption($opt, $value); - } - - // @codeCoverageIgnoreStart - if (RAXSDK_SSL_VERIFYHOST != 2) { - $this->getLogger()->warning("WARNING: RAXSDK_SSL_VERIFYHOST has reduced security, value [{value}]", array( - 'value' => RAXSDK_SSL_VERIFYHOST - )); - } - - if (RAXSDK_SSL_VERIFYPEER !== true) { - $this->getLogger()->warning("WARNING: RAXSDK_SSL_VERIFYPEER has reduced security"); - } - // @codeCoverageIgnoreEnd - - $this->setOption(CURLOPT_SSL_VERIFYHOST, RAXSDK_SSL_VERIFYHOST); - $this->setOption(CURLOPT_SSL_VERIFYPEER, RAXSDK_SSL_VERIFYPEER); - - if (defined('RAXSDK_CACERTPEM') && file_exists(RAXSDK_CACERTPEM)) { - $this->setOption(CURLOPT_CAINFO, RAXSDK_CACERTPEM); - } - - // curl code [18] - // message [transfer closed with x bytes remaining to read] - if ($method === 'HEAD') { - $this->setOption(CURLOPT_NOBODY, true); - } - - // follow redirects - $this->setOption(CURLOPT_FOLLOWLOCATION, true); - - // don't return the headers in the request - $this->setOption(CURLOPT_HEADER, false); - - // retrieve headers via callback - $this->setOption(CURLOPT_HEADERFUNCTION, array($this, '_get_header_cb')); - - // return the entire request on curl_exec() - $this->setOption(CURLOPT_RETURNTRANSFER, true); - - // set default timeouts - $this->setConnectTimeout(RAXSDK_CONNECTTIMEOUT); - $this->setHttpTimeout(RAXSDK_TIMEOUT); - } - - /** - * Sets a CURL option - * - * @param const $name - a CURL named constant; e.g. CURLOPT_TIMEOUT - * @param mixed $value - the value for the option - */ - public function setOption($name, $value) - { - return curl_setopt($this->handle, $name, $value); - } - - /** - * Explicit method for setting the connect timeout - * - * The connect timeout is the time it takes for the initial connection - * request to be established. It is different than the HTTP timeout, which - * is the time for the entire request to be serviced. - * - * @param integer $value The connection timeout in seconds. - * Use 0 to wait indefinitely (NOT recommended) - */ - public function setConnectTimeout($value) - { - $this->setOption(CURLOPT_CONNECTTIMEOUT, $value); - } - - /** - * Explicit method for setting the HTTP timeout - * - * The HTTP timeout is the time it takes for the HTTP request to be - * serviced. This value is usually larger than the connect timeout - * value. - * - * @param integer $value - the number of seconds to wait before timing out - * the HTTP request. - */ - public function setHttpTimeout($value) - { - $this->setOption(CURLOPT_TIMEOUT, $value); - } - - /** - * Sets the number of retries - * - * If you set this to a non-zero value, then it will repeat the request - * up to that number. - */ - public function setRetries($value) - { - $this->retries = $value; - } - - /** - * Simplified method for setting lots of headers at once - * - * This method takes an associative array of header/value pairs and calls - * the setheader() method on each of them. - * - * @param array $arr an associative array of headers - */ - public function setheaders($array) - { - if (!is_array($array)) { - throw new HttpError(Lang::translate( - 'Value passed to CurlRequest::setheaders() must be array' - )); - } - - foreach ($array as $name => $value) { - $this->setHeader($name, $value); - } - } - - /** - * Sets a single header - * - * For example, to set the content type to JSON: - * `$request->SetHeader('Content-Type','application/json');` - * - * @param string $name The name of the header - * @param mixed $value The value of the header - */ - public function setHeader($name, $value) - { - $this->headers[$name] = $value; - } - - /** - * Executes the current request - * - * This method actually performs the request using the values set - * previously. It throws a OpenCloud\HttpError exception on - * any CURL error. - * - * @return OpenCloud\HttpResponse - * @throws OpenCloud\HttpError - * - * @codeCoverageIgnore - */ - public function execute() - { - // set all the headers - $headarr = array(); - - foreach ($this->headers as $name => $value) { - $headarr[] = $name.': '.$value; - } - - $this->setOption(CURLOPT_HTTPHEADER, $headarr); - - // set up to retry if necessary - $try_counter = 0; - - do { - $data = curl_exec($this->handle); - if (curl_errno($this->handle) && ($try_counter<$this->retries)) { - $this->getLogger()->info(Lang::translate('Curl error [%d]; retrying [%s]'), array( - 'error' => curl_errno($this->handle), - 'url' => $this->url - )); - } - - } while((++$try_counter <= $this->retries) && (curl_errno($this->handle) != 0)); - - // log retries error - if ($this->retries && curl_errno($this->handle)) { - throw new HttpRetryError(sprintf( - Lang::translate('No more retries available, last error [%d]'), - curl_errno($this->handle) - )); - } - - // check for CURL errors - switch(curl_errno($this->handle)) { - case 0: - // everything's ok - break; - case 3: - throw new HttpUrlError(sprintf(Lang::translate('Malformed URL [%s]'), $this->url)); - break; - case 28: - // timeout - throw new HttpTimeoutError(Lang::translate('Operation timed out; check RAXSDK_TIMEOUT value')); - break; - default: - throw new HttpError(sprintf( - Lang::translate('HTTP error on [%s], curl code [%d] message [%s]'), - $this->url, - curl_errno($this->handle), - curl_error($this->handle) - )); - } - - // otherwise, return the HttpResponse - return new Response\Http($this, $data); - } - - /** - * returns an array of information about the request - */ - public function info() - { - return curl_getinfo($this->handle); - } - - /** - * returns the most recent CURL error number - */ - public function errno() - { - return curl_errno($this->handle); - } - - /** - * returns the most recent CURL error string - */ - public function error() - { - return curl_error($this->handle); - } - - /** - * Closes the HTTP request - */ - public function close() - { - return curl_close($this->handle); - } - - /** - * Returns the headers as an array - */ - public function returnHeaders() - { - return $this->returnheaders; - } - - /** - * This is a callback method used to handle the returned HTTP headers - * - * @param mixed $ch a CURL handle - * @param string $header the header string in its entirety - */ - public function _get_header_cb($ch, $header) - { - $this->returnheaders[] = $header; - return strlen($header); - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/HttpRequestInterface.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/HttpRequestInterface.php deleted file mode 100644 index cbe3b5412a..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/HttpRequestInterface.php +++ /dev/null @@ -1,23 +0,0 @@ - $value) { - $this->$name = $value; - } - } - - public function httpStatus() - { - return $this->status; - } - -} \ No newline at end of file diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Http.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Http.php deleted file mode 100644 index a7cb9e9634..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Http.php +++ /dev/null @@ -1,140 +0,0 @@ - - */ - -class Http extends Base -{ - - private $errno; - private $error; - private $info = array(); - protected $body; - protected $headers = array(); - - /** - * The constructor parses everything necessary - */ - public function __construct($request, $data) - { - // save the raw data (who knows? we might need it) - $this->setBody($data); - - // and split each line into name: value pairs - foreach($request->returnHeaders() as $line) { - if (preg_match('/^([^:]+):\s+(.+?)\s*$/', $line, $matches)) { - $this->headers[$matches[1]] = $matches[2]; - } else { - $this->headers[$line] = trim($line); - } - } - - // @codeCoverageIgnoreStart - if (isset($this->headers['Cache-Control'])) { - $this->getLogger()->info('Cache-Control: {header}', array( - 'headers' => $this->headers['Cache-Control'] - )); - } - if (isset($this->headers['Expires'])) { - $this->getLogger()->info('Expires: {header}', array( - 'headers' => $this->headers['Expires'] - )); - } - // @codeCoverageIgnoreEnd - - // set some other data - $this->info = $request->info(); - $this->errno = $request->errno(); - $this->error = $request->error(); - } - - /** - * Returns the full body of the request - * - * @return string - */ - public function httpBody() - { - return $this->body; - } - - /** - * Sets the body. - * - * @param string $body - */ - public function setBody($body) - { - $this->body = $body; - } - - /** - * Returns an array of headers - * - * @return associative array('header'=>value) - */ - public function headers() - { - return $this->headers; - } - - /** - * Returns a single header - * - * @return string with the value of the requested header, or NULL - */ - public function header($name) - { - return isset($this->headers[$name]) ? $this->headers[$name] : null; - } - - /** - * Returns an array of information - * - * @return array - */ - public function info() - { - return $this->info; - } - - /** - * Returns the most recent error number - * - * @return integer - */ - public function errno() - { - return $this->errno; - } - - /** - * Returns the most recent error message - * - * @return string - */ - public function error() - { - return $this->error; - } - - /** - * Returns the HTTP status code - * - * @return integer - */ - public function httpStatus() - { - return $this->info['http_code']; - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Service.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Service.php deleted file mode 100644 index 5b3aa729a9..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Service.php +++ /dev/null @@ -1,489 +0,0 @@ - - */ - -namespace OpenCloud\Common; - -use OpenCloud\Common\Base; -use OpenCloud\Common\Lang; -use OpenCloud\OpenStack; -use OpenCloud\Common\Exceptions; - -/** - * This class defines a cloud service; a relationship between a specific OpenStack - * and a provided service, represented by a URL in the service catalog. - * - * Because Service is an abstract class, it cannot be called directly. Provider - * services such as Rackspace Cloud Servers or OpenStack Swift are each - * subclassed from Service. - * - * @author Glen Campbell - */ - -abstract class Service extends Base -{ - - protected $conn; - private $service_type; - private $service_name; - private $service_region; - private $service_url; - - protected $_namespaces = array(); - - /** - * Creates a service on the specified connection - * - * Usage: `$x = new Service($conn, $type, $name, $region, $urltype);` - * The service's URL is defined in the OpenStack's serviceCatalog; it - * uses the $type, $name, $region, and $urltype to find the proper URL - * and set it. If it cannot find a URL in the service catalog that matches - * the criteria, then an exception is thrown. - * - * @param OpenStack $conn - a Connection object - * @param string $type - the service type (e.g., "compute") - * @param string $name - the service name (e.g., "cloudServersOpenStack") - * @param string $region - the region (e.g., "ORD") - * @param string $urltype - the specified URL from the catalog - * (e.g., "publicURL") - */ - public function __construct( - OpenStack $conn, - $type, - $name, - $region, - $urltype = RAXSDK_URL_PUBLIC, - $customServiceUrl = null - ) { - $this->setConnection($conn); - $this->service_type = $type; - $this->service_name = $name; - $this->service_region = $region; - $this->service_url = $customServiceUrl ?: $this->getEndpoint($type, $name, $region, $urltype); - } - - /** - * Set this service's connection. - * - * @param type $connection - */ - public function setConnection($connection) - { - $this->conn = $connection; - } - - /** - * Get this service's connection. - * - * @return type - */ - public function getConnection() - { - return $this->conn; - } - - /** - * Returns the URL for the Service - * - * @param string $resource optional sub-resource - * @param array $query optional k/v pairs for query strings - * @return string - */ - public function url($resource = '', array $param = array()) - { - $baseurl = $this->service_url; - - // use strlen instead of boolean test because '0' is a valid name - if (strlen($resource) > 0) { - $baseurl = Lang::noslash($baseurl).'/'.$resource; - } - - if (!empty($param)) { - $baseurl .= '?'.$this->MakeQueryString($param); - } - - return $baseurl; - } - - /** - * Returns the /extensions for the service - * - * @api - * @return array of objects - */ - public function extensions() - { - $ext = $this->getMetaUrl('extensions'); - return (is_object($ext) && isset($ext->extensions)) ? $ext->extensions : array(); - } - - /** - * Returns the /limits for the service - * - * @api - * @return array of limits - */ - public function limits() - { - $limits = $this->getMetaUrl('limits'); - return (is_object($limits)) ? $limits->limits : array(); - } - - /** - * Performs an authenticated request - * - * This method handles the addition of authentication headers to each - * request. It always adds the X-Auth-Token: header and will add the - * X-Auth-Project-Id: header if there is a tenant defined on the - * connection. - * - * @param string $url The URL of the request - * @param string $method The HTTP method (defaults to "GET") - * @param array $headers An associative array of headers - * @param string $body An optional body for POST/PUT requests - * @return \OpenCloud\HttpResult - */ - public function request( - $url, - $method = 'GET', - array $headers = array(), - $body = null - ) { - - $headers['X-Auth-Token'] = $this->conn->Token(); - - if ($tenant = $this->conn->Tenant()) { - $headers['X-Auth-Project-Id'] = $tenant; - } - - return $this->conn->request($url, $method, $headers, $body); - } - - /** - * returns a collection of objects - * - * @param string $class the class of objects to fetch - * @param string $url (optional) the URL to retrieve - * @param mixed $parent (optional) the parent service/object - * @return OpenCloud\Common\Collection - */ - public function collection($class, $url = null, $parent = null) - { - // Set the element names - $collectionName = $class::JsonCollectionName(); - $elementName = $class::JsonCollectionElement(); - - // Set the parent if empty - if (!$parent) { - $parent = $this; - } - - // Set the URL if empty - if (!$url) { - $url = $parent->url($class::ResourceName()); - } - - // Save debug info - $this->getLogger()->info( - '{class}:Collection({url}, {collectionClass}, {collectionName})', - array( - 'class' => get_class($this), - 'url' => $url, - 'collectionClass' => $class, - 'collectionName' => $collectionName - ) - ); - - // Fetch the list - $response = $this->request($url); - - $this->getLogger()->info('Response {status} [{body}]', array( - 'status' => $response->httpStatus(), - 'body' => $response->httpBody() - )); - - // Check return code - if ($response->httpStatus() > 204) { - throw new Exceptions\CollectionError(sprintf( - Lang::translate('Unable to retrieve [%s] list from [%s], status [%d] response [%s]'), - $class, - $url, - $response->httpStatus(), - $response->httpBody() - )); - } - - // Handle empty response - if (strlen($response->httpBody()) == 0) { - return new Collection($parent, $class, array()); - } - - // Parse the return - $object = json_decode($response->httpBody()); - $this->checkJsonError(); - - // See if there's a "next" link - // Note: not sure if the current API offers links as top-level structures; - // might have to refactor to allow $nextPageUrl as method argument - // @codeCoverageIgnoreStart - if (isset($object->links) && is_array($object->links)) { - foreach($object->links as $link) { - if (isset($link->rel) && $link->rel == 'next') { - if (isset($link->href)) { - $nextPageUrl = $link->href; - } else { - $this->getLogger()->warning( - 'Unexpected [links] found with no [href]' - ); - } - } - } - } - // @codeCoverageIgnoreEnd - - // How should we populate the collection? - $data = array(); - - if (!$collectionName) { - // No element name, just a plain object - // @codeCoverageIgnoreStart - $data = $object; - // @codeCoverageIgnoreEnd - } elseif (isset($object->$collectionName)) { - if (!$elementName) { - // The object has a top-level collection name only - $data = $object->$collectionName; - } else { - // The object has element levels which need to be iterated over - $data = array(); - foreach($object->$collectionName as $item) { - $subValues = $item->$elementName; - unset($item->$elementName); - $data[] = array_merge((array)$item, (array)$subValues); - } - } - } - - $collectionObject = new Collection($parent, $class, $data); - - // if there's a $nextPageUrl, then we need to establish a callback - // @codeCoverageIgnoreStart - if (!empty($nextPageUrl)) { - $collectionObject->setNextPageCallback(array($this, 'Collection'), $nextPageUrl); - } - // @codeCoverageIgnoreEnd - - return $collectionObject; - } - - /** - * returns the Region associated with the service - * - * @api - * @return string - */ - public function region() - { - return $this->service_region; - } - - /** - * returns the serviceName associated with the service - * - * This is used by DNS for PTR record lookups - * - * @api - * @return string - */ - public function name() - { - return $this->service_name; - } - - /** - * Returns a list of supported namespaces - * - * @return array - */ - public function namespaces() - { - return (isset($this->_namespaces) && is_array($this->_namespaces)) ? $this->_namespaces : array(); - } - - /** - * Given a service type, name, and region, return the url - * - * This function ensures that services are represented by an entry in the - * service catalog, and NOT by an arbitrarily-constructed URL. - * - * Note that it will always return the first match found in the - * service catalog (there *should* be only one, but you never know...) - * - * @param string $type The OpenStack service type ("compute" or - * "object-store", for example - * @param string $name The name of the service in the service catlog - * @param string $region The region of the service - * @param string $urltype The URL type; defaults to "publicURL" - * @return string The URL of the service - */ - private function getEndpoint($type, $name, $region, $urltype = 'publicURL') - { - $catalog = $this->getConnection()->serviceCatalog(); - - // Search each service to find The One - foreach ($catalog as $service) { - // Find the service by comparing the type ("compute") and name ("openstack") - if (!strcasecmp($service->type, $type) && !strcasecmp($service->name, $name)) { - foreach($service->endpoints as $endpoint) { - // Only set the URL if: - // a. It is a regionless service (i.e. no region key set) - // b. The region matches the one we want - if (isset($endpoint->$urltype) && - (!isset($endpoint->region) || !strcasecmp($endpoint->region, $region)) - ) { - $url = $endpoint->$urltype; - } - } - } - } - - // error if not found - if (empty($url)) { - throw new Exceptions\EndpointError(sprintf( - 'No endpoints for service type [%s], name [%s], region [%s] and urlType [%s]', - $type, - $name, - $region, - $urltype - )); - } - - return $url; - } - - /** - * Constructs a specified URL from the subresource - * - * Given a subresource (e.g., "extensions"), this constructs the proper - * URL and retrieves the resource. - * - * @param string $resource The resource requested; should NOT have slashes - * at the beginning or end - * @return \stdClass object - */ - private function getMetaUrl($resource) - { - $urlBase = $this->getEndpoint( - $this->service_type, - $this->service_name, - $this->service_region, - RAXSDK_URL_PUBLIC - ); - - $url = Lang::noslash($urlBase) . '/' . $resource; - - $response = $this->request($url); - - // check for NOT FOUND response - if ($response->httpStatus() == 404) { - return array(); - } - - // @codeCoverageIgnoreStart - if ($response->httpStatus() >= 300) { - throw new Exceptions\HttpError(sprintf( - Lang::translate('Error accessing [%s] - status [%d], response [%s]'), - $urlBase, - $response->httpStatus(), - $response->httpBody() - )); - } - // @codeCoverageIgnoreEnd - - // we're good; proceed - $object = json_decode($response->httpBody()); - - $this->checkJsonError(); - - return $object; - } - - /** - * Get all associated resources for this service. - * - * @access public - * @return void - */ - public function getResources() - { - return $this->resources; - } - - /** - * Internal method for accessing child namespace from parent scope. - * - * @return type - */ - protected function getCurrentNamespace() - { - $namespace = get_class($this); - return substr($namespace, 0, strrpos($namespace, '\\')); - } - - /** - * Resolves fully-qualified classname for associated local resource. - * - * @param string $resourceName - * @return string - */ - protected function resolveResourceClass($resourceName) - { - $className = substr_count($resourceName, '\\') - ? $resourceName - : $this->getCurrentNamespace() . '\\Resource\\' . ucfirst($resourceName); - - if (!class_exists($className)) { - throw new Exceptions\UnrecognizedServiceError(sprintf( - '%s resource does not exist, please try one of the following: %s', - $resourceName, - implode(', ', $this->getResources()) - )); - } - - return $className; - } - - /** - * Factory method for instantiating resource objects. - * - * @access public - * @param string $resourceName - * @param mixed $info (default: null) - * @return object - */ - public function resource($resourceName, $info = null) - { - $className = $this->resolveResourceClass($resourceName); - return new $className($this, $info); - } - - /** - * Factory method for instantiate a resource collection. - * - * @param string $resourceName - * @param string|null $url - * @return Collection - */ - public function resourceList($resourceName, $url = null, $service = null) - { - $className = $this->resolveResourceClass($resourceName); - return $this->collection($className, $url, $service); - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/ServiceCatalogItem.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/ServiceCatalogItem.php deleted file mode 100644 index 3e20bcbc7b..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/ServiceCatalogItem.php +++ /dev/null @@ -1,18 +0,0 @@ - $value) { - $this->$key = $value; - } - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Globals.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Globals.php deleted file mode 100644 index fbdc4355e0..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Globals.php +++ /dev/null @@ -1,252 +0,0 @@ - - */ - -namespace OpenCloud; - -/** - * This file contains only configuration data such as constants. - * You can override these constants by defining them BEFORE you including - * any of the top-level files from the SDK. - * - * Definitions: - * * RAXSDK_TIMEZONE - the default timezone for interpreting date/time requests - * * RAXSDK_STRICT_PROPERTY_CHECKS - if TRUE, the library will strictly enforce - * property names on objects; only properties that are pre-defined or - * appear in the extensions aliases for the service will be permitted. - * When FALSE (the default), then any property can be set on an object. - * * RAXSDK_COMPUTE_NAME - the default name for the compute service - * * RAXSDK_COMPUTE_REGION - the default region for the compute service - * * RAXSDK_COMPUTE_URLTYPE - the default URL type for the compute service - * * RAXSDK_OBJSTORE_NAME - the default name for the object storage service - * * RAXSDK_OBJSTORE_REGION - the default region for the object storage service - * * RAXSDK_OBJSTORE_URLTYPE - the default URL type for the object storage - * service - * * RAXSDK_DATABASE_NAME - the default name for the DbService service - * * RAXSDK_DATABASE_REGION - the default region for the DbService service - * * RAXSDK_DATABASE_URLTYPE - the default URL type for the DbService service - * * RAXSDK_CONNECTTIMEOUT - the time (in seconds) to wait for a connection - * to a service - * * RAXSDK_TIMEOUT - the max time (in seconds) to wait for an HTTP request - * to complete - * * RAXSDK_SERVER_MAXTIMEOUT - the max time (in seconds) that a server - * will wait for a change in status (Server::WaitFor() method) - * * RAXSDK_POLL_INTERVAL - how often (in seconds) the Server::WaitFor() method - * will poll for a status change - * * RAXSDK_DEFAULT_IP_VERSION - the default IP version (4 or 6) to return for - * the server's primary IP address - * * RAXSDK_OVERLIMIT_TIMEOUT - the max time (in seconds) to wait before - * retrying a request that has failed because of rate limits. If the - * next available time for the request is more than (X) seconds away, - * then the request will fail; otherwise, the request will sleep until - * available. - */ - -if (!defined('RAXSDK_TIMEZONE')) - define('RAXSDK_TIMEZONE', 'America/Chicago'); -if (!defined('RAXSDK_STRICT_PROPERTY_CHECKS')) - define('RAXSDK_STRICT_PROPERTY_CHECKS', FALSE); -if (!defined('RAXSDK_COMPUTE_NAME')) - define('RAXSDK_COMPUTE_NAME', 'cloudServersOpenStack'); -if (!defined('RAXSDK_COMPUTE_REGION')) - define('RAXSDK_COMPUTE_REGION', NULL); -if (!defined('RAXSDK_COMPUTE_URLTYPE')) - define('RAXSDK_COMPUTE_URLTYPE', 'publicURL'); -if (!defined('RAXSDK_MONITORING_NAME')) - define('RAXSDK_MONITORING_NAME', 'cloudMonitoring'); -if (!defined('RAXSDK_MONITORING_REGION')) - define('RAXSDK_MONITORING_REGION', '{ignore}'); -if (!defined('RAXSDK_MONITORING_URLTYPE')) - define('RAXSDK_MONITORING_URLTYPE', 'publicURL'); -if (!defined('RAXSDK_ORCHESTRATION_NAME')) - define('RAXSDK_ORCHESTRATION_NAME', 'cloudOrchestration'); -if (!defined('RAXSDK_ORCHESTRATION_REGION')) - define('RAXSDK_ORCHESTRATION_REGION', NULL); -if (!defined('RAXSDK_ORCHESTRATION_URLTYPE')) - define('RAXSDK_ORCHESTRATION_URLTYPE', 'publicURL'); -if (!defined('RAXSDK_OBJSTORE_NAME')) - define('RAXSDK_OBJSTORE_NAME', 'cloudFiles'); -if (!defined('RAXSDK_OBJSTORE_REGION')) - define('RAXSDK_OBJSTORE_REGION', NULL); -if (!defined('RAXSDK_OBJSTORE_URLTYPE')) - define('RAXSDK_OBJSTORE_URLTYPE', 'publicURL'); -if (!defined('RAXSDK_DATABASE_NAME')) - define('RAXSDK_DATABASE_NAME', 'cloudDatabases'); -if (!defined('RAXSDK_DATABASE_REGION')) - define('RAXSDK_DATABASE_REGION', NULL); -if (!defined('RAXSDK_DATABASE_URLTYPE')) - define('RAXSDK_DATABASE_URLTYPE', 'publicURL'); -if (!defined('RAXSDK_VOLUME_NAME')) - define('RAXSDK_VOLUME_NAME', 'cloudBlockStorage'); -if (!defined('RAXSDK_VOLUME_REGION')) - define('RAXSDK_VOLUME_REGION', NULL); -if (!defined('RAXSDK_VOLUME_URLTYPE')) - define('RAXSDK_VOLUME_URLTYPE', 'publicURL'); -if (!defined('RAXSDK_LBSERVICE_NAME')) - define('RAXSDK_LBSERVICE_NAME', 'cloudLoadBalancers'); -if (!defined('RAXSDK_LBSERVICE_REGION')) - define('RAXSDK_LBSERVICE_REGION', NULL); -if (!defined('RAXSDK_LBSERVICE_URLTYPE')) - define('RAXSDK_LBSERVICE_URLTYPE', 'publicURL'); -if (!defined('RAXSDK_DNS_NAME')) - define('RAXSDK_DNS_NAME', 'cloudDNS'); -if (!defined('RAXSDK_DNS_REGION')) - define('RAXSDK_DNS_REGION', '{ignore}'); // DNS is regionless -if (!defined('RAXSDK_DNS_URLTYPE')) - define('RAXSDK_DNS_URLTYPE', 'publicURL'); -if (!defined('RAXSDK_AUTOSCALE_NAME')) - define('RAXSDK_AUTOSCALE_NAME', 'autoscale'); -if (!defined('RAXSDK_AUTOSCALE_REGION')) - define('RAXSDK_AUTOSCALE_REGION', NULL); -if (!defined('RAXSDK_AUTOSCALE_URLTYPE')) - define('RAXSDK_AUTOSCALE_URLTYPE', 'publicURL'); -if (!defined('RAXSDK_DNS_ASYNC_TIMEOUT')) - define('RAXSDK_DNS_ASYNC_TIMEOUT', 60); -if (!defined('RAXSDK_DNS_ASYNC_INTERVAL')) - define('RAXSDK_DNS_ASYNC_INTERVAL', 1); -if (!defined('RAXSDK_CONNECTTIMEOUT')) - define('RAXSDK_CONNECTTIMEOUT', 5); -if (!defined('RAXSDK_TIMEOUT')) - define('RAXSDK_TIMEOUT', 60); -if (!defined('RAXSDK_SERVER_MAXTIMEOUT')) - define('RAXSDK_SERVER_MAXTIMEOUT', 3600); -if (!defined('RAXSDK_POLL_INTERVAL')) - define('RAXSDK_POLL_INTERVAL', 10); -if (!defined('RAXSDK_DEFAULT_IP_VERSION')) - define('RAXSDK_DEFAULT_IP_VERSION', 4); -if (!defined('RAXSDK_OVERLIMIT_TIMEOUT')) - define('RAXSDK_OVERLIMIT_TIMEOUT', 300); -/** - * sets default (highly secure) value for CURLOPT_SSL_VERIFYHOST. If you - * are using a self-signed SSL certificate, you can reduce this setting, but - * you do so at your own risk. - */ -if (!defined('RAXSDK_SSL_VERIFYHOST')) - define('RAXSDK_SSL_VERIFYHOST', 2); -/** - * sets default (highly secure) value for CURLOPT_SSL_VERIFYPEER. If you - * are using a self-signed SSL certificate, you can reduce this setting, but - * you do so at your own risk. - */ -if (!defined('RAXSDK_SSL_VERIFYPEER')) - define('RAXSDK_SSL_VERIFYPEER', TRUE); - -/** - * edit and uncomment this to set the default location of cacert.pem file - */ -//define('RAXSDK_CACERTPEM', __DIR__ . DIRECTORY_SEPARATOR . 'cacert.pem'); - -/* these should not be overridden */ -define('RAXSDK_VERSION', '1.5.10'); -define('RAXSDK_USER_AGENT', 'php-opencloud/'.RAXSDK_VERSION.' (Rackspace)'); -define('RAXSDK_ERROR', 'Error:'); -define('RAXSDK_FATAL', 'FATAL ERROR:'); -define('RAXSDK_TERMINATED', '*** PROCESSING HALTED ***'); -define('RAXSDK_CONTENT_TYPE_JSON', 'application/json'); -define('RAXSDK_URL_PUBLIC', 'publicURL'); -define('RAXSDK_URL_INTERNAL', 'internalURL'); -define('RAXSDK_URL_VERSION_INFO', 'versionInfo'); -define('RAXSDK_URL_VERSION_LIST', 'versionList'); - -/** - * definitions for Rackspace authentication endpoints - */ -define('RACKSPACE_US', 'https://identity.api.rackspacecloud.com/v2.0/'); -define('RACKSPACE_UK', 'https://lon.identity.api.rackspacecloud.com/v2.0/'); - -/** - * We can re-authenticate this many seconds before the token expires - * - * Set this to a higher value if your service does not cache tokens; if - * it *does* cache them, then this value is not required. - */ -define('RAXSDK_FUDGE', 0); - -/** - * Readable constants - */ -define('RAXSDK_SOFT_REBOOT', 'soft'); -define('RAXSDK_HARD_REBOOT', 'hard'); -define('RAXSDK_DETAILS', TRUE); -define('RAXSDK_MAX_CONTAINER_NAME_LEN', 256); - -/** - * UUID of the Rackspace 'public' network - */ -define('RAX_PUBLIC','00000000-0000-0000-0000-000000000000'); -/** - * UUID of the Rackspace 'private' network - */ -define('RAX_PRIVATE','11111111-1111-1111-1111-111111111111'); - -// Turn off debug mode by default -define('RAXSDK_DEBUG', false); - -/********** TIMEZONE MAGIC **********/ - -/** - * This is called if there is an error getting the default timezone; - * that means that the default timezone isn't set. - * - * @codeCoverageIgnore - */ -function __raxsdk_timezone_set($errno, $errstr) { - if ($errno==2) - date_default_timezone_set(RAXSDK_TIMEZONE); - else - die(sprintf("Unknown error %d: %s\n", $errno, $errstr)); -} -set_error_handler('\OpenCloud\__raxsdk_timezone_set'); -@date_default_timezone_get(); -restore_error_handler(); - -/********** SOME GLOBAL FUNCTIONS **********/ - - /** - * \OpenCloud\Common\Lang::translate() - this function should be used to wrap all static strings. In the future, - * this may provide us with a hook for providing different language - * translations. - * - * @codeCoverageIgnore - */ - function define_gettext() { - function translate($str) { - return $str; - } - } - - if (!function_exists('_')) - define_gettext(); - - /** - * removes trailing slash(es) from a URL string - * - * Mainly, this is just for appearance's sake. I really hate to see - * URLs like .../servers//address, for some reason. - * - * @codeCoverageIgnore - */ - function noslash($str) { - while ($str && (substr($str, -1) == '/')) - $str = substr($str, 0, strlen($str)-1); - return $str; - } - - /** - * Turns debugging on or off - * - * @codeCoverageIgnore - */ - function setDebug($state=TRUE) { - global $RAXSDK_DEBUG; - $RAXSDK_DEBUG=$state; - } - diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/AbstractService.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/AbstractService.php deleted file mode 100644 index 4a2298d60e..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/AbstractService.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @author Jamie Hannaford - */ - -namespace OpenCloud\ObjectStore; - -use OpenCloud\Common\Service as CommonService; - -define('SWIFT_MAX_OBJECT_SIZE', 5 * 1024 * 1024 * 1024 + 1); - -/** - * An abstract base class for common code shared between ObjectStore\Service - * (container) and ObjectStore\CDNService (CDN containers). - * - * @todo Maybe we use Traits instead of this small abstract class? - */ -abstract class AbstractService extends CommonService -{ - - const MAX_CONTAINER_NAME_LEN = 256; - const MAX_OBJECT_NAME_LEN = 1024; - const MAX_OBJECT_SIZE = SWIFT_MAX_OBJECT_SIZE; - - /** - * Creates a Container resource object. - * - * @param mixed $cdata The name of the container or an object from which to set values - * @return OpenCloud\ObjectStore\Resource\Container - */ - public function container($cdata = null) - { - return new Resource\Container($this, $cdata); - } - - /** - * Returns a Collection of Container objects. - * - * @param array $filter An array to filter the results - * @return OpenCloud\Common\Collection - */ - public function containerList(array $filter = array()) - { - $filter['format'] = 'json'; - - return $this->collection( - 'OpenCloud\ObjectStore\Resource\Container', $this->url(null, $filter) - ); - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/CDNService.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/CDNService.php deleted file mode 100644 index 132d5f47ad..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/CDNService.php +++ /dev/null @@ -1,62 +0,0 @@ - - * @author Jamie Hannaford - */ - -namespace OpenCloud\ObjectStore; - -use OpenCloud\OpenStack; -use OpenCloud\Common\Exceptions; - -/** - * This is the CDN version of the ObjectStore service. - */ -class CDNService extends AbstractService -{ - - /** - * Creates a new CDNService object. - * - * This is a simple wrapper function around the parent Service construct, - * but supplies defaults for the service type. - * - * @param OpenCloud\OpenStack $connection The connection object - * @param string $serviceName The name of the service - * @param string $serviceRegion The service's region - * @param string $urlType The type of URL (normally 'publicURL') - */ - public function __construct( - OpenStack $connection, - $serviceName = RAXSDK_OBJSTORE_NAME, - $serviceRegion = RAXSDK_OBJSTORE_REGION, - $urltype = RAXSDK_URL_PUBLIC - ) { - $this->getLogger()->info('Initializing CDN Service...'); - - parent::__construct( - $connection, - 'rax:object-cdn', - $serviceName, - $serviceRegion, - $urltype - ); - } - - /** - * Helps catch errors if someone calls the method on the - * wrong object - */ - public function CDN() - { - throw new Exceptions\CdnError( - 'Invalid method call; no CDN() on the CDN object' - ); - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/AbstractStorageObject.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/AbstractStorageObject.php deleted file mode 100644 index c6799b22b7..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/AbstractStorageObject.php +++ /dev/null @@ -1,170 +0,0 @@ - - * @author Jamie Hannaford - */ - -namespace OpenCloud\ObjectStore\Resource; - -use OpenCloud\Common\Base; -use OpenCloud\Common\Metadata; -use OpenCloud\Common\Exceptions\NameError; -use OpenCloud\Common\Exceptions\MetadataPrefixError; -use OpenCloud\Common\Request\Response\Http; - -/** - * Abstract base class which implements shared functionality of ObjectStore - * resources. Provides support, for example, for metadata-handling and other - * features that are common to the ObjectStore components. - */ -abstract class AbstractStorageObject extends Base -{ - - const ACCOUNT_META_PREFIX = 'X-Account-'; - const CONTAINER_META_PREFIX = 'X-Container-Meta-'; - const OBJECT_META_PREFIX = 'X-Object-Meta-'; - const CDNCONTAINER_META_PREFIX = 'X-Cdn-'; - - /** - * Metadata belonging to a resource. - * - * @var OpenCloud\Common\Metadata - */ - public $metadata; - - /** - * Initializes the metadata component - */ - public function __construct() - { - $this->metadata = new Metadata; - } - - /** - * Given an Http response object, converts the appropriate headers - * to metadata - * - * @param OpenCloud\Common\Request\Response\Http - * @return void - */ - public function getMetadata(Http $response) - { - $this->metadata = new Metadata; - $this->metadata->setArray($response->headers(), $this->prefix()); - } - - /** - * If object has metadata, return an associative array of headers. - * - * For example, if a DataObject has a metadata item named 'FOO', - * then this would return array('X-Object-Meta-FOO'=>$value); - * - * @return array - */ - public function metadataHeaders() - { - $headers = array(); - - // only build if we have metadata - if (is_object($this->metadata)) { - foreach ($this->metadata as $key => $value) { - $headers[$this->prefix() . $key] = $value; - } - } - - return $headers; - } - - /** - * Returns the displayable name of the object - * - * Can be overridden by child objects; *must* be overridden by child - * objects if the object does not have a `name` attribute defined. - * - * @api - * @throws NameError if attribute 'name' is not defined - */ - public function name() - { - if (property_exists($this, 'name')) { - return $this->name; - } else { - throw new NameError(sprintf( - 'Name attribute does not exist for [%s]', - get_class($this) - )); - } - } - - /** - * Override parent method. - * - * @return null - */ - public static function jsonName() - { - return null; - } - - /** - * Override parent method. - * - * @return null - */ - public static function jsonCollectionName() - { - return null; - } - - /** - * Override parent method. - * - * @return null - */ - public static function jsonCollectionElement() - { - return null; - } - - /** - * Returns the proper prefix for the specified type of object - * - * @param string $type The type of object; derived from `get_class()` if not - * specified. - * @codeCoverageIgnore - */ - private function prefix($type = null) - { - if ($type === null) { - $parts = preg_split('/\\\/', get_class($this)); - $type = $parts[count($parts)-1]; - } - - switch($type) { - case 'Account': - $prefix = self::ACCOUNT_META_PREFIX; - break; - case 'CDNContainer': - $prefix = self::CDNCONTAINER_META_PREFIX; - break; - case 'Container': - $prefix = self::CONTAINER_META_PREFIX; - break; - case 'DataObject': - $prefix = self::OBJECT_META_PREFIX; - break; - default: - throw new MetadataPrefixError(sprintf( - 'Unrecognized metadata type [%s]', - $type - )); - } - - return $prefix; - } -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/CDNContainer.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/CDNContainer.php deleted file mode 100644 index 9b6367c87e..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/CDNContainer.php +++ /dev/null @@ -1,298 +0,0 @@ - - * @author Jamie Hannaford - */ - -namespace OpenCloud\ObjectStore\Resource; - -use OpenCloud\Common\Service as AbstractService; -use OpenCloud\Common\Lang; -use OpenCloud\Common\Exceptions; -use OpenCloud\ObjectStore\AbstractService as AbstractObjectService; - -/** - * A container that has been CDN-enabled. Each CDN-enabled container has a unique - * Uniform Resource Locator (URL) that can be combined with its object names and - * openly distributed in web pages, emails, or other applications. - */ -class CDNContainer extends AbstractStorageObject -{ - /** - * The name of the container. - * - * The only restrictions on container names is that they cannot contain a - * forward slash (/) and must be less than 256 bytes in length. Please note - * that the length restriction applies to the name after it has been URL - * encoded. For example, a container named Course Docs would be URL encoded - * as Course%20Docs - which is 13 bytes in length rather than the expected 11. - * - * @var string - */ - public $name; - - /** - * Count of how many objects exist in the container. - * - * @var int - */ - public $count = 0; - - /** - * The total bytes used in the container. - * - * @var int - */ - public $bytes = 0; - - /** - * The service object. - * - * @var AbstractService - */ - private $service; - - /** - * URL of the container. - * - * @var string - */ - private $containerUrl; - - /** - * Creates the container object - * - * Creates a new container object or, if the $cdata object is a string, - * retrieves the named container from the object store. If $cdata is an - * array or an object, then its values are used to set this object. - * - * @param OpenCloud\ObjectStore $service - the ObjectStore service - * @param mixed $cdata - if supplied, the name of the object - */ - public function __construct(AbstractService $service, $cdata = null) - { - $this->getLogger()->info('Initializing CDN Container Service...'); - - parent::__construct(); - - $this->service = $service; - - // Populate data if set - $this->populate($cdata); - } - - /** - * Allow other objects to know what the primary key is. - * - * @return string - */ - public function primaryKeyField() - { - return 'name'; - } - - /** - * Returns the Service associated with the Container - */ - public function getService() - { - return $this->service; - } - - /** - * Returns the URL of the container - * - * @return string - * @param string $subresource not used; required for compatibility - * @throws NoNameError - */ - public function url($subresource = '') - { - if (strlen($this->name) == 0) { - throw new Exceptions\NoNameError( - Lang::translate('Container does not have an identifier') - ); - } - - return Lang::noslash($this->getService()->url(rawurlencode($this->name))); - } - - /** - * Creates a new container with the specified attributes - * - * @param array $params array of parameters - * @return boolean TRUE on success; FALSE on failure - * @throws ContainerCreateError - */ - public function create($params = array()) - { - // Populate object and check container name - $this->populate($params); - $this->isValidName($this->name); - - // Dispatch - $this->containerUrl = $this->url(); - $response = $this->getService()->request($this->url(), 'PUT', $this->metadataHeaders()); - - // Check return code - // @codeCoverageIgnoreStart - if ($response->httpStatus() > 202) { - throw new Exceptions\ContainerCreateError(sprintf( - Lang::translate('Problem creating container [%s] status [%d] response [%s]'), - $this->url(), - $response->httpStatus(), - $response->httpBody() - )); - } - // @codeCoverageIgnoreEnd - - return true; - } - - /** - * Updates the metadata for a container - * - * @return boolean TRUE on success; FALSE on failure - * @throws ContainerCreateError - */ - public function update() - { - $response = $this->getService()->request($this->url(), 'POST', $this->metadataHeaders()); - - // check return code - // @codeCoverageIgnoreStart - if ($response->httpStatus() > 204) { - throw new Exceptions\ContainerCreateError(sprintf( - Lang::translate('Problem updating container [%s] status [%d] response [%s]'), - $this->Url(), - $response->httpStatus(), - $response->httpBody() - )); - } - // @codeCoverageIgnoreEnd - - return true; - } - - /** - * Deletes the specified container - * - * @return boolean TRUE on success; FALSE on failure - * @throws ContainerDeleteError - */ - public function delete() - { - $response = $this->getService()->request($this->url(), 'DELETE'); - - // validate the response code - // @codeCoverageIgnoreStart - if ($response->httpStatus() == 404) { - throw new Exceptions\ContainerNotFoundError(sprintf( - Lang::translate('Container [%s] not found'), - $this->name - )); - } - - if ($response->httpStatus() == 409) { - throw new Exceptions\ContainerNotEmptyError(sprintf( - Lang::translate('Container [%s] must be empty before deleting'), - $this->name - )); - } - - if ($response->httpStatus() >= 300) { - throw new Exceptions\ContainerDeleteError(sprintf( - Lang::translate('Problem deleting container [%s] status [%d] response [%s]'), - $this->url(), - $response->httpStatus(), - $response->httpBody() - )); - return false; - } - // @codeCoverageIgnoreEnd - - return true; - } - - /** - * Loads the object from the service - * - * @return void - */ - public function refresh($name = null, $url = null) - { - $response = $this->getService()->request( - $this->url($name), 'HEAD', array('Accept' => '*/*') - ); - - // validate the response code - // @codeCoverageIgnoreStart - if ($response->HttpStatus() == 404) { - throw new Exceptions\ContainerNotFoundError(sprintf( - 'Container [%s] (%s) not found', - $this->name, - $this->url() - )); - } - - if ($response->HttpStatus() >= 300) { - throw new Exceptions\HttpError(sprintf( - 'Error retrieving Container, status [%d] response [%s]', - $response->httpStatus(), - $response->httpBody() - )); - } - - // check for headers (not metadata) - foreach($response->headers() as $header => $value) { - switch($header) { - case 'X-Container-Object-Count': - $this->count = $value; - break; - case 'X-Container-Bytes-Used': - $this->bytes = $value; - break; - } - } - // @codeCoverageIgnoreEnd - - // parse the returned object - $this->getMetadata($response); - } - - /** - * Validates that the container name is acceptable - * - * @param string $name the container name to validate - * @return boolean TRUE if ok; throws an exception if not - * @throws ContainerNameError - */ - public function isValidName($name) - { - if (strlen($name) == 0) { - throw new Exceptions\ContainerNameError( - 'Container name cannot be blank' - ); - } - - if (strpos($name, '/') !== false) { - throw new Exceptions\ContainerNameError( - 'Container name cannot contain "/"' - ); - } - - if (strlen($name) > AbstractObjectService::MAX_CONTAINER_NAME_LEN) { - throw new Exceptions\ContainerNameError( - 'Container name is too long' - ); - } - - return true; - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/Container.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/Container.php deleted file mode 100644 index 3a56ebd9fc..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/Container.php +++ /dev/null @@ -1,401 +0,0 @@ - - * @author Jamie Hannaford - */ - -namespace OpenCloud\ObjectStore\Resource; - -use OpenCloud\Common\Exceptions; -use OpenCloud\Common\Lang; - -/** - * A container is a storage compartment for your data and provides a way for you - * to organize your data. You can think of a container as a folder in Windows® - * or a directory in UNIX®. The primary difference between a container and these - * other file system concepts is that containers cannot be nested. - * - * A container can also be CDN-enabled (for public access), in which case you - * will need to interact with a CDNContainer object instead of this one. - */ -class Container extends CDNContainer -{ - - /** - * CDN container (if set). - * - * @var CDNContainer|null - */ - private $cdn; - - /** - * Sets the CDN container. - * - * @param OpenCloud\ObjectStore\Resource\CDNContainer $cdn - */ - public function setCDN(CDNContainer $cdn) - { - $this->cdn = $cdn; - } - - /** - * Returns the CDN container. - * - * @returns CDNContainer - */ - public function getCDN() - { - if (!$this->cdn) { - throw new Exceptions\CdnNotAvailableError( - Lang::translate('CDN-enabled container is not available') - ); - } - - return $this->cdn; - } - - /** - * Backwards compatability. - */ - public function CDN() - { - return $this->getCDN(); - } - - /** - * Makes the container public via the CDN - * - * @api - * @param integer $TTL the Time-To-Live for the CDN container; if NULL, - * then the cloud's default value will be used for caching. - * @throws CDNNotAvailableError if CDN services are not available - * @return CDNContainer - */ - public function enableCDN($ttl = null) - { - $url = $this->getService()->CDN()->url() . '/' . rawurlencode($this->name); - - $headers = $this->metadataHeaders(); - - if ($ttl) { - - // Make sure we're dealing with a real figure - if (!is_integer($ttl)) { - throw new Exceptions\CdnTtlError(sprintf( - Lang::translate('TTL value [%s] must be an integer'), - $ttl - )); - } - - $headers['X-TTL'] = $ttl; - } - - $headers['X-Log-Retention'] = 'True'; - $headers['X-CDN-Enabled'] = 'True'; - - // PUT to the CDN container - $response = $this->getService()->request($url, 'PUT', $headers); - - // check the response status - // @codeCoverageIgnoreStart - if ($response->httpStatus() > 202) { - throw new Exceptions\CdnHttpError(sprintf( - Lang::translate('HTTP error publishing to CDN, status [%d] response [%s]'), - $response->httpStatus(), - $response->httpBody() - )); - } - // @codeCoverageIgnoreEnd - - // refresh the data - $this->refresh(); - - // return the CDN container object - $cdn = new CDNContainer($this->getService()->getCDNService(), $this->name); - $this->setCDN($cdn); - - return $cdn; - } - - /** - * Backwards compatability. - */ - public function publishToCDN($ttl = null) - { - return $this->enableCDN($ttl); - } - - /** - * Disables the containers CDN function. - * - * Note that the container will still be available on the CDN until - * its TTL expires. - * - * @api - * @return void - */ - public function disableCDN() - { - // Set necessary headers - $headers['X-Log-Retention'] = 'False'; - $headers['X-CDN-Enabled'] = 'False'; - - // PUT it to the CDN service - $response = $this->getService()->request($this->CDNURL(), 'PUT', $headers); - - // check the response status - // @codeCoverageIgnoreStart - if ($response->httpStatus() != 201) { - throw new Exceptions\CdnHttpError(sprintf( - Lang::translate('HTTP error disabling CDN, status [%d] response [%s]'), - $response->httpStatus(), - $response->httpBody() - )); - } - // @codeCoverageIgnoreEnd - - return true; - } - - /** - * Creates a static website from the container - * - * @api - * @link http://docs.rackspace.com/files/api/v1/cf-devguide/content/Create_Static_Website-dle4000.html - * @param string $index the index page (starting page) of the website - * @return \OpenCloud\HttpResponse - */ - public function createStaticSite($indexHtml) - { - $headers = array('X-Container-Meta-Web-Index' => $indexHtml); - $response = $this->getService()->request($this->url(), 'POST', $headers); - - // check return code - // @codeCoverageIgnoreStart - if ($response->HttpStatus() > 204) { - throw new Exceptions\ContainerError(sprintf( - Lang::translate('Error creating static website for [%s], status [%d] response [%s]'), - $this->name, - $response->httpStatus(), - $response->httpBody() - )); - } - // @codeCoverageIgnoreEnd - - return $response; - } - - /** - * Sets the error page(s) for the static website - * - * @api - * @link http://docs.rackspace.com/files/api/v1/cf-devguide/content/Set_Error_Pages_for_Static_Website-dle4005.html - * @param string $name the name of the error page - * @return \OpenCloud\HttpResponse - */ - public function staticSiteErrorPage($name) - { - $headers = array('X-Container-Meta-Web-Error' => $name); - $response = $this->getService()->request($this->url(), 'POST', $headers); - - // check return code - // @codeCoverageIgnoreStart - if ($response->httpStatus() > 204) { - throw new Exceptions\ContainerError(sprintf( - Lang::translate('Error creating static site error page for [%s], status [%d] response [%s]'), - $this->name, - $response->httpStatus(), - $response->httpBody() - )); - } - - return $response; - // @codeCoverageIgnoreEnd - } - - /** - * Returns the CDN URL of the container (if enabled) - * - * The CDNURL() is used to manage the container. Note that it is different - * from the PublicURL() of the container, which is the publicly-accessible - * URL on the network. - * - * @api - * @return string - */ - public function CDNURL() - { - return $this->getCDN()->url(); - } - - /** - * Returns the Public URL of the container (on the CDN network) - * - */ - public function publicURL() - { - return $this->CDNURI(); - } - - /** - * Returns the CDN info about the container - * - * @api - * @return stdClass - */ - public function CDNinfo($property = null) - { - // Not quite sure why this is here... - // @codeCoverageIgnoreStart - if ($this->getService() instanceof CDNService) { - return $this->metadata; - } - // @codeCoverageIgnoreEnd - - // return NULL if the CDN container is not enabled - if (!isset($this->getCDN()->metadata->Enabled) - || $this->getCDN()->metadata->Enabled == 'False' - ) { - return null; - } - - // check to see if it's set - if (isset($this->getCDN()->metadata->$property)) { - return trim($this->getCDN()->metadata->$property); - } elseif ($property !== null) { - return null; - } - - // otherwise, return the whole metadata object - return $this->getCDN()->metadata; - } - - /** - * Returns the CDN container URI prefix - * - * @api - * @return string - */ - public function CDNURI() - { - return $this->CDNinfo('Uri'); - } - - /** - * Returns the SSL URI for the container - * - * @api - * @return string - */ - public function SSLURI() - { - return $this->CDNinfo('Ssl-Uri'); - } - - /** - * Returns the streaming URI for the container - * - * @api - * @return string - */ - public function streamingURI() - { - return $this->CDNinfo('Streaming-Uri'); - } - - /** - * Returns the IOS streaming URI for the container - * - * @api - * @link http://docs.rackspace.com/files/api/v1/cf-devguide/content/iOS-Streaming-d1f3725.html - * @return string - */ - public function iosStreamingURI() - { - return $this->CDNinfo('Ios-Uri'); - } - - /** - * Creates a Collection of objects in the container - * - * @param array $params associative array of parameter values. - * * account/tenant - The unique identifier of the account/tenant. - * * container- The unique identifier of the container. - * * limit (Optional) - The number limit of results. - * * marker (Optional) - Value of the marker, that the object names - * greater in value than are returned. - * * end_marker (Optional) - Value of the marker, that the object names - * less in value than are returned. - * * prefix (Optional) - Value of the prefix, which the returned object - * names begin with. - * * format (Optional) - Value of the serialized response format, either - * json or xml. - * * delimiter (Optional) - Value of the delimiter, that all the object - * names nested in the container are returned. - * @link http://api.openstack.org for a list of possible parameter - * names and values - * @return OpenCloud\Collection - * @throws ObjFetchError - */ - public function objectList($params = array()) - { - // construct a query string out of the parameters - $params['format'] = 'json'; - - $queryString = $this->makeQueryString($params); - - // append the query string to the URL - $url = $this->url(); - if (strlen($queryString) > 0) { - $url .= '?' . $queryString; - } - - return $this->getService()->collection( - 'OpenCloud\ObjectStore\Resource\DataObject', $url, $this - ); - } - - /** - * Returns a new DataObject associated with this container - * - * @param string $name if supplied, the name of the object to return - * @return DataObject - */ - public function dataObject($name = null) - { - return new DataObject($this, $name); - } - - /** - * Refreshes, then associates the CDN container - */ - public function refresh($id = null, $url = null) - { - parent::refresh($id, $url); - - // @codeCoverageIgnoreStart - if ($this->getService() instanceof CDNService) { - return; - } - - - if (null !== ($cdn = $this->getService()->CDN())) { - try { - $this->cdn = new CDNContainer( - $cdn, - $this->name - ); - } catch (Exceptions\ContainerNotFoundError $e) { - $this->cdn = new CDNContainer($cdn); - $this->cdn->name = $this->name; - } - } - // @codeCoverageIgnoreEnd - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/DataObject.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/DataObject.php deleted file mode 100644 index 443df1f651..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/DataObject.php +++ /dev/null @@ -1,941 +0,0 @@ - - * @author Jamie Hannaford - */ - -namespace OpenCloud\ObjectStore\Resource; - -use finfo as FileInfo; -use OpenCloud\Common\Lang; -use OpenCloud\Common\Exceptions; -use OpenCloud\ObjectStore\AbstractService; -use OpenCloud\Common\Request\Response\Http; - -/** - * Objects are the basic storage entities in Cloud Files. They represent the - * files and their optional metadata you upload to the system. When you upload - * objects to Cloud Files, the data is stored as-is (without compression or - * encryption) and consists of a location (container), the object's name, and - * any metadata you assign consisting of key/value pairs. - */ -class DataObject extends AbstractStorageObject -{ - /** - * Object name. The only restriction on object names is that they must be - * less than 1024 bytes in length after URL encoding. - * - * @var string - */ - public $name; - - /** - * Hash value of the object. - * - * @var string - */ - public $hash; - - /** - * Size of object in bytes. - * - * @var string - */ - public $bytes; - - /** - * Date of last modification. - * - * @var string - */ - public $last_modified; - - /** - * Object's content type. - * - * @var string - */ - public $content_type; - - /** - * Object's content length. - * - * @var string - */ - public $content_length; - - /** - * Other headers set for this object (e.g. Access-Control-Allow-Origin) - * - * @var array - */ - public $extra_headers = array(); - - /** - * Whether or not to calculate and send an ETag on create. - * - * @var bool - */ - public $send_etag = true; - - /** - * The data contained by the object. - * - * @var string - */ - private $data; - - /** - * The ETag value. - * - * @var string - */ - private $etag; - - /** - * The parent container of this object. - * - * @var CDNContainer - */ - private $container; - - /** - * Is this data object a pseudo directory? - * - * @var bool - */ - private $directory = false; - - /** - * Used to translate header values (returned by requests) into properties. - * - * @var array - */ - private $headerTranslate = array( - 'Etag' => 'hash', - 'ETag' => 'hash', - 'Last-Modified' => 'last_modified', - 'Content-Length' => array('bytes', 'content_length'), - ); - - /** - * These properties can be freely set by the user for CRUD operations. - * - * @var array - */ - private $allowedProperties = array( - 'name', - 'content_type', - 'extra_headers', - 'send_etag' - ); - - /** - * Option for clearing the status cache when objects are uploaded to API. - * By default, it is set to FALSE for performance; but if you have files - * that are rapidly and very often updated, you might want to clear the status - * cache so PHP reads the files directly, instead of relying on the cache. - * - * @link http://php.net/manual/en/function.clearstatcache.php - * @var bool - */ - public $clearStatusCache = false; - - /** - * A DataObject is related to a container and has a name - * - * If `$name` is specified, then it attempts to retrieve the object from the - * object store. - * - * @param Container $container the container holding this object - * @param mixed $cdata if an object or array, it is treated as values - * with which to populate the object. If it is a string, it is - * treated as a name and the object's info is retrieved from - * the service. - * @return void - */ - public function __construct($container, $cdata = null) - { - parent::__construct(); - - $this->container = $container; - - // For pseudo-directories, we need to ensure the name is set - if (!empty($cdata->subdir)) { - $this->name = $cdata->subdir; - $this->directory = true; - } else { - $this->populate($cdata); - } - } - - /** - * Is this data object a pseudo-directory? - * - * @return bool - */ - public function isDirectory() - { - return $this->directory; - } - - /** - * Allow other objects to know what the primary key is. - * - * @return string - */ - public function primaryKeyField() - { - return 'name'; - } - - /** - * Is this a real file? - * - * @param string $filename - * @return bool - */ - private function isRealFile($filename) - { - return $filename != '/dev/null' && $filename != 'NUL'; - } - - /** - * Set this file's content type. - * - * @param string $contentType - */ - public function setContentType($contentType) - { - $this->content_type = $contentType; - } - - /** - * Return the content type. - * - * @return string - */ - public function getContentType() - { - return $this->content_type; - } - - /** - * Returns the URL of the data object - * - * If the object is new and doesn't have a name, then an exception is - * thrown. - * - * @param string $subresource Not used - * @return string - * @throws NoNameError - */ - public function url($subresource = '') - { - if (!$this->name) { - throw new Exceptions\NoNameError(Lang::translate('Object has no name')); - } - - return Lang::noslash( - $this->container->url()) . '/' . str_replace('%2F', '/', rawurlencode($this->name) - ); - } - - /** - * Creates (or updates; both the same) an instance of the object - * - * @api - * @param array $params an optional associative array that can contain the - * 'name' and 'content_type' of the object - * @param string $filename if provided, then the object is loaded from the - * specified file - * @return boolean - * @throws CreateUpdateError - */ - public function create($params = array(), $filename = null, $extractArchive = null) - { - // Set and validate params - $this->setParams($params); - - // assume no file upload - $fp = false; - - // if the filename is provided, process it - if ($filename) { - - if (!$fp = @fopen($filename, 'r')) { - throw new Exceptions\IOError(sprintf( - Lang::translate('Could not open file [%s] for reading'), - $filename - )); - } - - // @todo Maybe, for performance, we could set the "clear status cache" - // feature to false by default - but allow users to set to true if required - clearstatcache($this->clearStatusCache === true, $filename); - - // Cast filesize as a floating point - $filesize = (float) filesize($filename); - - // Check it's below a reasonable size, and set - // @codeCoverageIgnoreStart - if ($filesize > AbstractService::MAX_OBJECT_SIZE) { - throw new Exceptions\ObjectError("File size exceeds maximum object size."); - } - // @codeCoverageIgnoreEnd - $this->content_length = $filesize; - - // Guess the content type if necessary - if (!$this->getContentType() && $this->isRealFile($filename)) { - $this->setContentType($this->inferContentType($filename)); - } - - // Send ETag checksum if necessary - if ($this->send_etag) { - $this->etag = md5_file($filename); - } - - // Announce to the world - $this->getLogger()->info('Uploading {size} bytes from {name}', array( - 'size' => $filesize, - 'name' => $filename - )); - - } else { - // compute the length - $this->content_length = strlen($this->data); - - if ($this->send_etag) { - $this->etag = md5($this->data); - } - } - - // Only allow supported archive types - // http://docs.rackspace.com/files/api/v1/cf-devguide/content/Extract_Archive-d1e2338.html - $extractArchiveUrlArg = ''; - - if ($extractArchive) { - if ($extractArchive !== "tar.gz" && $extractArchive !== "tar.bz2") { - throw new Exceptions\ObjectError( - "Extract Archive only supports tar.gz and tar.bz2" - ); - } else { - $extractArchiveUrlArg = "?extract-archive=" . $extractArchive; - $this->etag = null; - $this->setContentType(''); - } - } - - // Set headers - $headers = $this->metadataHeaders(); - - if (!empty($this->etag)) { - $headers['ETag'] = $this->etag; - } - - // Content-Type is no longer required; if not specified, it will - // attempt to guess based on the file extension. - if (!$this->getContentType()) { - $headers['Content-Type'] = $this->getContentType(); - } - - $headers['Content-Length'] = $this->content_length; - - // Merge in extra headers - if (!empty($this->extra_headers)) { - $headers = $this->extra_headers + $headers; - } - - // perform the request - $response = $this->getService()->request( - $this->url() . $extractArchiveUrlArg, - 'PUT', - $headers, - $fp ? $fp : $this->data - ); - - // check the status - // @codeCoverageIgnoreStart - if (($status = $response->httpStatus()) >= 300) { - throw new Exceptions\CreateUpdateError(sprintf( - Lang::translate('Problem saving/updating object [%s] HTTP status [%s] response [%s]'), - $this->url() . $extractArchiveUrlArg, - $status, - $response->httpBody() - )); - } - // @codeCoverageIgnoreEnd - - // set values from response - $this->saveResponseHeaders($response); - - // close the file handle - if ($fp) { - fclose($fp); - } - - return $response; - } - - /** - * Update() is provided as an alias for the Create() method - * - * Since update and create both use a PUT request, the different functions - * may allow the developer to distinguish between the semantics in his or - * her application. - * - * @api - * @param array $params an optional associative array that can contain the - * 'name' and 'type' of the object - * @param string $filename if provided, the object is loaded from the file - * @return boolean - */ - public function update($params = array(), $filename = '') - { - return $this->create($params, $filename); - } - - /** - * UpdateMetadata() - updates headers - * - * Updates metadata headers - * - * @api - * @param array $params an optional associative array that can contain the - * 'name' and 'type' of the object - * @return boolean - */ - public function updateMetadata($params = array()) - { - $this->setParams($params); - - // set the headers - $headers = $this->metadataHeaders(); - $headers['Content-Type'] = $this->getContentType(); - - $response = $this->getService()->request( - $this->url(), - 'POST', - $headers - ); - - // check the status - // @codeCoverageIgnoreStart - if (($stat = $response->httpStatus()) >= 204) { - throw new Exceptions\UpdateError(sprintf( - Lang::translate('Problem updating object [%s] HTTP status [%s] response [%s]'), - $this->url(), - $stat, - $response->httpBody() - )); - } - // @codeCoverageIgnoreEnd - - return $response; - } - - /** - * Deletes an object from the Object Store - * - * Note that we can delete without retrieving by specifying the name in the - * parameter array. - * - * @api - * @param array $params an array of parameters - * @return HttpResponse if successful; FALSE if not - * @throws DeleteError - */ - public function delete($params = array()) - { - $this->setParams($params); - - $response = $this->getService()->request($this->url(), 'DELETE'); - - // check the status - // @codeCoverageIgnoreStart - if (($stat = $response->httpStatus()) >= 300) { - throw new Exceptions\DeleteError(sprintf( - Lang::translate('Problem deleting object [%s] HTTP status [%s] response [%s]'), - $this->url(), - $stat, - $response->httpBody() - )); - } - // @codeCoverageIgnoreEnd - - return $response; - } - - /** - * Copies the object to another container/object - * - * Note that this function, because it operates within the Object Store - * itself, is much faster than downloading the object and re-uploading it - * to a new object. - * - * @param DataObject $target the target of the COPY command - */ - public function copy(DataObject $target) - { - $uri = sprintf('/%s/%s', $target->container()->name(), $target->name()); - - $this->getLogger()->info('Copying object to [{uri}]', array('uri' => $uri)); - - $response = $this->getService()->request( - $this->url(), - 'COPY', - array('Destination' => $uri) - ); - - // check response code - // @codeCoverageIgnoreStart - if ($response->httpStatus() > 202) { - throw new Exceptions\ObjectCopyError(sprintf( - Lang::translate('Error copying object [%s], status [%d] response [%s]'), - $this->url(), - $response->httpStatus(), - $response->httpBody() - )); - } - // @codeCoverageIgnoreEnd - - return $response; - } - - /** - * Returns the container of the object - * - * @return Container - */ - public function container() - { - return $this->container; - } - - /** - * returns the TEMP_URL for the object - * - * Some notes: - * * The `$secret` value is arbitrary; it must match the value set for - * the `X-Account-Meta-Temp-URL-Key` on the account level. This can be - * set by calling `$service->SetTempUrlSecret($secret)`. - * * The `$expires` value is the number of seconds you want the temporary - * URL to be valid for. For example, use `60` to make it valid for a - * minute - * * The `$method` must be either GET or PUT. No other methods are - * supported. - * - * @param string $secret the shared secret - * @param integer $expires the expiration time (in seconds) - * @param string $method either GET or PUT - * @return string the temporary URL - */ - public function tempUrl($secret, $expires, $method) - { - $method = strtoupper($method); - $expiry_time = time() + $expires; - - // check for proper method - if ($method != 'GET' && $method != 'PUT') { - throw new Exceptions\TempUrlMethodError(sprintf( - Lang::translate( - 'Bad method [%s] for TempUrl; only GET or PUT supported'), - $method - )); - } - - // construct the URL - $url = $this->url(); - $path = urldecode(parse_url($url, PHP_URL_PATH)); - - $hmac_body = "$method\n$expiry_time\n$path"; - $hash = hash_hmac('sha1', $hmac_body, $secret); - - $this->getLogger()->info('URL [{url}]; SIG [{sig}]; HASH [{hash}]', array( - 'url' => $url, - 'sig' => $hmac_body, - 'hash' => $hash - )); - - $temp_url = sprintf('%s?temp_url_sig=%s&temp_url_expires=%d', $url, $hash, $expiry_time); - - // debug that stuff - $this->getLogger()->info('TempUrl generated [{url}]', array( - 'url' => $temp_url - )); - - return $temp_url; - } - - /** - * Sets object data from string - * - * This is a convenience function to permit the use of other technologies - * for setting an object's content. - * - * @param string $data - * @return void - */ - public function setData($data) - { - $this->data = (string) $data; - } - - /** - * Return object's data as a string - * - * @return string the entire object - */ - public function saveToString() - { - return $this->getService()->request($this->url())->httpBody(); - } - - /** - * Saves the object's data to local filename - * - * Given a local filename, the Object's data will be written to the newly - * created file. - * - * Example: - * - * # ... authentication/connection/container code excluded - * # ... see previous examples - * - * # Whoops! I deleted my local README, let me download/save it - * # - * $my_docs = $conn->get_container("documents"); - * $doc = $my_docs->get_object("README"); - * - * $doc->SaveToFilename("/home/ej/cloudfiles/readme.restored"); - * - * - * @param string $filename name of local file to write data to - * @return boolean TRUE if successful - * @throws IOException error opening file - * @throws InvalidResponseException unexpected response - */ - public function saveToFilename($filename) - { - if (!$fp = @fopen($filename, "wb")) { - throw new Exceptions\IOError(sprintf( - Lang::translate('Could not open file [%s] for writing'), - $filename - )); - } - - $result = $this->getService()->request($this->url(), 'GET', array(), $fp); - - fclose($fp); - - return $result; - } - - /** - * Saves the object's to a stream filename - * - * Given a local filename, the Object's data will be written to the stream - * - * Example: - * - * # ... authentication/connection/container code excluded - * # ... see previous examples - * - * # If I want to write the README to a temporary memory string I - * # do : - * # - * $my_docs = $conn->get_container("documents"); - * $doc = $my_docs->DataObject(array("name"=>"README")); - * - * $fp = fopen('php://temp', 'r+'); - * $doc->SaveToStream($fp); - * fclose($fp); - * - * - * @param string $filename name of local file to write data to - * @return boolean TRUE if successful - * @throws IOException error opening file - * @throws InvalidResponseException unexpected response - */ - public function saveToStream($resource) - { - if (!is_resource($resource)) { - throw new Exceptions\ObjectError( - Lang::translate("Resource argument not a valid PHP resource." - )); - } - - return $this->getService()->request($this->url(), 'GET', array(), $resource); - } - - - /** - * Returns the object's MD5 checksum - * - * Accessor method for reading Object's private ETag attribute. - * - * @api - * @return string MD5 checksum hexidecimal string - */ - public function getETag() - { - return $this->etag; - } - - /** - * Purges the object from the CDN - * - * Note that the object will still be served up to the time of its - * TTL value. - * - * @api - * @param string $email An email address that will be notified when - * the object is purged. - * @return void - * @throws CdnError if the container is not CDN-enabled - * @throws CdnHttpError if there is an HTTP error in the transaction - */ - public function purgeCDN($email) - { - // @codeCoverageIgnoreStart - if (!$cdn = $this->Container()->CDNURL()) { - throw new Exceptions\CdnError(Lang::translate('Container is not CDN-enabled')); - } - // @codeCoverageIgnoreEnd - - $url = $cdn . '/' . $this->name; - $headers['X-Purge-Email'] = $email; - $response = $this->getService()->request($url, 'DELETE', $headers); - - // check the status - // @codeCoverageIgnoreStart - if ($response->httpStatus() > 204) { - throw new Exceptions\CdnHttpError(sprintf( - Lang::translate('Error purging object, status [%d] response [%s]'), - $response->httpStatus(), - $response->httpBody() - )); - } - // @codeCoverageIgnoreEnd - - return true; - } - - /** - * Returns the CDN URL (for managing the object) - * - * Note that the DataObject::PublicURL() method is used to return the - * publicly-available URL of the object, while the CDNURL() is used - * to manage the object. - * - * @return string - */ - public function CDNURL() - { - return $this->container()->CDNURL() . '/' . $this->name; - } - - /** - * Returns the object's Public CDN URL, if available - * - * @api - * @param string $type can be 'streaming', 'ssl', 'ios-streaming', - * or anything else for the - * default URL. For example, `$object->PublicURL('ios-streaming')` - * @return string - */ - public function publicURL($type = null) - { - if (!$prefix = $this->container()->CDNURI()) { - return null; - } - - switch(strtoupper($type)) { - case 'SSL': - $url = $this->container()->SSLURI().'/'.$this->name; - break; - case 'STREAMING': - $url = $this->container()->streamingURI().'/'.$this->name; - break; - case 'IOS': - case 'IOS-STREAMING': - $url = $this->container()->iosStreamingURI().'/'.$this->name; - break; - default: - $url = $prefix.'/'.$this->name; - break; - } - - return $url; - } - - /** - * Sets parameters from an array and validates them. - * - * @param array $params Associative array of parameters - * @return void - */ - private function setParams(array $params = array()) - { - // Inspect the user's array for any unapproved keys, and unset if necessary - foreach (array_diff(array_keys($params), $this->allowedProperties) as $key) { - $this->getLogger()->warning('You cannot use the {keyName} key when creating an object', array( - 'keyName' => $key - )); - unset($params[$key]); - } - - $this->populate($params); - } - - /** - * Retrieves a single object, parses headers - * - * @return void - * @throws NoNameError, ObjFetchError - */ - private function fetch() - { - if (!$this->name) { - throw new Exceptions\NoNameError(Lang::translate('Cannot retrieve an unnamed object')); - } - - $response = $this->getService()->request($this->url(), 'HEAD', array('Accept' => '*/*')); - - // check for errors - // @codeCoverageIgnoreStart - if ($response->httpStatus() >= 300) { - throw new Exceptions\ObjFetchError(sprintf( - Lang::translate('Problem retrieving object [%s]'), - $this->url() - )); - } - // @codeCoverageIgnoreEnd - - // set headers as metadata? - $this->saveResponseHeaders($response); - - // parse the metadata - $this->getMetadata($response); - } - - /** - * Extracts the headers from the response, and saves them as object - * attributes. Additional name conversions are done where necessary. - * - * @param Http $response - */ - private function saveResponseHeaders(Http $response, $fillExtraIfNotFound = true) - { - foreach ($response->headers() as $header => $value) { - if (isset($this->headerTranslate[$header])) { - // This header needs to be translated - $property = $this->headerTranslate[$header]; - // Are there multiple properties that need to be set? - if (is_array($property)) { - foreach ($property as $subProperty) { - $this->$subProperty = $value; - } - } else { - $this->$property = $value; - } - } elseif ($fillExtraIfNotFound === true) { - // Otherwise, stock extra headers - $this->extra_headers[$header] = $value; - } - } - } - - /** - * Compatability. - */ - public function refresh() - { - return $this->fetch(); - } - - /** - * Returns the service associated with this object - * - * It's actually the object's container's service, so this method will - * simplify things a bit. - */ - private function getService() - { - return $this->container->getService(); - } - - /** - * Performs an internal check to get the proper MIME type for an object - * - * This function would go over the available PHP methods to get - * the MIME type. - * - * By default it will try to use the PHP fileinfo library which is - * available from PHP 5.3 or as an PECL extension - * (http://pecl.php.net/package/Fileinfo). - * - * It will get the magic file by default from the system wide file - * which is usually available in /usr/share/magic on Unix or try - * to use the file specified in the source directory of the API - * (share directory). - * - * if fileinfo is not available it will try to use the internal - * mime_content_type function. - * - * @param string $handle name of file or buffer to guess the type from - * @return boolean TRUE if successful - * @throws BadContentTypeException - * @codeCoverageIgnore - */ - private function inferContentType($handle) - { - if ($contentType = $this->getContentType()) { - return $contentType; - } - - $contentType = false; - - $filePath = (is_string($handle)) ? $handle : (string) $handle; - - if (function_exists("finfo_open")) { - - $magicPath = dirname(__FILE__) . "/share/magic"; - $finfo = new FileInfo(FILEINFO_MIME, file_exists($magicPath) ? $magicPath : null); - - if ($finfo) { - - $contentType = is_file($filePath) - ? $finfo->file($handle) - : $finfo->buffer($handle); - - /** - * PHP 5.3 fileinfo display extra information like charset so we - * remove everything after the ; since we are not into that stuff - */ - if (null !== ($extraInfo = strpos($contentType, "; "))) { - $contentType = substr($contentType, 0, $extraInfo); - } - } - - //unset($finfo); - } - - if (!$contentType) { - // Try different native function instead - if (is_file((string) $handle) && function_exists("mime_content_type")) { - $contentType = mime_content_type($handle); - } else { - $this->getLogger()->error('Content-Type cannot be found'); - } - } - - return $contentType; - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Service.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Service.php deleted file mode 100644 index 571b33378a..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Service.php +++ /dev/null @@ -1,115 +0,0 @@ - - * @author Jamie Hannaford - */ - -namespace OpenCloud\ObjectStore; - -use OpenCloud\OpenStack; -use OpenCloud\Common\Exceptions; -use OpenCloud\Common\Lang; - -/** - * The ObjectStore (Cloud Files) service. - */ -class Service extends AbstractService -{ - - /** - * This holds the associated CDN service (for Rackspace public cloud) - * or is NULL otherwise. The existence of an object here is - * indicative that the CDN service is available. - */ - private $cdn; - - /** - * Creates a new ObjectStore service object. - * - * @param OpenCloud\OpenStack $connection The connection object - * @param string $serviceName The name of the service - * @param string $serviceRegion The service's region - * @param string $urlType The type of URL (normally 'publicURL') - */ - public function __construct( - OpenStack $connection, - $serviceName = RAXSDK_OBJSTORE_NAME, - $serviceRegion = RAXSDK_OBJSTORE_REGION, - $urltype = RAXSDK_OBJSTORE_URLTYPE - ) { - $this->getLogger()->info('Initializing Container Service...'); - - parent::__construct( - $connection, - 'object-store', - $serviceName, - $serviceRegion, - $urltype - ); - - // establish the CDN container, if available - try { - $this->cdn = new CDNService( - $connection, - $serviceName . 'CDN', - $serviceRegion, - $urltype - ); - } catch (Exceptions\EndpointError $e) { - // If we have an endpoint error, then the CDN functionality is not - // available. In this case, we silently ignore it. - } - } - - /** - * Sets the shared secret value for the TEMP_URL - * - * @param string $secret the shared secret - * @return HttpResponse - */ - public function setTempUrlSecret($secret) - { - $response = $this->request( - $this->url(), - 'POST', - array('X-Account-Meta-Temp-Url-Key' => $secret) - ); - - // @codeCoverageIgnoreStart - if ($response->httpStatus() > 204) { - throw new Exceptions\HttpError(sprintf( - Lang::translate('Error in request, status [%d] for URL [%s] [%s]'), - $response->httpStatus(), - $this->url(), - $response->httpBody() - )); - } - // @codeCoverageIgnoreEnd - - return $response; - } - - /** - * Get the CDN service. - * - * @return null|CDNService - */ - public function getCDNService() - { - return $this->cdn; - } - - /** - * Backwards compability. - */ - public function CDN() - { - return $this->getCDNService(); - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/OpenStack.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/OpenStack.php deleted file mode 100644 index c3e645a540..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/OpenStack.php +++ /dev/null @@ -1,1198 +0,0 @@ - - * @author Jamie Hannaford - */ - -namespace OpenCloud; - -require_once __DIR__ . '/Globals.php'; - -use OpenCloud\Common\Base; -use OpenCloud\Common\Lang; -use OpenCloud\Common\Exceptions; -use OpenCloud\Common\ServiceCatalogItem; - -/** - * The OpenStack class represents a relationship (or "connection") - * between a user and a service. - * - * This is the primary entry point into an OpenStack system, and the only one - * where the developer is required to know and provide the endpoint URL (in - * all other cases, the endpoint is derived from the Service Catalog provided - * by the authentication system). - * - * Since various providers have different mechanisms for authentication, users - * will often use a subclass of OpenStack. For example, the Rackspace - * class is provided for users of Rackspace's cloud services, and other cloud - * providers are welcome to add their own subclasses as well. - * - * General usage example: - * - * $username = 'My Username'; - * $secret = 'My Secret'; - * $connection = new OpenCloud\OpenStack($username, $secret); - * // having established the connection, we can set some defaults - * // this sets the default name and region of the Compute service - * $connection->SetDefaults('Compute', 'cloudServersOpenStack', 'ORD'); - * // access a Compute service - * $chicago = $connection->Compute(); - * // if we want to access a different service, we can: - * $dallas = $connection->Compute('cloudServersOpenStack', 'DFW'); - * - */ -class OpenStack extends Base -{ - - /** - * This holds the HTTP User-Agent: used for all requests to the services. It - * is public so that, if necessary, it can be entirely overridden by the - * developer. However, it's strongly recomended that you use the - * appendUserAgent() method to APPEND your own User Agent identifier to the - * end of this string; the user agent information can be very valuable to - * service providers to track who is using their service. - * - * @var string - */ - public $useragent = RAXSDK_USER_AGENT; - - protected $url; - protected $secret = array(); - protected $token; - protected $expiration = 0; - protected $tenant; - protected $catalog; - protected $connectTimeout = RAXSDK_CONNECTTIMEOUT; - protected $httpTimeout = RAXSDK_TIMEOUT; - protected $overlimitTimeout = RAXSDK_OVERLIMIT_TIMEOUT; - - /** - * This associative array holds default values used to identify each - * service (and to select it from the Service Catalog). Use the - * Compute::SetDefaults() method to change the default values, or - * define the global constants (for example, RAXSDK_COMPUTE_NAME) - * BEFORE loading the OpenCloud library: - * - * - * define('RAXSDK_COMPUTE_NAME', 'cloudServersOpenStack'); - * include('openstack.php'); - * - */ - protected $defaults = array( - 'Compute' => array( - 'name' => RAXSDK_COMPUTE_NAME, - 'region' => RAXSDK_COMPUTE_REGION, - 'urltype' => RAXSDK_COMPUTE_URLTYPE - ), - 'ObjectStore' => array( - 'name' => RAXSDK_OBJSTORE_NAME, - 'region' => RAXSDK_OBJSTORE_REGION, - 'urltype' => RAXSDK_OBJSTORE_URLTYPE - ), - 'Database' => array( - 'name' => RAXSDK_DATABASE_NAME, - 'region' => RAXSDK_DATABASE_REGION, - 'urltype' => RAXSDK_DATABASE_URLTYPE - ), - 'Volume' => array( - 'name' => RAXSDK_VOLUME_NAME, - 'region' => RAXSDK_VOLUME_REGION, - 'urltype' => RAXSDK_VOLUME_URLTYPE - ), - 'LoadBalancer' => array( - 'name' => RAXSDK_LBSERVICE_NAME, - 'region' => RAXSDK_LBSERVICE_REGION, - 'urltype' => RAXSDK_LBSERVICE_URLTYPE - ), - 'DNS' => array( - 'name' => RAXSDK_DNS_NAME, - 'region' => RAXSDK_DNS_REGION, - 'urltype' => RAXSDK_DNS_URLTYPE - ), - 'Orchestration' => array( - 'name' => RAXSDK_ORCHESTRATION_NAME, - 'region' => RAXSDK_ORCHESTRATION_REGION, - 'urltype' => RAXSDK_ORCHESTRATION_URLTYPE - ), - 'CloudMonitoring' => array( - 'name' => RAXSDK_MONITORING_NAME, - 'region' => RAXSDK_MONITORING_REGION, - 'urltype' => RAXSDK_MONITORING_URLTYPE - ), - 'Autoscale' => array( - 'name' => RAXSDK_AUTOSCALE_NAME, - 'region' => RAXSDK_AUTOSCALE_REGION, - 'urltype' => RAXSDK_AUTOSCALE_URLTYPE - ) - ); - - private $_user_write_progress_callback_func; - private $_user_read_progress_callback_func; - - /** - * Tracks file descriptors used by streaming downloads - * - * This will permit multiple simultaneous streaming downloads; the - * key is the URL of the object, and the value is its file descriptor. - * - * To prevent memory overflows, each array element is deleted when - * the end of the file is reached. - */ - private $fileDescriptors = array(); - - /** - * array of options to pass to the CURL request object - */ - private $curlOptions = array(); - - /** - * list of attributes to export/import - */ - private $exportItems = array( - 'token', - 'expiration', - 'tenant', - 'catalog' - ); - - /** - * Creates a new OpenStack object - * - * The OpenStack object needs two bits of information: the URL to - * authenticate against, and a "secret", which is an associative array - * of name/value pairs. Usually, the secret will be a username and a - * password, but other values may be required by different authentication - * systems. For example, OpenStack Keystone requires a username and - * password, but Rackspace uses a username, tenant ID, and API key. - * (See OpenCloud\Rackspace for that.) - * - * @param string $url - the authentication endpoint URL - * @param array $secret - an associative array of auth information: - * * username - * * password - * @param array $options - CURL options to pass to the HttpRequest object - */ - public function __construct($url, array $secret, array $options = array()) - { - // check for supported version - // @codeCoverageIgnoreStart - $version = phpversion(); - if ($version < '5.3.1') { - throw new Exceptions\UnsupportedVersionError(sprintf( - Lang::translate('PHP version [%s] is not supported'), - $version - )); - } - // @codeCoverageIgnoreEnd - - // Start processing - $this->getLogger()->info(Lang::translate('Initializing OpenStack client')); - - // Set properties - $this->setUrl($url); - $this->setSecret($secret); - $this->setCurlOptions($options); - } - - /** - * Set user agent. - * - * @param string $useragent - * @return OpenCloud\OpenStack - */ - public function setUserAgent($useragent) - { - $this->useragent = $useragent; - - return $this; - } - - /** - * Allows the user to append a user agent string - * - * Programs that are using these bindings are encouraged to add their - * user agent to the one supplied by this SDK. This will permit cloud - * providers to track users so that they can provide better service. - * - * @param string $agent an arbitrary user-agent string; e.g. "My Cloud App" - * @return OpenCloud\OpenStack - */ - public function appendUserAgent($useragent) - { - $this->useragent .= ';' . $useragent; - - return $this; - } - - /** - * Get user agent. - * - * @return string - */ - public function getUserAgent() - { - return $this->useragent; - } - - /** - * Sets the URL which the client will access. - * - * @param string $url - * @return OpenCloud\OpenStack - */ - public function setUrl($url) - { - $this->url = $url; - - return $this; - } - - /** - * Get the URL. - * - * @return string - */ - public function getUrl() - { - return $this->url; - } - - /** - * Set the secret for the client. - * - * @param array $secret - * @return OpenCloud\OpenStack - */ - public function setSecret(array $secret = array()) - { - $this->secret = $secret; - - return $this; - } - - /** - * Get the secret. - * - * @return array - */ - public function getSecret() - { - return $this->secret; - } - - /** - * Set the token for this client. - * - * @param string $token - * @return OpenCloud\OpenStack - */ - public function setToken($token) - { - $this->token = $token; - - return $this; - } - - /** - * Get the token for this client. - * - * @return string - */ - public function getToken() - { - return $this->token; - } - - /** - * Set the expiration for this token. - * - * @param int $expiration - * @return OpenCloud\OpenStack - */ - public function setExpiration($expiration) - { - $this->expiration = $expiration; - - return $this; - } - - /** - * Get the expiration time. - * - * @return int - */ - public function getExpiration() - { - return $this->expiration; - } - - /** - * Set the tenant for this client. - * - * @param string $tenant - * @return OpenCloud\OpenStack - */ - public function setTenant($tenant) - { - $this->tenant = $tenant; - - return $this; - } - - /** - * Get the tenant for this client. - * - * @return string - */ - public function getTenant() - { - return $this->tenant; - } - - /** - * Set the service catalog. - * - * @param mixed $catalog - * @return OpenCloud\OpenStack - */ - public function setCatalog($catalog) - { - $this->catalog = $catalog; - - return $this; - } - - /** - * Get the service catalog. - * - * @return array - */ - public function getCatalog() - { - return $this->catalog; - } - - /** - * Set (all) the cURL options. - * - * @param array $options - * @return OpenCloud\OpenStack - */ - public function setCurlOptions(array $options) - { - $this->curlOptions = $options; - - return $this; - } - - /** - * Get the cURL options. - * - * @return array - */ - public function getCurlOptions() - { - return $this->curlOptions; - } - - /** - * Set a specific file descriptor (associated with a URL) - * - * @param string $key - * @param resource $value - * @return OpenCloud\OpenStack - */ - public function setFileDescriptor($key, $value) - { - $this->descriptors[$key] = $value; - - return $this; - } - - /** - * Get a specific file descriptor (associated with a URL) - * - * @param string $key - * @return resource|false - */ - public function getFileDescriptor($key) - { - return (!isset($this->descriptors[$key])) ? false : $this->descriptors[$key]; - } - - /** - * Get the items to be exported. - * - * @return array - */ - public function getExportItems() - { - return $this->exportItems; - } - - /** - * Sets the connect timeout. - * - * @param int $timeout - * @return OpenCloud\OpenStack - */ - public function setConnectTimeout($timeout) - { - $this->connectTimeout = $timeout; - - return $this; - } - - /** - * Get the connect timeout. - * - * @return int - */ - public function getConnectTimeout() - { - return $this->connectTimeout; - } - - /** - * Set the HTTP timeout. - * - * @param int $timeout - * @return OpenCloud\OpenStack - */ - public function setHttpTimeout($timeout) - { - $this->httpTimeout = $timeout; - - return $this; - } - - /** - * Get the HTTP timeout. - * - * @return int - */ - public function getHttpTimeout() - { - return $this->httpTimeout; - } - - /** - * Set the overlimit timeout. - * - * @param int $timeout - * @return OpenCloud\OpenStack - */ - public function setOverlimitTimeout($timeout) - { - $this->overlimitTimeout = $timeout; - - return $this; - } - - /** - * Get the overlimit timeout. - * - * @return int - */ - public function getOverlimitTimeout() - { - return $this->overlimitTimeout; - } - - /** - * Sets default values (an array) for a service. Each array must contain a - * "name", "region" and "urltype" key. - * - * @param string $service - * @param array $value - * @return OpenCloud\OpenStack - */ - public function setDefault($service, array $value = array()) - { - if (isset($value['name']) && isset($value['region']) && isset($value['urltype'])) { - $this->defaults[$service] = $value; - } - - return $this; - } - - /** - * Get a specific default value for a service. If none exist, return FALSE. - * - * @param string $service - * @return array|false - */ - public function getDefault($service) - { - return (!isset($this->defaults[$service])) ? false : $this->defaults[$service]; - } - -/** - * Sets the timeouts for the current connection - * - * @api - * @param integer $t_http the HTTP timeout value (the max period that - * the OpenStack object will wait for any HTTP request to complete). - * Value is in seconds. - * @param integer $t_conn the Connect timeout value (the max period - * that the OpenStack object will wait to establish an HTTP - * connection). Value is in seconds. - * @param integer $t_overlimit the overlimit timeout value (the max period - * that the OpenStack object will wait to retry on an overlimit - * condition). Value is in seconds. - * @return void - */ - public function setTimeouts($httpTimeout, $connectTimeout = null, $overlimitTimeout = null) - { - $this->setHttpTimeout($httpTimeout); - - if (isset($connectTimeout)) { - $this->setConnectTimeout($connectTimeout); - } - - if (isset($overlimitTimeout)) { - $this->setOverlimitTimeout($overlimitTimeout); - } - } - - /** - * Returns the URL of this object - * - * @api - * @param string $subresource specified subresource - * @return string - */ - public function url($subresource='tokens') - { - return Lang::noslash($this->url) . '/' . $subresource; - } - - /** - * Returns the stored secret - * - * @return array - */ - public function secret() - { - return $this->getSecret(); - } - - /** - * Re-authenticates session if expired. - */ - public function checkExpiration() - { - if ($this->hasExpired()) { - $this->authenticate(); - } - } - - /** - * Checks whether token has expired. - * - * @return bool - */ - public function hasExpired() - { - return time() > ($this->getExpiration() - RAXSDK_FUDGE); - } - - /** - * Returns the cached token; if it has expired, then it re-authenticates - * - * @api - * @return string - */ - public function token() - { - $this->checkExpiration(); - - return $this->getToken(); - } - - /** - * Returns the cached expiration time; - * if it has expired, then it re-authenticates - * - * @api - * @return string - */ - public function expiration() - { - $this->checkExpiration(); - - return $this->getExpiration(); - } - - /** - * Returns the tenant ID, re-authenticating if necessary - * - * @api - * @return string - */ - public function tenant() - { - $this->checkExpiration(); - - return $this->getTenant(); - } - - /** - * Returns the service catalog object from the auth service - * - * @return \stdClass - */ - public function serviceCatalog() - { - $this->checkExpiration(); - - return $this->getCatalog(); - } - - /** - * Returns a Collection of objects with information on services - * - * Note that these are informational (read-only) and are not actually - * 'Service'-class objects. - */ - public function serviceList() - { - return new Common\Collection($this, 'ServiceCatalogItem', $this->serviceCatalog()); - } - - /** - * Creates and returns the formatted credentials to POST to the auth - * service. - * - * @return string - */ - public function credentials() - { - if (isset($this->secret['username']) && isset($this->secret['password'])) { - - $credentials = array( - 'auth' => array( - 'passwordCredentials' => array( - 'username' => $this->secret['username'], - 'password' => $this->secret['password'] - ) - ) - ); - - if (isset($this->secret['tenantName'])) { - $credentials['auth']['tenantName'] = $this->secret['tenantName']; - } - - return json_encode($credentials); - - } else { - throw new Exceptions\CredentialError( - Lang::translate('Unrecognized credential secret') - ); - } - } - - /** - * Authenticates using the supplied credentials - * - * @api - * @return void - * @throws AuthenticationError - */ - public function authenticate() - { - // try to auth - $response = $this->request( - $this->url(), - 'POST', - array('Content-Type'=>'application/json'), - $this->credentials() - ); - - $json = $response->httpBody(); - - // check for errors - if ($response->HttpStatus() >= 400) { - throw new Exceptions\AuthenticationError(sprintf( - Lang::translate('Authentication failure, status [%d], response [%s]'), - $response->httpStatus(), - $json - )); - } - - // Decode and check - $object = json_decode($json); - $this->checkJsonError(); - - // Save the token information as well as the ServiceCatalog - $this->setToken($object->access->token->id); - $this->setExpiration(strtotime($object->access->token->expires)); - $this->setCatalog($object->access->serviceCatalog); - - /** - * In some cases, the tenant name/id is not returned - * as part of the auth token, so we check for it before - * we set it. This occurs with pure Keystone, but not - * with the Rackspace auth. - */ - if (isset($object->access->token->tenant)) { - $this->setTenant($object->access->token->tenant->id); - } - } - - /** - * Performs a single HTTP request - * - * The request() method is one of the most frequently-used in the entire - * library. It performs an HTTP request using the specified URL, method, - * and with the supplied headers and body. It handles error and - * exceptions for the request. - * - * @api - * @param string url - the URL of the request - * @param string method - the HTTP method (defaults to GET) - * @param array headers - an associative array of headers - * @param string data - either a string or a resource (file pointer) to - * use as the request body (for PUT or POST) - * @return HttpResponse object - * @throws HttpOverLimitError, HttpUnauthorizedError, HttpForbiddenError - */ - public function request($url, $method = 'GET', $headers = array(), $data = null) - { - $this->getLogger()->info('Resource [{url}] method [{method}] body [{body}]', array( - 'url' => $url, - 'method' => $method, - 'data' => $data - )); - - // get the request object - $http = $this->getHttpRequestObject($url, $method, $this->getCurlOptions()); - - // set various options - $this->getLogger()->info('Headers: [{headers}]', array( - 'headers' => print_r($headers, true) - )); - - $http->setheaders($headers); - $http->setHttpTimeout($this->getHttpTimeout()); - $http->setConnectTimeout($this->getConnectTimeout()); - $http->setOption(CURLOPT_USERAGENT, $this->getUserAgent()); - - // data can be either a resource or a string - if (is_resource($data)) { - // loading from or writing to a file - // set the appropriate callback functions - switch($method) { - // @codeCoverageIgnoreStart - case 'GET': - // need to save the file descriptor - $this->setFileDescriptor($url, $data); - // set the CURL options - $http->setOption(CURLOPT_FILE, $data); - $http->setOption(CURLOPT_WRITEFUNCTION, array($this, '_write_cb')); - break; - // @codeCoverageIgnoreEnd - case 'PUT': - case 'POST': - // need to save the file descriptor - $this->setFileDescriptor($url, $data); - if (!isset($headers['Content-Length'])) { - throw new Exceptions\HttpError( - Lang::translate('The Content-Length: header must be specified for file uploads') - ); - } - $http->setOption(CURLOPT_UPLOAD, TRUE); - $http->setOption(CURLOPT_INFILE, $data); - $http->setOption(CURLOPT_INFILESIZE, $headers['Content-Length']); - $http->setOption(CURLOPT_READFUNCTION, array($this, '_read_cb')); - break; - default: - // do nothing - break; - } - } elseif (is_string($data)) { - $http->setOption(CURLOPT_POSTFIELDS, $data); - } elseif (isset($data)) { - throw new Exceptions\HttpError( - Lang::translate('Unrecognized data type for PUT/POST body, must be string or resource') - ); - } - - // perform the HTTP request; returns an HttpResult object - $response = $http->execute(); - - // handle and retry on overlimit errors - if ($response->httpStatus() == 413) { - - $object = json_decode($response->httpBody()); - $this->checkJsonError(); - - // @codeCoverageIgnoreStart - if (isset($object->overLimit)) { - /** - * @TODO(glen) - The documentation says "retryAt", but - * the field returned is "retryAfter". If the doc changes, - * then there's no problem, but we'll need to fix this if - * they change the code to match the docs. - */ - $retryAfter = $object->overLimit->retryAfter; - $sleepInterval = strtotime($retryAfter) - time(); - - if ($sleepInterval && $sleepInterval <= $this->getOverlimitTimeout()) { - sleep($sleepInterval); - $response = $http->Execute(); - } else { - throw new Exceptions\HttpOverLimitError(sprintf( - Lang::translate('Over limit; next available request [%s][%s] is not for [%d] seconds at [%s]'), - $method, - $url, - $sleepInterval, - $retryAfter - )); - } - } - // @codeCoverageIgnoreEnd - } - - // do some common error checking - switch ($response->httpStatus()) { - case 401: - throw new Exceptions\HttpUnauthorizedError(sprintf( - Lang::translate('401 Unauthorized for [%s] [%s]'), - $url, - $response->HttpBody() - )); - break; - case 403: - throw new Exceptions\HttpForbiddenError(sprintf( - Lang::translate('403 Forbidden for [%s] [%s]'), - $url, - $response->HttpBody() - )); - break; - case 413: // limit - throw new Exceptions\HttpOverLimitError(sprintf( - Lang::translate('413 Over limit for [%s] [%s]'), - $url, - $response->HttpBody() - )); - break; - default: - // everything is fine here, we're fine, how are you? - break; - } - - // free the handle - $http->close(); - - // return the HttpResponse object - $this->getLogger()->info('HTTP STATUS [{code}]', array( - 'code' => $response->httpStatus() - )); - - return $response; - } - - /** - * Sets default values for name, region, URL type for a service - * - * Once these are set (and they can also be set by defining global - * constants), then you do not need to specify these values when - * creating new service objects. - * - * @api - * @param string $service the name of a supported service; e.g. 'Compute' - * @param string $name the service name; e.g., 'cloudServersOpenStack' - * @param string $region the region name; e.g., 'LON' - * @param string $urltype the type of URL to use; e.g., 'internalURL' - * @return void - * @throws UnrecognizedServiceError - */ - public function setDefaults( - $service, - $name = null, - $region = null, - $urltype = null - ) { - - if (!isset($this->defaults[$service])) { - throw new Exceptions\UnrecognizedServiceError(sprintf( - Lang::translate('Service [%s] is not recognized'), $service - )); - } - - if (isset($name)) { - $this->defaults[$service]['name'] = $name; - } - - if (isset($region)) { - $this->defaults[$service]['region'] = $region; - } - - if (isset($urltype)) { - $this->defaults[$service]['urltype'] = $urltype; - } - } - - /** - * Allows the user to define a function for tracking uploads - * - * This can be used to implement a progress bar or similar function. The - * callback function is called with a single parameter, the length of the - * data that is being uploaded on this call. - * - * @param callable $callback the name of a global callback function, or an - * array($object, $functionname) - * @return void - */ - public function setUploadProgressCallback($callback) - { - $this->_user_write_progress_callback_func = $callback; - } - - /** - * Allows the user to define a function for tracking downloads - * - * This can be used to implement a progress bar or similar function. The - * callback function is called with a single parameter, the length of the - * data that is being downloaded on this call. - * - * @param callable $callback the name of a global callback function, or an - * array($object, $functionname) - * @return void - */ - public function setDownloadProgressCallback($callback) - { - $this->_user_read_progress_callback_func = $callback; - } - - /** - * Callback function to handle reads for file uploads - * - * Internal function for handling file uploads. Note that, although this - * function's visibility is public, this is only because it must be called - * from the HttpRequest interface. This should NOT be called by users - * directly. - * - * @param resource $ch a CURL handle - * @param resource $fd a file descriptor - * @param integer $length the amount of data to read - * @return string the data read - * @codeCoverageIgnore - */ - public function _read_cb($ch, $fd, $length) - { - $data = fread($fd, $length); - $len = strlen($data); - if (isset($this->_user_write_progress_callback_func)) { - call_user_func($this->_user_write_progress_callback_func, $len); - } - return $data; - } - - /** - * Callback function to handle writes for file downloads - * - * Internal function for handling file downloads. Note that, although this - * function's visibility is public, this is only because it must be called - * via the HttpRequest interface. This should NOT be called by users - * directly. - * - * @param resource $ch a CURL handle - * @param string $data the data to be written to a file - * @return integer the number of bytes written - * @codeCoverageIgnore - */ - public function _write_cb($ch, $data) - { - $url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); - - if (false === ($fp = $this->getFileDescriptor($url))) { - throw new Exceptions\HttpUrlError(sprintf( - Lang::translate('Cannot find file descriptor for URL [%s]'), $url) - ); - } - - $dlen = strlen($data); - fwrite($fp, $data, $dlen); - - // call used callback function - if (isset($this->_user_read_progress_callback_func)) { - call_user_func($this->_user_read_progress_callback_func, $dlen); - } - - // MUST return the length to CURL - return $dlen; - } - - /** - * exports saved token, expiration, tenant, and service catalog as an array - * - * This could be stored in a cache (APC or disk file) and reloaded using - * ImportCredentials() - * - * @return array - */ - public function exportCredentials() - { - $this->authenticate(); - - $array = array(); - - foreach ($this->getExportItems() as $key) { - $array[$key] = $this->$key; - } - - return $array; - } - - /** - * imports credentials from an array - * - * Takes the same values as ExportCredentials() and reuses them. - * - * @return void - */ - public function importCredentials(array $values) - { - foreach ($this->getExportItems() as $item) { - $this->$item = $values[$item]; - } - } - - /********** FACTORY METHODS ********** - * - * These methods are provided to permit easy creation of services - * (for example, Nova or Swift) from a connection object. As new - * services are supported, factory methods should be provided here. - */ - - /** - * Creates a new ObjectStore object (Swift/Cloud Files) - * - * @api - * @param string $name the name of the Object Storage service to attach to - * @param string $region the name of the region to use - * @param string $urltype the URL type (normally "publicURL") - * @return ObjectStore - */ - public function objectStore($name = null, $region = null, $urltype = null) - { - return $this->service('ObjectStore', $name, $region, $urltype); - } - - /** - * Creates a new Compute object (Nova/Cloud Servers) - * - * @api - * @param string $name the name of the Compute service to attach to - * @param string $region the name of the region to use - * @param string $urltype the URL type (normally "publicURL") - * @return Compute - */ - public function compute($name = null, $region = null, $urltype = null) - { - return $this->service('Compute', $name, $region, $urltype); - } - - /** - * Creates a new Orchestration (heat) service object - * - * @api - * @param string $name the name of the Compute service to attach to - * @param string $region the name of the region to use - * @param string $urltype the URL type (normally "publicURL") - * @return Orchestration\Service - * @codeCoverageIgnore - */ - public function orchestration($name = null, $region = null, $urltype = null) - { - return $this->service('Orchestration', $name, $region, $urltype); - } - - /** - * Creates a new VolumeService (cinder) service object - * - * This is a factory method that is Rackspace-only (NOT part of OpenStack). - * - * @param string $name the name of the service (e.g., 'cloudBlockStorage') - * @param string $region the region (e.g., 'DFW') - * @param string $urltype the type of URL (e.g., 'publicURL'); - */ - public function volumeService($name = null, $region = null, $urltype = null) - { - return $this->service('Volume', $name, $region, $urltype); - } - - /** - * Generic Service factory method - * - * Contains code reused by the other service factory methods. - * - * @param string $class the name of the Service class to produce - * @param string $name the name of the Compute service to attach to - * @param string $region the name of the region to use - * @param string $urltype the URL type (normally "publicURL") - * @return Service (or subclass such as Compute, ObjectStore) - * @throws ServiceValueError - */ - public function service($class, $name = null, $region = null, $urltype = null) - { - // debug message - $this->getLogger()->info('Factory for class [{class}] [{name}/{region}/{urlType}]', array( - 'class' => $class, - 'name' => $name, - 'region' => $region, - 'urlType' => $urltype - )); - - // Strips off base namespace - $class = preg_replace('#\\\?OpenCloud\\\#', '', $class); - - // check for defaults - $default = $this->getDefault($class); - - // report errors - if (!$name = $name ?: $default['name']) { - throw new Exceptions\ServiceValueError(sprintf( - Lang::translate('No value for %s name'), - $class - )); - } - - if (!$region = $region ?: $default['region']) { - throw new Exceptions\ServiceValueError(sprintf( - Lang::translate('No value for %s region'), - $class - )); - } - - if (!$urltype = $urltype ?: $default['urltype']) { - throw new Exceptions\ServiceValueError(sprintf( - Lang::translate('No value for %s URL type'), - $class - )); - } - - // return the object - $fullclass = 'OpenCloud\\' . $class . '\\Service'; - - return new $fullclass($this, $name, $region, $urltype); - } - - /** - * returns a service catalog item - * - * This is a helper function used to list service catalog items easily - */ - public function serviceCatalogItem($info = array()) - { - return new ServiceCatalogItem($info); - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Rackspace.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Rackspace.php deleted file mode 100644 index 41be608b34..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Rackspace.php +++ /dev/null @@ -1,132 +0,0 @@ - - */ - -namespace OpenCloud; - -/** - * Rackspace extends the OpenStack class with support for Rackspace's - * API key and tenant requirements. - * - * The only difference between Rackspace and OpenStack is that the - * Rackspace class generates credentials using the username - * and API key, as required by the Rackspace authentication - * service. - * - * Example: - * - * $username = 'FRED'; - * $apiKey = '0900af093093788912388fc09dde090ffee09'; - * $conn = new Rackspace( - * 'https://identity.api.rackspacecloud.com/v2.0/', - * array( - * 'username' => $username, - * 'apiKey' => $apiKey - * )); - * - */ -class Rackspace extends OpenStack -{ - - //this is the JSON string for our new credentials -const APIKEYTEMPLATE = <<Secret(); - if (isset($sec['username']) - && isset($sec['apiKey']) - ) { - return sprintf( - self::APIKEYTEMPLATE, - $sec['username'], - $sec['apiKey'] - ); - } else { - return parent::Credentials(); - } - } - - /** - * Creates a new DbService (Database as a Service) object - * - * This is a factory method that is Rackspace-only (NOT part of OpenStack). - * - * @param string $name the name of the service (e.g., 'Cloud Databases') - * @param string $region the region (e.g., 'DFW') - * @param string $urltype the type of URL (e.g., 'publicURL'); - */ - public function DbService($name = null, $region = null, $urltype = null) - { - return $this->Service('Database', $name, $region, $urltype); - } - - /** - * Creates a new LoadBalancerService object - * - * This is a factory method that is Rackspace-only (NOT part of OpenStack). - * - * @param string $name the name of the service - * (e.g., 'Cloud Load Balancers') - * @param string $region the region (e.g., 'DFW') - * @param string $urltype the type of URL (e.g., 'publicURL'); - */ - public function LoadBalancerService($name = null, $region = null, $urltype = null) - { - return $this->Service('LoadBalancer', $name, $region, $urltype); - } - - /** - * creates a new DNS service object - * - * This is a factory method that is currently Rackspace-only - * (not available via the OpenStack class) - */ - public function DNS($name = null, $region = null, $urltype = null) - { - return $this->Service('DNS', $name, $region, $urltype); - } - - /** - * creates a new CloudMonitoring service object - * - * This is a factory method that is currently Rackspace-only - * (not available via the OpenStack class) - */ - public function CloudMonitoring($name=null, $region=null, $urltype=null) - { - return $this->Service('CloudMonitoring', $name, $region, $urltype); - } - - /** - * creates a new Autoscale service object - * - * This is a factory method that is currently Rackspace-only - * (not available via the OpenStack class) - */ - public function Autoscale($name=null, $region=null, $urltype=null) - { - return $this->Service('Autoscale', $name, $region, $urltype); - } - -} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/openstack.php b/apps/files_external/3rdparty/php-opencloud/lib/openstack.php deleted file mode 100644 index 738902d244..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/openstack.php +++ /dev/null @@ -1,8 +0,0 @@ -registerNamespaces(array( - 'OpenCloud' => array(__DIR__, __DIR__ . '/../tests') -)); -$classLoader->register(); \ No newline at end of file diff --git a/apps/files_external/3rdparty/php-opencloud/lib/rackspace.php b/apps/files_external/3rdparty/php-opencloud/lib/rackspace.php deleted file mode 100644 index 738902d244..0000000000 --- a/apps/files_external/3rdparty/php-opencloud/lib/rackspace.php +++ /dev/null @@ -1,8 +0,0 @@ - $options) { + if (isset($options['options']['objectstore'])) { + $objectClass = $options['options']['objectstore']['class']; + $options['options']['objectstore'] = new $objectClass($options['options']['objectstore']); + } if ($options['personal']){ $mount = new \OCA\Files_External\PersonalMount($options['class'], $mountPoint, $options['options'], $loader); } else{ diff --git a/apps/files_external/lib/swift.php b/apps/files_external/lib/swift.php index 03364867b0..47ab329467 100644 --- a/apps/files_external/lib/swift.php +++ b/apps/files_external/lib/swift.php @@ -22,21 +22,21 @@ namespace OC\Files\Storage; -set_include_path(get_include_path() . PATH_SEPARATOR . - \OC_App::getAppPath('files_external') . '/3rdparty/php-opencloud/lib'); -require_once 'openstack.php'; - -use \OpenCloud; -use \OpenCloud\Common\Exceptions; +use Guzzle\Http\Exception\ClientErrorResponseException; +use OpenCloud; +use OpenCloud\Common\Exceptions; +use OpenCloud\OpenStack; +use OpenCloud\ObjectStore\Resource\DataObject; +use OpenCloud\ObjectStore\Exception; class Swift extends \OC\Files\Storage\Common { /** - * @var \OpenCloud\ObjectStore + * @var \OpenCloud\ObjectStore\Service */ private $connection; /** - * @var \OpenCloud\ObjectStore\Container + * @var \OpenCloud\ObjectStore\Resource\Container */ private $container; /** @@ -62,6 +62,8 @@ class Swift extends \OC\Files\Storage\Common { $path = '.'; } + $path = str_replace('#', '%23', $path); + return $path; } @@ -82,12 +84,9 @@ class Swift extends \OC\Files\Storage\Common { */ private function doesObjectExist($path) { try { - $object = $this->container->DataObject($path); + $this->container->getPartialObject($path); return true; - } catch (Exceptions\ObjFetchError $e) { - \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); - return false; - } catch (Exceptions\HttpError $e) { + } catch (ClientErrorResponseException $e) { \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; } @@ -113,7 +112,6 @@ class Swift extends \OC\Files\Storage\Common { $settings = array( 'username' => $params['user'], - ); if (isset($params['password'])) { @@ -126,19 +124,18 @@ class Swift extends \OC\Files\Storage\Common { $settings['tenantName'] = $params['tenant']; } - $this->anchor = new \OpenCloud\OpenStack($params['url'], $settings); - if (isset($params['timeout'])) { - $this->anchor->setHttpTimeout($params['timeout']); + $settings['timeout'] = $params['timeout']; } - $this->connection = $this->anchor->ObjectStore($params['service_name'], $params['region'], 'publicURL'); + $this->anchor = new OpenStack($params['url'], $settings); + + $this->connection = $this->anchor->objectStoreService($params['service_name'], $params['region']); try { - $this->container = $this->connection->Container($this->bucket); - } catch (Exceptions\ContainerNotFoundError $e) { - $this->container = $this->connection->Container(); - $this->container->Create(array('name' => $this->bucket)); + $this->container = $this->connection->getContainer($this->bucket); + } catch (ClientErrorResponseException $e) { + $this->container = $this->connection->createContainer($this->bucket); } if (!$this->file_exists('.')) { @@ -158,11 +155,10 @@ class Swift extends \OC\Files\Storage\Common { } try { - $object = $this->container->DataObject(); - $object->Create(array( - 'name' => $path, - 'content_type' => 'httpd/unix-directory' - )); + $customHeaders = array('content-type' => 'httpd/unix-directory'); + $metadataHeaders = DataObject::stockHeaders(array()); + $allHeaders = $customHeaders + $metadataHeaders; + $this->container->uploadObject($path, '', $allHeaders); } catch (Exceptions\CreateUpdateError $e) { \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; @@ -202,8 +198,7 @@ class Swift extends \OC\Files\Storage\Common { } try { - $object = $this->container->DataObject($path . '/'); - $object->Delete(); + $this->container->dataObject()->setName($path . '/')->delete(); } catch (Exceptions\DeleteError $e) { \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; @@ -221,15 +216,19 @@ class Swift extends \OC\Files\Storage\Common { $path .= '/'; } + $path = str_replace('%23', '#', $path); // the prefix is sent as a query param, so revert the encoding of # + try { $files = array(); - $objects = $this->container->ObjectList(array( + /** @var OpenCloud\Common\Collection $objects */ + $objects = $this->container->objectList(array( 'prefix' => $path, 'delimiter' => '/' )); - while ($object = $objects->Next()) { - $file = basename($object->Name()); + /** @var OpenCloud\ObjectStore\Resource\DataObject $object */ + foreach ($objects as $object) { + $file = basename($object->getName()); if ($file !== basename($path)) { $files[] = $file; } @@ -252,15 +251,22 @@ class Swift extends \OC\Files\Storage\Common { } try { - $object = $this->container->DataObject($path); - } catch (Exceptions\ObjFetchError $e) { + $object = $this->container->getPartialObject($path); + } catch (ClientErrorResponseException $e) { \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; } - $mtime = $object->extra_headers['X-Timestamp']; - if (isset($object->extra_headers['X-Object-Meta-Timestamp'])) { - $mtime = $object->extra_headers['X-Object-Meta-Timestamp']; + $dateTime = \DateTime::createFromFormat(\DateTime::RFC1123, $object->getLastModified()); + if ($dateTime !== false) { + $mtime = $dateTime->getTimestamp(); + } else { + $mtime = null; + } + $objectMetadata = $object->getMetadata(); + $metaTimestamp = $objectMetadata->getProperty('timestamp'); + if (isset($metaTimestamp)) { + $mtime = $metaTimestamp; } if (!empty($mtime)) { @@ -268,7 +274,7 @@ class Swift extends \OC\Files\Storage\Common { } $stat = array(); - $stat['size'] = $object->content_length; + $stat['size'] = (int) $object->getContentLength(); $stat['mtime'] = $mtime; $stat['atime'] = time(); return $stat; @@ -293,13 +299,13 @@ class Swift extends \OC\Files\Storage\Common { public function unlink($path) { $path = $this->normalizePath($path); + if ($this->is_dir($path)) { + return $this->rmdir($path); + } + try { - $object = $this->container->DataObject($path); - $object->Delete(); - } catch (Exceptions\DeleteError $e) { - \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); - return false; - } catch (Exceptions\ObjFetchError $e) { + $this->container->dataObject()->setName($path)->delete(); + } catch (ClientErrorResponseException $e) { \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; } @@ -316,13 +322,19 @@ class Swift extends \OC\Files\Storage\Common { $tmpFile = \OC_Helper::tmpFile(); self::$tmpFiles[$tmpFile] = $path; try { - $object = $this->container->DataObject($path); - } catch (Exceptions\ObjFetchError $e) { + $object = $this->container->getObject($path); + } catch (ClientErrorResponseException $e) { + \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); + return false; + } catch (Exception\ObjectNotFoundException $e) { \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; } try { - $object->SaveToFilename($tmpFile); + $objectContent = $object->getContent(); + $objectContent->rewind(); + $stream = $objectContent->getStream(); + file_put_contents($tmpFile, $stream); } catch (Exceptions\IOError $e) { \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; @@ -363,43 +375,32 @@ class Swift extends \OC\Files\Storage\Common { if ($this->is_dir($path)) { return 'httpd/unix-directory'; } else if ($this->file_exists($path)) { - $object = $this->container->DataObject($path); - return $object->extra_headers["Content-Type"]; + $object = $this->container->getPartialObject($path); + return $object->getContentType(); } return false; } public function touch($path, $mtime = null) { $path = $this->normalizePath($path); + if (is_null($mtime)) { + $mtime = time(); + } + $metadata = array('timestamp' => $mtime); if ($this->file_exists($path)) { if ($this->is_dir($path) && $path != '.') { $path .= '/'; } - $object = $this->container->DataObject($path); - if( is_null($mtime)) { - $mtime = time(); - } - $settings = array( - 'name' => $path, - 'extra_headers' => array( - 'X-Object-Meta-Timestamp' => $mtime - ) - ); - return $object->UpdateMetadata($settings); + $object = $this->container->getPartialObject($path); + $object->saveMetadata($metadata); + return true; } else { - $object = $this->container->DataObject(); - if (is_null($mtime)) { - $mtime = time(); - } - $settings = array( - 'name' => $path, - 'content_type' => 'text/plain', - 'extra_headers' => array( - 'X-Object-Meta-Timestamp' => $mtime - ) - ); - return $object->Create($settings); + $customHeaders = array('content-type' => 'text/plain'); + $metadataHeaders = DataObject::stockHeaders($metadata); + $allHeaders = $customHeaders + $metadataHeaders; + $this->container->uploadObject($path, '', $allHeaders); + return true; } } @@ -407,31 +408,29 @@ class Swift extends \OC\Files\Storage\Common { $path1 = $this->normalizePath($path1); $path2 = $this->normalizePath($path2); - if ($this->is_file($path1)) { + $fileType = $this->filetype($path1); + if ($fileType === 'file') { + + // make way + $this->unlink($path2); + try { - $source = $this->container->DataObject($path1); - $target = $this->container->DataObject(); - $target->Create(array( - 'name' => $path2, - )); - $source->Copy($target); - } catch (Exceptions\ObjectCopyError $e) { + $source = $this->container->getPartialObject($path1); + $source->copy($this->bucket.'/'.$path2); + } catch (ClientErrorResponseException $e) { \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; } - } else { - if ($this->file_exists($path2)) { - return false; - } + + } else if ($fileType === 'dir') { + + // make way + $this->unlink($path2); try { - $source = $this->container->DataObject($path1 . '/'); - $target = $this->container->DataObject(); - $target->Create(array( - 'name' => $path2 . '/', - )); - $source->Copy($target); - } catch (Exceptions\ObjectCopyError $e) { + $source = $this->container->getPartialObject($path1 . '/'); + $source->copy($this->bucket.'/'.$path2 . '/'); + } catch (ClientErrorResponseException $e) { \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; } @@ -446,6 +445,10 @@ class Swift extends \OC\Files\Storage\Common { $target = $path2 . '/' . $file; $this->copy($source, $target); } + + } else { + //file does not exist + return false; } return true; @@ -455,31 +458,28 @@ class Swift extends \OC\Files\Storage\Common { $path1 = $this->normalizePath($path1); $path2 = $this->normalizePath($path2); - if ($this->is_file($path1)) { + $fileType = $this->filetype($path1); + + if ($fileType === 'dir' || $fileType === 'file') { + + // make way + $this->unlink($path2); + + // copy if ($this->copy($path1, $path2) === false) { return false; } + // cleanup if ($this->unlink($path1) === false) { $this->unlink($path2); return false; } - } else { - if ($this->file_exists($path2)) { - return false; - } - if ($this->copy($path1, $path2) === false) { - return false; - } - - if ($this->rmdir($path1) === false) { - $this->rmdir($path2); - return false; - } + return true; } - return true; + return false; } public function getId() { @@ -494,12 +494,8 @@ class Swift extends \OC\Files\Storage\Common { if (!isset(self::$tmpFiles[$tmpFile])) { return false; } - - $object = $this->container->DataObject(); - $object->Create(array( - 'name' => self::$tmpFiles[$tmpFile], - 'content_type' => \OC_Helper::getMimeType($tmpFile) - ), $tmpFile); + $fileData = fopen($tmpFile, 'r'); + $this->container->uploadObject(self::$tmpFiles[$tmpFile], $fileData); unlink($tmpFile); } diff --git a/apps/files_external/tests/swift.php b/apps/files_external/tests/swift.php index bdfdbdeebe..3918497ebf 100644 --- a/apps/files_external/tests/swift.php +++ b/apps/files_external/tests/swift.php @@ -38,14 +38,15 @@ class Swift extends Storage { public function tearDown() { if ($this->instance) { $connection = $this->instance->getConnection(); - $container = $connection->Container($this->config['swift']['bucket']); + $container = $connection->getContainer($this->config['swift']['bucket']); - $objects = $container->ObjectList(); - while($object = $objects->Next()) { - $object->Delete(); + $objects = $container->objectList(); + while($object = $objects->next()) { + $object->setName(str_replace('#','%23',$object->getName())); + $object->delete(); } - $container->Delete(); + $container->delete(); } } } diff --git a/config/config.sample.php b/config/config.sample.php index 6da00fc12a..59e1f3890c 100755 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -304,4 +304,32 @@ $CONFIG = array( /* If true, prevent owncloud from changing the cache due to changes in the filesystem for all storage */ 'filesystem_cache_readonly' => false, + +/* + * The example below shows how to configure ownCloud to store all files in a swift object storage + * + * It is important to note that ownCloud in object store mode will expect exclusive access + * to the object store container because it only stores the binary data for each file. The + * metadata is currently kept in the local database for performance reasons. + * + * WARNING: The current implementation is incompatible with any app that uses direct file IO and circumvents our + * virtual filesystem. That includes Encryption and Gallery. Gallery will store thumbnails directly in the filesystem + * and encryption will cause severe overhead because key files need to be fetched in addition to any requested file. + * + * One way to test is applying for a trystack account at http://trystack.org/ + */ +'objectstore' => array( + 'class' => 'OC\\Files\\ObjectStore\\Swift', + 'arguments' => array( + 'username' => 'facebook100000123456789', // trystack will user your facebook id as the user name + 'password' => 'Secr3tPaSSWoRdt7', // in the trystack dashboard go to user -> settings -> API Password to generate a password + 'container' => 'owncloud', // must already exist in the objectstore, name can be different + 'autocreate' => true, // create the container if it does not exist. default is false + 'region' => 'RegionOne', //required, dev-/trystack defaults to 'RegionOne' + 'url' => 'http://8.21.28.222:5000/v2.0', // The Identity / Keystone endpoint + 'tenantName' => 'facebook100000123456789', // required on dev-/trystack + 'serviceName' => 'swift', //dev-/trystack uses swift by default, the lib defaults to 'cloudFiles' if omitted + ), +), + ); diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php index 2cc4a2130e..4774d25ad9 100644 --- a/lib/private/files/filesystem.php +++ b/lib/private/files/filesystem.php @@ -325,13 +325,36 @@ class Filesystem { $userObject = \OC_User::getManager()->get($user); if (!is_null($userObject)) { + $homeStorage = \OC_Config::getValue( 'objectstore' ); + if (!empty($homeStorage)) { + // sanity checks + if (empty($homeStorage['class'])) { + \OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR); + } + if (!isset($homeStorage['arguments'])) { + $homeStorage['arguments'] = array(); + } + // instantiate object store implementation + $homeStorage['arguments']['objectstore'] = new $homeStorage['class']($homeStorage['arguments']); + // mount with home object store implementation + $homeStorage['class'] = '\OC\Files\ObjectStore\HomeObjectStoreStorage'; + } else { + $homeStorage = array( + //default home storage configuration: + 'class' => '\OC\Files\Storage\Home', + 'arguments' => array() + ); + } + $homeStorage['arguments']['user'] = $userObject; + // check for legacy home id (<= 5.0.12) if (\OC\Files\Cache\Storage::exists('local::' . $root . '/')) { - self::mount('\OC\Files\Storage\Home', array('user' => $userObject, 'legacy' => true), $user); - } - else { - self::mount('\OC\Files\Storage\Home', array('user' => $userObject), $user); + $homeStorage['arguments']['legacy'] = true; } + + self::mount($homeStorage['class'], $homeStorage['arguments'], $user); + + $home = \OC\Files\Filesystem::getStorage($user); } else { self::mount('\OC\Files\Storage\Local', array('datadir' => $root), $user); diff --git a/lib/private/files/mount/mount.php b/lib/private/files/mount/mount.php index 04bccbcab8..48c9d88c23 100644 --- a/lib/private/files/mount/mount.php +++ b/lib/private/files/mount/mount.php @@ -93,7 +93,12 @@ class Mount { try { return $this->loader->load($this->mountPoint, $this->class, $this->arguments); } catch (\Exception $exception) { - \OC_Log::write('core', $exception->getMessage(), \OC_Log::ERROR); + if ($this->mountPoint === '/') { + // the root storage could not be initialized, show the user! + throw new \Exception('The root storage could not be initialized. Please contact your local administrator.', $exception->getCode(), $exception); + } else { + \OC_Log::write('core', $exception->getMessage(), \OC_Log::ERROR); + } return null; } } else { diff --git a/lib/private/files/objectstore/homeobjectstorestorage.php b/lib/private/files/objectstore/homeobjectstorestorage.php new file mode 100644 index 0000000000..26a2788d86 --- /dev/null +++ b/lib/private/files/objectstore/homeobjectstorestorage.php @@ -0,0 +1,71 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +namespace OC\Files\ObjectStore; + +use OC\User\User; + +class HomeObjectStoreStorage extends ObjectStoreStorage { + + /** + * The home user storage requires a user object to create a unique storage id + * @param array $params + */ + public function __construct($params) { + if ( ! isset($params['user']) || ! $params['user'] instanceof User) { + throw new \Exception('missing user object in parameters'); + } + $this->user = $params['user']; + parent::__construct($params); + + + //initialize cache with root directory in cache + if ( ! $this->is_dir('files') ) { + $this->mkdir('files'); + } + } + + public function getId () { + return 'object::user:' . $this->user->getUID(); + } + + /** + * get the owner of a path + * + * @param string $path The path to get the owner + * @return false|string uid + */ + public function getOwner($path) { + if (is_object($this->user)) { + return $this->user->getUID(); + } + return false; + } + + /** + * @param string $path, optional + * @return \OC\User\User + */ + public function getUser($path = null) { + return $this->user; + } + + +} \ No newline at end of file diff --git a/lib/private/files/objectstore/noopscanner.php b/lib/private/files/objectstore/noopscanner.php new file mode 100644 index 0000000000..59ca177197 --- /dev/null +++ b/lib/private/files/objectstore/noopscanner.php @@ -0,0 +1,74 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +namespace OC\Files\ObjectStore; +use \OC\Files\Cache\Scanner; +use \OC\Files\Storage\Storage; + +class NoopScanner extends Scanner { + + public function __construct(Storage $storage) { + //we don't need the storage, so do nothing here + } + + /** + * scan a single file and store it in the cache + * + * @param string $file + * @param int $reuseExisting + * @param bool $parentExistsInCache + * @return array with metadata of the scanned file + */ + public function scanFile($file, $reuseExisting = 0, $parentExistsInCache = false) { + return array(); + } + + /** + * scan a folder and all it's children + * + * @param string $path + * @param bool $recursive + * @param int $reuse + * @return array with the meta data of the scanned file or folder + */ + public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1) { + return array(); + } + + /** + * scan all the files and folders in a folder + * + * @param string $path + * @param bool $recursive + * @param int $reuse + * @return int the size of the scanned folder or -1 if the size is unknown at this stage + */ + public function scanChildren($path, $recursive = Storage::SCAN_RECURSIVE, $reuse = -1) { + $size = 0; + return $size; + } + + /** + * walk over any folders that are not fully scanned yet and scan them + */ + public function backgroundScan() { + //noop + } +} diff --git a/lib/private/files/objectstore/objectstorestorage.php b/lib/private/files/objectstore/objectstorestorage.php new file mode 100644 index 0000000000..85f43b90cb --- /dev/null +++ b/lib/private/files/objectstore/objectstorestorage.php @@ -0,0 +1,421 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +namespace OC\Files\ObjectStore; + +use OC\Files\Filesystem; +use OCP\Files\ObjectStore\IObjectStore; + +class ObjectStoreStorage extends \OC\Files\Storage\Common { + + /** + * @var array + */ + private static $tmpFiles = array(); + /** + * @var \OCP\Files\ObjectStore\IObjectStore $objectStore + */ + protected $objectStore; + /** + * @var \OC\User\User $user + */ + protected $user; + + public function __construct($params) { + if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) { + $this->objectStore = $params['objectstore']; + } else { + throw new \Exception('missing IObjectStore instance'); + } + if (isset($params['storageid'])) { + $this->id = 'object::store:' . $params['storageid']; + } else { + $this->id = 'object::store:' . $this->objectStore->getStorageId(); + } + //initialize cache with root directory in cache + if (!$this->is_dir('/')) { + $this->mkdir('/'); + } + } + + public function mkdir($path) { + $path = $this->normalizePath($path); + + if ($this->is_dir($path)) { + return false; + } + + $dirName = $this->normalizePath(dirname($path)); + $parentExists = $this->is_dir($dirName); + + $mTime = time(); + + $data = array( + 'mimetype' => 'httpd/unix-directory', + 'size' => 0, + 'mtime' => $mTime, + 'storage_mtime' => $mTime, + 'permissions' => \OCP\PERMISSION_ALL, + ); + + if ($dirName === '' && !$parentExists) { + //create root on the fly + $data['etag'] = $this->getETag(''); + $this->getCache()->put('', $data); + $parentExists = true; + + // we are done when the root folder was meant to be created + if ($dirName === $path) { + return true; + } + } + + if ($parentExists) { + $data['etag'] = $this->getETag($path); + $this->getCache()->put($path, $data); + return true; + } + return false; + } + + /** + * @param string $path + * @return string + */ + private function normalizePath($path) { + $path = trim($path, '/'); + //FIXME why do we sometimes get a path like 'files//username'? + $path = str_replace('//', '/', $path); + + // dirname('/folder') returns '.' but internally (in the cache) we store the root as '' + if (!$path || $path === '.') { + $path = ''; + } + + return $path; + } + + /** + * Object Stores use a NoopScanner because metadata is directly stored in + * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere. + * + * @param string $path + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner + * @return \OC\Files\ObjectStore\NoopScanner + */ + public function getScanner($path = '', $storage = null) { + if (!$storage) { + $storage = $this; + } + if (!isset($this->scanner)) { + $this->scanner = new NoopScanner($storage); + } + return $this->scanner; + } + + public function getId() { + return $this->id; + } + + public function rmdir($path) { + $path = $this->normalizePath($path); + + if (!$this->is_dir($path)) { + return false; + } + + $this->rmObjects($path); + + $this->getCache()->remove($path); + + return true; + } + + private function rmObjects($path) { + $children = $this->getCache()->getFolderContents($path); + foreach ($children as $child) { + if ($child['mimetype'] === 'httpd/unix-directory') { + $this->rmObjects($child['path']); + } else { + $this->unlink($child['path']); + } + } + } + + public function unlink($path) { + $path = $this->normalizePath($path); + $stat = $this->stat($path); + + if ($stat && isset($stat['fileid'])) { + if ($stat['mimetype'] === 'httpd/unix-directory') { + return $this->rmdir($path); + } + try { + $this->objectStore->deleteObject($this->getURN($stat['fileid'])); + } catch (\Exception $ex) { + if ($ex->getCode() !== 404) { + \OCP\Util::writeLog('objectstore', 'Could not delete object: ' . $ex->getMessage(), \OCP\Util::ERROR); + return false; + } else { + //removing from cache is ok as it does not exist in the objectstore anyway + } + } + $this->getCache()->remove($path); + return true; + } + return false; + } + + public function stat($path) { + $path = $this->normalizePath($path); + return $this->getCache()->get($path); + } + + /** + * Override this method if you need a different unique resource identifier for your object storage implementation. + * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users. + * You may need a mapping table to store your URN if it cannot be generated from the fileid. + * + * @param int $fileId the fileid + * @return null|string the unified resource name used to identify the object + */ + protected function getURN($fileId) { + if (is_numeric($fileId)) { + return 'urn:oid:' . $fileId; + } + return null; + } + + public function opendir($path) { + $path = $this->normalizePath($path); + + try { + $files = array(); + $folderContents = $this->getCache()->getFolderContents($path); + foreach ($folderContents as $file) { + $files[] = $file['name']; + } + + \OC\Files\Stream\Dir::register('objectstore' . $path . '/', $files); + + return opendir('fakedir://objectstore' . $path . '/'); + } catch (Exception $e) { + \OCP\Util::writeLog('objectstore', $e->getMessage(), \OCP\Util::ERROR); + return false; + } + } + + public function filetype($path) { + $path = $this->normalizePath($path); + $stat = $this->stat($path); + if ($stat) { + if ($stat['mimetype'] === 'httpd/unix-directory') { + return 'dir'; + } + return 'file'; + } else { + return false; + } + } + + public function fopen($path, $mode) { + $path = $this->normalizePath($path); + + switch ($mode) { + case 'r': + case 'rb': + $stat = $this->stat($path); + if (is_array($stat)) { + try { + return $this->objectStore->readObject($this->getURN($stat['fileid'])); + } catch (\Exception $ex) { + \OCP\Util::writeLog('objectstore', 'Could not get object: ' . $ex->getMessage(), \OCP\Util::ERROR); + return false; + } + } else { + return false; + } + case 'w': + case 'wb': + case 'a': + case 'ab': + case 'r+': + case 'w+': + case 'wb+': + case 'a+': + case 'x': + case 'x+': + case 'c': + case 'c+': + if (strrpos($path, '.') !== false) { + $ext = substr($path, strrpos($path, '.')); + } else { + $ext = ''; + } + $tmpFile = \OC_Helper::tmpFile($ext); + \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); + if ($this->file_exists($path)) { + $source = $this->fopen($path, 'r'); + file_put_contents($tmpFile, $source); + } + self::$tmpFiles[$tmpFile] = $path; + + return fopen('close://' . $tmpFile, $mode); + } + return false; + } + + public function file_exists($path) { + $path = $this->normalizePath($path); + return (bool)$this->stat($path); + } + + public function rename($source, $target) { + $source = $this->normalizePath($source); + $target = $this->normalizePath($target); + $stat1 = $this->stat($source); + if (isset($stat1['mimetype']) && $stat1['mimetype'] === 'httpd/unix-directory') { + $this->remove($target); + $dir = $this->opendir($source); + $this->mkdir($target); + while ($file = readdir($dir)) { + if (!Filesystem::isIgnoredDir($file)) { + if (!$this->rename($source . '/' . $file, $target . '/' . $file)) { + return false; + } + } + } + closedir($dir); + $this->remove($source); + return true; + } else { + if (is_array($stat1)) { + $parent = $this->stat(dirname($target)); + if (is_array($parent)) { + $this->remove($target); + $stat1['parent'] = $parent['fileid']; + $stat1['path'] = $target; + $stat1['path_hash'] = md5($target); + $stat1['name'] = \OC_Util::basename($target); + $stat1['mtime'] = time(); + $stat1['etag'] = $this->getETag($target); + $this->getCache()->update($stat1['fileid'], $stat1); + return true; + } + } + } + return false; + } + + public function getMimeType($path) { + $path = $this->normalizePath($path); + $stat = $this->stat($path); + if (is_array($stat)) { + return $stat['mimetype']; + } else { + return false; + } + } + + public function touch($path, $mtime = null) { + if (is_null($mtime)) { + $mtime = time(); + } + + $path = $this->normalizePath($path); + $dirName = dirname($path); + $parentExists = $this->is_dir($dirName); + if (!$parentExists) { + return false; + } + + $stat = $this->stat($path); + if (is_array($stat)) { + // update existing mtime in db + $stat['mtime'] = $mtime; + $this->getCache()->update($stat['fileid'], $stat); + } else { + $mimeType = \OC_Helper::getFileNameMimeType($path); + // create new file + $stat = array( + 'etag' => $this->getETag($path), + 'mimetype' => $mimeType, + 'size' => 0, + 'mtime' => $mtime, + 'storage_mtime' => $mtime, + 'permissions' => \OCP\PERMISSION_ALL, + ); + $fileId = $this->getCache()->put($path, $stat); + try { + //read an empty file from memory + $this->objectStore->writeObject($this->getURN($fileId), fopen('php://memory', 'r')); + } catch (\Exception $ex) { + $this->getCache()->remove($path); + \OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR); + return false; + } + } + return true; + } + + public function writeBack($tmpFile) { + if (!isset(self::$tmpFiles[$tmpFile])) { + return false; + } + + $path = self::$tmpFiles[$tmpFile]; + $stat = $this->stat($path); + if (empty($stat)) { + // create new file + $stat = array( + 'etag' => $this->getETag($path), + 'permissions' => \OCP\PERMISSION_ALL, + ); + } + // update stat with new data + $mTime = time(); + $stat['size'] = filesize($tmpFile); + $stat['mtime'] = $mTime; + $stat['storage_mtime'] = $mTime; + $stat['mimetype'] = \OC_Helper::getMimeType($tmpFile); + + $fileId = $this->getCache()->put($path, $stat); + try { + //upload to object storage + $this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r')); + } catch (\Exception $ex) { + $this->getCache()->remove($path); + \OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * external changes are not supported, exclusive access to the object storage is assumed + * + * @param string $path + * @param int $time + * @return false + */ + public function hasUpdated($path, $time) { + return false; + } +} diff --git a/lib/private/files/objectstore/swift.php b/lib/private/files/objectstore/swift.php new file mode 100644 index 0000000000..3378fd7b86 --- /dev/null +++ b/lib/private/files/objectstore/swift.php @@ -0,0 +1,147 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +namespace OC\Files\ObjectStore; + +use Guzzle\Http\Exception\ClientErrorResponseException; +use OCP\Files\ObjectStore\IObjectStore; +use OpenCloud\OpenStack; +use OpenCloud\Rackspace; + +class Swift implements IObjectStore { + /** + * @var \OpenCloud\OpenStack + */ + private $client; + + /** + * @var array + */ + private $params; + + /** + * @var \OpenCloud\ObjectStore\Service + */ + private $objectStoreService; + + /** + * @var \OpenCloud\ObjectStore\Resource\Container + */ + private $container; + + public function __construct($params) { + if (!isset($params['container'])) { + $params['container'] = 'owncloud'; + } + if (!isset($params['autocreate'])) { + // should only be true for tests + $params['autocreate'] = false; + } + + if (isset($params['apiKey'])) { + $this->client = new Rackspace($params['url'], $params); + } else { + $this->client = new OpenStack($params['url'], $params); + } + $this->params = $params; + } + + protected function init() { + if ($this->container) { + return; + } + + // the OpenCloud client library will default to 'cloudFiles' if $serviceName is null + $serviceName = null; + if ($this->params['serviceName']) { + $serviceName = $this->params['serviceName']; + } + + $this->objectStoreService = $this->client->objectStoreService($serviceName, $this->params['region']); + + try { + $this->container = $this->objectStoreService->getContainer($this->params['container']); + } catch (ClientErrorResponseException $ex) { + // if the container does not exist and autocreate is true try to create the container on the fly + if (isset($this->params['autocreate']) && $this->params['autocreate'] === true) { + $this->container = $this->objectStoreService->createContainer($this->params['container']); + } else { + throw $ex; + } + } + } + + /** + * @return string the container name where objects are stored + */ + public function getStorageId() { + return $this->params['container']; + } + + /** + * @param string $urn the unified resource name used to identify the object + * @param resource $stream stream with the data to write + * @throws Exception from openstack lib when something goes wrong + */ + public function writeObject($urn, $stream) { + $this->init(); + $this->container->uploadObject($urn, $stream); + } + + /** + * @param string $urn the unified resource name used to identify the object + * @return resource stream with the read data + * @throws Exception from openstack lib when something goes wrong + */ + public function readObject($urn) { + $this->init(); + $object = $this->container->getObject($urn); + + // we need to keep a reference to objectContent or + // the stream will be closed before we can do anything with it + /** @var $objectContent \Guzzle\Http\EntityBody * */ + $objectContent = $object->getContent(); + $objectContent->rewind(); + + // directly returning the object stream does not work because the GC seems to collect it, so we need a copy + $tmpStream = fopen('php://temp', 'r+'); + stream_copy_to_stream($objectContent->getStream(), $tmpStream); + rewind($tmpStream); + + return $tmpStream; + } + + /** + * @param string $urn Unified Resource Name + * @return void + * @throws Exception from openstack lib when something goes wrong + */ + public function deleteObject($urn) { + $this->init(); + // see https://github.com/rackspace/php-opencloud/issues/243#issuecomment-30032242 + $this->container->dataObject()->setName($urn)->delete(); + } + + public function deleteContainer($recursive = false) { + $this->init(); + $this->container->delete($recursive); + } + +} diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php index ecc75298b6..9657b511f1 100644 --- a/lib/private/files/storage/common.php +++ b/lib/private/files/storage/common.php @@ -279,6 +279,11 @@ abstract class Common implements \OC\Files\Storage\Storage { /** * check if a file or folder has been updated since $time * + * The method is only used to check if the cache needs to be updated. Storage backends that don't support checking + * the mtime should always return false here. As a result storage implementations that always return false expect + * exclusive access to the backend and will not pick up files that have been added in a way that circumvents + * ownClouds filesystem. + * * @param string $path * @param int $time * @return bool diff --git a/lib/private/util.php b/lib/private/util.php index 94005daef6..225cd64dbb 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -12,6 +12,45 @@ class OC_Util { private static $rootMounted=false; private static $fsSetup=false; + private static function initLocalStorageRootFS() { + // mount local file backend as root + $configDataDirectory = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); + //first set up the local "root" storage + \OC\Files\Filesystem::initMounts(); + if(!self::$rootMounted) { + \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', array('datadir'=>$configDataDirectory), '/'); + self::$rootMounted = true; + } + } + + /** + * mounting an object storage as the root fs will in essence remove the + * necessity of a data folder being present. + * TODO make home storage aware of this and use the object storage instead of local disk access + * @param array $config containing 'class' and optional 'arguments' + */ + private static function initObjectStoreRootFS($config) { + // check misconfiguration + if (empty($config['class'])) { + \OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR); + } + if (!isset($config['arguments'])) { + $config['arguments'] = array(); + } + + // instantiate object store implementation + $config['arguments']['objectstore'] = new $config['class']($config['arguments']); + // mount with plain / root object store implementation + $config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage'; + + // mount object storage as root + \OC\Files\Filesystem::initMounts(); + if(!self::$rootMounted) { + \OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/'); + self::$rootMounted = true; + } + } + /** * Can be set up * @param string $user @@ -39,12 +78,12 @@ class OC_Util { self::$fsSetup=true; } - $configDataDirectory = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ); - //first set up the local "root" storage - \OC\Files\Filesystem::initMounts(); - if(!self::$rootMounted) { - \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', array('datadir'=>$configDataDirectory), '/'); - self::$rootMounted = true; + //check if we are using an object storage + $objectStore = OC_Config::getValue( 'objectstore' ); + if ( isset( $objectStore ) ) { + self::initObjectStoreRootFS($objectStore); + } else { + self::initLocalStorageRootFS(); } if ($user != '' && !OCP\User::userExists($user)) { @@ -60,24 +99,33 @@ class OC_Util { /** * @var \OC\Files\Storage\Storage $storage */ - if ($storage->instanceOfStorage('\OC\Files\Storage\Home')) { - $user = $storage->getUser()->getUID(); - $quota = OC_Util::getUserQuota($user); - if ($quota !== \OC\Files\SPACE_UNLIMITED) { - return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $quota, 'root' => 'files')); + if ($storage->instanceOfStorage('\OC\Files\Storage\Home') + || $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage') + ) { + if (is_object($storage->getUser())) { + $user = $storage->getUser()->getUID(); + $quota = OC_Util::getUserQuota($user); + if ($quota !== \OC\Files\SPACE_UNLIMITED) { + return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $quota, 'root' => 'files')); + } } } return $storage; }); - $userDir = '/'.$user.'/files'; - $userRoot = OC_User::getHome($user); - $userDirectory = $userRoot . '/files'; - if( !is_dir( $userDirectory )) { - mkdir( $userDirectory, 0755, true ); - OC_Util::copySkeleton($userDirectory); + // copy skeleton for local storage only + if ( ! isset( $objectStore ) ) { + $userRoot = OC_User::getHome($user); + $userDirectory = $userRoot . '/files'; + if( !is_dir( $userDirectory )) { + mkdir( $userDirectory, 0755, true ); + OC_Util::copySkeleton($userDirectory); + } } + + $userDir = '/'.$user.'/files'; + //jail the user into his "home" directory \OC\Files\Filesystem::init($user, $userDir); diff --git a/lib/public/files/objectstore/iobjectstore.php b/lib/public/files/objectstore/iobjectstore.php new file mode 100644 index 0000000000..b2c5a9da13 --- /dev/null +++ b/lib/public/files/objectstore/iobjectstore.php @@ -0,0 +1,33 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +namespace OCA\ObjectStore\Tests\Unit; + +use OC\Files\ObjectStore\ObjectStoreStorage; +use OC\Files\ObjectStore\Swift as ObjectStoreToTest; + +use PHPUnit_Framework_TestCase; + +//class Swift extends PHPUnit_Framework_TestCase { +class Swift extends \Test\Files\Storage\Storage { + + private $objectStorage; + + public function setUp() { + + \OC_App::disable('files_sharing'); + \OC_App::disable('files_versions'); + + // reset backend + \OC_User::clearBackends(); + \OC_User::useBackend('database'); + + // create users + $users = array('test'); + foreach($users as $userName) { + \OC_User::deleteUser($userName); + \OC_User::createUser($userName, $userName); + } + + // main test user + $userName = 'test'; + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + \OC\Files\Filesystem::tearDown(); + \OC_User::setUserId('test'); + + $testContainer = 'oc-test-container-'.substr( md5(rand()), 0, 7); + + $params = array( + 'username' => 'facebook100000330192569', + 'password' => 'Dbdj1sXnRSHxIGc4', + 'container' => $testContainer, + 'autocreate' => true, + 'region' => 'RegionOne', //required, trystack defaults to 'RegionOne' + 'url' => 'http://8.21.28.222:5000/v2.0', // The Identity / Keystone endpoint + 'tenantName' => 'facebook100000330192569', // required on trystack + 'serviceName' => 'swift', //trystack uses swift by default, the lib defaults to 'cloudFiles' if omitted + 'user' => \OC_User::getManager()->get($userName) + ); + $this->objectStorage = new ObjectStoreToTest($params); + $params['objectstore'] = $this->objectStorage; + $this->instance = new ObjectStoreStorage($params); + } + + public function tearDown() { + if (is_null($this->instance)) { + return; + } + $this->objectStorage->deleteContainer(true); + $this->instance->getCache()->clear(); + } + + public function testStat() { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $ctimeStart = time(); + $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); + $this->assertTrue($this->instance->isReadable('/lorem.txt')); + $ctimeEnd = time(); + $mTime = $this->instance->filemtime('/lorem.txt'); + + // check that ($ctimeStart - 5) <= $mTime <= ($ctimeEnd + 1) + $this->assertGreaterThanOrEqual(($ctimeStart - 5), $mTime); + $this->assertLessThanOrEqual(($ctimeEnd + 1), $mTime); + $this->assertEquals(filesize($textFile), $this->instance->filesize('/lorem.txt')); + + $stat = $this->instance->stat('/lorem.txt'); + //only size and mtime are required in the result + $this->assertEquals($stat['size'], $this->instance->filesize('/lorem.txt')); + $this->assertEquals($stat['mtime'], $mTime); + + if ($this->instance->touch('/lorem.txt', 100) !== false) { + $mTime = $this->instance->filemtime('/lorem.txt'); + $this->assertEquals($mTime, 100); + } + } + +}