diff options
author | raghunayyar <me@iraghu.com> | 2014-01-16 14:42:37 +0530 |
---|---|---|
committer | raghunayyar <me@iraghu.com> | 2014-01-16 14:42:37 +0530 |
commit | 775e08e0ee4125cc7b2a594771437686f6a21b56 (patch) | |
tree | 362f84449171898335dd3e8511b65c97c150e9e1 /apps/files_external | |
parent | 4687d2dd0bde3f689eb57c90d0c4341cd00991bd (diff) | |
parent | bd643c47f32ba6d7b3ba6a18ed1591aab0b81be8 (diff) | |
download | nextcloud-server-775e08e0ee4125cc7b2a594771437686f6a21b56.tar.gz nextcloud-server-775e08e0ee4125cc7b2a594771437686f6a21b56.zip |
Merge branch 'master' into core-em-to-px
Conflicts:
apps/files_sharing/css/public.css
apps/user_ldap/css/settings.css
core/css/multiselect.css
core/css/share.css
Diffstat (limited to 'apps/files_external')
170 files changed, 9043 insertions, 718 deletions
diff --git a/apps/files_external/3rdparty/php-opencloud/LICENSE b/apps/files_external/3rdparty/php-opencloud/LICENSE new file mode 100644 index 00000000000..f7c56967e6c --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/LICENSE @@ -0,0 +1,16 @@ + 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 new file mode 100644 index 00000000000..32e9dc24b7e --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/Autoload.php @@ -0,0 +1,296 @@ +<?php + +// Copyright (c) 2004-2013 Fabien Potencier + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is furnished +// to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +class ClassLoader +{ + private $namespaces = array(); + private $prefixes = array(); + private $namespaceFallbacks = array(); + private $prefixFallbacks = array(); + private $useIncludePath = false; + + /** + * Turns on searching the include for class files. Allows easy loading + * of installed PEAR packages + * + * @param Boolean $useIncludePath + */ + public function useIncludePath($useIncludePath) + { + $this->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 new file mode 100644 index 00000000000..f80c9320e2a --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Base.php @@ -0,0 +1,301 @@ +<?php +/** + * @copyright 2012-2013 Rackspace Hosting, Inc. + * See COPYING for licensing information + * @package phpOpenCloud + * @version 1.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..e1bf80376e0 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Collection.php @@ -0,0 +1,320 @@ +<?php + +namespace OpenCloud\Common; + +/** + * Provides an abstraction for working with ordered sets of objects + * + * Collection objects are used whenever there are multiples; for example, + * multiple objects in a container, or multiple servers in a service. + * + * @since 1.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ +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: + * <code> + * $services = $connection->ServiceList(); + * $services->Select(function($item){ return $item->region=='ORD';}); + * // now the $services Collection only has items from the ORD region + * </code> + * + * `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 new file mode 100644 index 00000000000..cbbacff38bd --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class AsyncError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncHttpError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncHttpError.php new file mode 100644 index 00000000000..dc7b2d7e3a7 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncHttpError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class AsyncHttpError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncTimeoutError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncTimeoutError.php new file mode 100644 index 00000000000..bba5f09f64f --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AsyncTimeoutError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class AsyncTimeoutError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AttributeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AttributeError.php new file mode 100644 index 00000000000..7d09ceb0147 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AttributeError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class AttributeError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AuthenticationError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AuthenticationError.php new file mode 100644 index 00000000000..091e4602ec0 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/AuthenticationError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class AuthenticationError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/BaseException.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/BaseException.php new file mode 100644 index 00000000000..0bc967adf67 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/BaseException.php @@ -0,0 +1,7 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class BaseException extends \Exception +{ +}
\ No newline at end of file diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnError.php new file mode 100644 index 00000000000..0f972e9c5c7 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class CdnError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnHttpError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnHttpError.php new file mode 100644 index 00000000000..f1e2722f158 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnHttpError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class CdnHttpError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnNotAvailableError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnNotAvailableError.php new file mode 100644 index 00000000000..853b17c7127 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnNotAvailableError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class CdnNotAvailableError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnTtlError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnTtlError.php new file mode 100644 index 00000000000..b4364f93467 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CdnTtlError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class CdnTtlError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CollectionError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CollectionError.php new file mode 100644 index 00000000000..9d5030403f6 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CollectionError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class CollectionError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerCreateError.php new file mode 100644 index 00000000000..afc8119bd5a --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerCreateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ContainerCreateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerDeleteError.php new file mode 100644 index 00000000000..c212bfbaffd --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerDeleteError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ContainerDeleteError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerError.php new file mode 100644 index 00000000000..c9716fef075 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ContainerError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNameError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNameError.php new file mode 100644 index 00000000000..e0b9592835e --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNameError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ContainerNameError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotEmptyError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotEmptyError.php new file mode 100644 index 00000000000..e987449d444 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotEmptyError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ContainerNotEmptyError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotFoundError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotFoundError.php new file mode 100644 index 00000000000..2e700dbe039 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ContainerNotFoundError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ContainerNotFoundError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateError.php new file mode 100644 index 00000000000..bb2030373fb --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class CreateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateUpdateError.php new file mode 100644 index 00000000000..8aa651a76d9 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CreateUpdateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class CreateUpdateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CredentialError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CredentialError.php new file mode 100644 index 00000000000..2769edaf378 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/CredentialError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class CredentialError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseCreateError.php new file mode 100644 index 00000000000..eb19198c2fe --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseCreateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class DatabaseCreateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseDeleteError.php new file mode 100644 index 00000000000..41f397529fe --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseDeleteError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class DatabaseDeleteError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseListError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseListError.php new file mode 100644 index 00000000000..04a7fb9e835 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseListError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class DatabaseListError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseNameError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseNameError.php new file mode 100644 index 00000000000..17a987a03b0 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseNameError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class DatabaseNameError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseUpdateError.php new file mode 100644 index 00000000000..c891c173787 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DatabaseUpdateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class DatabaseUpdateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DeleteError.php new file mode 100644 index 00000000000..27c4b2a4894 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DeleteError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class DeleteError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DocumentError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DocumentError.php new file mode 100644 index 00000000000..d501e3594b6 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DocumentError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class DocumentError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DomainError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DomainError.php new file mode 100644 index 00000000000..b4eac2ae1d3 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/DomainError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class DomainError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EmptyResponseError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EmptyResponseError.php new file mode 100644 index 00000000000..c7863c09b01 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EmptyResponseError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class EmptyResponseError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EndpointError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EndpointError.php new file mode 100644 index 00000000000..a686a6456e9 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/EndpointError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class EndpointError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/FlavorError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/FlavorError.php new file mode 100644 index 00000000000..469dc27e76c --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/FlavorError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class FlavorError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpError.php new file mode 100644 index 00000000000..1b54b8a8253 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class HttpError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpForbiddenError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpForbiddenError.php new file mode 100644 index 00000000000..a5c64780516 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpForbiddenError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class HttpForbiddenError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpOverLimitError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpOverLimitError.php new file mode 100644 index 00000000000..243e8df64fd --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpOverLimitError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class HttpOverLimitError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpRetryError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpRetryError.php new file mode 100644 index 00000000000..78345840bba --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpRetryError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class HttpRetryError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpTimeoutError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpTimeoutError.php new file mode 100644 index 00000000000..81bc9dda608 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpTimeoutError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class HttpTimeoutError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUnauthorizedError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUnauthorizedError.php new file mode 100644 index 00000000000..9b1edb20333 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUnauthorizedError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class HttpUnauthorizedError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUrlError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUrlError.php new file mode 100644 index 00000000000..fa2af82c564 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/HttpUrlError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class HttpUrlError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IOError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IOError.php new file mode 100644 index 00000000000..df816336c6c --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IOError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class IOError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IdRequiredError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IdRequiredError.php new file mode 100644 index 00000000000..398b9f3fd85 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/IdRequiredError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class IdRequiredError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ImageError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ImageError.php new file mode 100644 index 00000000000..3b846a7551f --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ImageError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ImageError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceCreateError.php new file mode 100644 index 00000000000..65caa154497 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceCreateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class InstanceCreateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceDeleteError.php new file mode 100644 index 00000000000..e4c6fdb7f57 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceDeleteError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class InstanceDeleteError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceError.php new file mode 100644 index 00000000000..48152824862 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class InstanceError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceFlavorError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceFlavorError.php new file mode 100644 index 00000000000..e8a074eb9bf --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceFlavorError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class InstanceFlavorError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceNotFound.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceNotFound.php new file mode 100644 index 00000000000..4bc94797b3f --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceNotFound.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class InstanceNotFound extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceUpdateError.php new file mode 100644 index 00000000000..b15f3426013 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InstanceUpdateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class InstanceUpdateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidArgumentError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidArgumentError.php new file mode 100644 index 00000000000..a655f11a731 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidArgumentError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class InvalidArgumentError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIdTypeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIdTypeError.php new file mode 100644 index 00000000000..f329c748957 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIdTypeError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class InvalidIdTypeError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIpTypeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIpTypeError.php new file mode 100644 index 00000000000..370d8f650de --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidIpTypeError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class InvalidIpTypeError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidParameterError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidParameterError.php new file mode 100644 index 00000000000..f13986ffc94 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidParameterError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class InvalidParameterError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidRequestError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidRequestError.php new file mode 100644 index 00000000000..0266d8f22bd --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/InvalidRequestError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class InvalidRequestError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/JsonError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/JsonError.php new file mode 100644 index 00000000000..96f9102ed37 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/JsonError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class JsonError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/LoggingException.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/LoggingException.php new file mode 100644 index 00000000000..a5bdad705f4 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/LoggingException.php @@ -0,0 +1,16 @@ +<?php +/** + * @copyright Copyright 2012-2013 Rackspace US, Inc. + See COPYING for licensing information. + * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0 + * @version 1.5.9 + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..a119397392f --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataCreateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class MetadataCreateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataDeleteError.php new file mode 100644 index 00000000000..4acd879afe9 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataDeleteError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class MetadataDeleteError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataError.php new file mode 100644 index 00000000000..65f94975a44 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class MetadataError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataJsonError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataJsonError.php new file mode 100644 index 00000000000..a7a74ca9e13 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataJsonError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class MetadataJsonError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataKeyError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataKeyError.php new file mode 100644 index 00000000000..606f6d95874 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataKeyError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class MetadataKeyError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataPrefixError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataPrefixError.php new file mode 100644 index 00000000000..271e69010a7 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataPrefixError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class MetadataPrefixError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataUpdateError.php new file mode 100644 index 00000000000..49db43d6f70 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MetadataUpdateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class MetadataUpdateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MisMatchedChecksumError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MisMatchedChecksumError.php new file mode 100644 index 00000000000..75b4f926995 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MisMatchedChecksumError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class MisMatchedChecksumError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MissingValueError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MissingValueError.php new file mode 100644 index 00000000000..0dd5b8ee737 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/MissingValueError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class MissingValueError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NameError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NameError.php new file mode 100644 index 00000000000..6918120a56c --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NameError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class NameError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkCreateError.php new file mode 100644 index 00000000000..a0c7640ffe8 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkCreateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class NetworkCreateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkDeleteError.php new file mode 100644 index 00000000000..0e2922babe2 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkDeleteError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class NetworkDeleteError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkError.php new file mode 100644 index 00000000000..4b30806c1bc --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class NetworkError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUpdateError.php new file mode 100644 index 00000000000..f55f09d8ec2 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUpdateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class NetworkUpdateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUrlError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUrlError.php new file mode 100644 index 00000000000..666ec50482b --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NetworkUrlError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class NetworkUrlError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoContentTypeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoContentTypeError.php new file mode 100644 index 00000000000..59a33088163 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoContentTypeError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class NoContentTypeError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoNameError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoNameError.php new file mode 100644 index 00000000000..2d56f5fcd0d --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/NoNameError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class NoNameError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjFetchError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjFetchError.php new file mode 100644 index 00000000000..9d7391823e8 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjFetchError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ObjFetchError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectCopyError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectCopyError.php new file mode 100644 index 00000000000..ef7b3b39220 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectCopyError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ObjectCopyError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectError.php new file mode 100644 index 00000000000..ea667ad25f6 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ObjectError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ObjectError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RebuildError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RebuildError.php new file mode 100644 index 00000000000..9ee6ab37fd9 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RebuildError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class RebuildError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RecordTypeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RecordTypeError.php new file mode 100644 index 00000000000..718ce98574c --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/RecordTypeError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class RecordTypeError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerActionError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerActionError.php new file mode 100644 index 00000000000..d4ad6453281 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerActionError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ServerActionError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerCreateError.php new file mode 100644 index 00000000000..69904111c61 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerCreateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ServerCreateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerDeleteError.php new file mode 100644 index 00000000000..94a1adc4f0b --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerDeleteError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ServerDeleteError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerImageScheduleError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerImageScheduleError.php new file mode 100644 index 00000000000..19fbcbd279c --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerImageScheduleError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ServerImageScheduleError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerIpsError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerIpsError.php new file mode 100644 index 00000000000..3e737c28614 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerIpsError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ServerIpsError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerJsonError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerJsonError.php new file mode 100644 index 00000000000..c10e67d645d --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerJsonError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ServerJsonError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUpdateError.php new file mode 100644 index 00000000000..d9d7b370808 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUpdateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ServerUpdateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUrlError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUrlError.php new file mode 100644 index 00000000000..ba0308d04e7 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServerUrlError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ServerUrlError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServiceValueError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServiceValueError.php new file mode 100644 index 00000000000..7ce52c846a4 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/ServiceValueError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class ServiceValueError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/SnapshotError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/SnapshotError.php new file mode 100644 index 00000000000..14d7614a9ee --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/SnapshotError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class SnapshotError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/TempUrlMethodError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/TempUrlMethodError.php new file mode 100644 index 00000000000..61f4647d1b3 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/TempUrlMethodError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class TempUrlMethodError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownError.php new file mode 100644 index 00000000000..2b0772530fc --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class UnknownError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownParameterError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownParameterError.php new file mode 100644 index 00000000000..704ee28c052 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnknownParameterError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class UnknownParameterError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnrecognizedServiceError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnrecognizedServiceError.php new file mode 100644 index 00000000000..396d451e131 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnrecognizedServiceError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class UnrecognizedServiceError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedExtensionError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedExtensionError.php new file mode 100644 index 00000000000..5ff5ae89c73 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedExtensionError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class UnsupportedExtensionError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedFeatureExtension.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedFeatureExtension.php new file mode 100644 index 00000000000..6d9143a1d91 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedFeatureExtension.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class UnsupportedFeatureExtension extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedVersionError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedVersionError.php new file mode 100644 index 00000000000..060733ad5b5 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UnsupportedVersionError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class UnsupportedVersionError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UpdateError.php new file mode 100644 index 00000000000..23f0dbb6aa7 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UpdateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class UpdateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UrlError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UrlError.php new file mode 100644 index 00000000000..6c4d9ab69aa --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UrlError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class UrlError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserCreateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserCreateError.php new file mode 100644 index 00000000000..f87ee0d2fc9 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserCreateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class UserCreateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserDeleteError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserDeleteError.php new file mode 100644 index 00000000000..3196289aafc --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserDeleteError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class UserDeleteError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserListError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserListError.php new file mode 100644 index 00000000000..7d287ae0ecf --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserListError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class UserListError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserNameError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserNameError.php new file mode 100644 index 00000000000..51902f8e93c --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserNameError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class UserNameError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserUpdateError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserUpdateError.php new file mode 100644 index 00000000000..403b53420d0 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/UserUpdateError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class UserUpdateError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeError.php new file mode 100644 index 00000000000..c19c4c2009d --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class VolumeError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeTypeError.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeTypeError.php new file mode 100644 index 00000000000..a9cc1e3f64b --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Exceptions/VolumeTypeError.php @@ -0,0 +1,5 @@ +<?php + +namespace OpenCloud\Common\Exceptions; + +class VolumeTypeError extends \Exception {} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Role.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Role.php new file mode 100644 index 00000000000..b2c480d71b5 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Role.php @@ -0,0 +1,21 @@ +<?php + +/** + * PHP OpenCloud library. + * + * @author Jamie Hannaford <jamie@limetree.org> + * @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 new file mode 100644 index 00000000000..62783613c2f --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/Tenant.php @@ -0,0 +1,22 @@ +<?php + +/** + * PHP OpenCloud library. + * + * @author Jamie Hannaford <jamie@limetree.org> + * @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 new file mode 100644 index 00000000000..9e3862d1750 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Identity/User.php @@ -0,0 +1,73 @@ +<?php +/** + * @copyright 2012-2013 Rackspace Hosting, Inc. + * See COPYING for licensing information + * @package phpOpenCloud + * @version 1.5.9 + * @author Glen Campbell <glen.campbell@rackspace.com> + * @author Jamie Hannaford <jamie.hannaford@rackspace.co.uk> + */ + +/** + * 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 new file mode 100644 index 00000000000..7bb12859734 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Lang.php @@ -0,0 +1,21 @@ +<?php + +namespace OpenCloud\Common; + +class Lang +{ + + public static function translate($word = null) + { + return $word; + } + + public static function noslash($str) + { + while ($str && (substr($str, -1) == '/')) { + $str = substr($str, 0, strlen($str) - 1); + } + return $str; + } + +} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/AbstractLogger.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/AbstractLogger.php new file mode 100644 index 00000000000..c7aea7f8767 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/AbstractLogger.php @@ -0,0 +1,140 @@ +<?php + +// Copyright (c) 2012 PHP Framework Interoperability Group +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace OpenCloud\Common\Log; + +/** + * This is a simple Logger implementation that other Loggers can inherit from. + * + * It simply delegates all log-level-specific methods to the `log` method to + * reduce boilerplate code that a simple Logger that does the same thing with + * messages regardless of the error level has to implement. + */ +abstract class AbstractLogger implements LoggerInterface +{ + /** + * System is unusable. + * + * @param string $message + * @param array $context + * @return null + */ + public function emergency($message, array $context = array()) + { + $this->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 new file mode 100644 index 00000000000..64b0169b507 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LogLevel.php @@ -0,0 +1,38 @@ +<?php + +// Copyright (c) 2012 PHP Framework Interoperability Group +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace OpenCloud\Common\Log; + +/** + * Describes log levels + */ +class LogLevel +{ + const EMERGENCY = 'emergency'; + const ALERT = 'alert'; + const CRITICAL = 'critical'; + const ERROR = 'error'; + const WARNING = 'warning'; + const NOTICE = 'notice'; + const INFO = 'info'; + const DEBUG = 'debug'; +}
\ No newline at end of file diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/Logger.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/Logger.php new file mode 100644 index 00000000000..e11d3fbb7ca --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/Logger.php @@ -0,0 +1,220 @@ +<?php +/** + * @copyright Copyright 2012-2013 Rackspace US, Inc. + See COPYING for licensing information. + * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0 + * @version 1.5.9 + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..daef1b04dad --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Log/LoggerInterface.php @@ -0,0 +1,134 @@ +<?php + +// Copyright (c) 2012 PHP Framework Interoperability Group +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace OpenCloud\Common\Log; + +/** + * Describes a logger instance + * + * The message MUST be a string or object implementing __toString(). + * + * The message MAY contain placeholders in the form: {foo} where foo + * will be replaced by the context data in key "foo". + * + * The context array can contain arbitrary data, the only assumption that + * can be made by implementors is that if an Exception instance is given + * to produce a stack trace, it MUST be in a key named "exception". + * + * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md + * for the full interface specification. + */ +interface LoggerInterface +{ + /** + * System is unusable. + * + * @param string $message + * @param array $context + * @return null + */ + public function emergency($message, array $context = array()); + + /** + * 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()); + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param array $context + * @return null + */ + public function critical($message, array $context = array()); + + /** + * 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()); + + /** + * 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()); + + /** + * Normal but significant events. + * + * @param string $message + * @param array $context + * @return null + */ + public function notice($message, array $context = array()); + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param array $context + * @return null + */ + public function info($message, array $context = array()); + + /** + * Detailed debug information. + * + * @param string $message + * @param array $context + * @return null + */ + public function debug($message, array $context = array()); + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * @return null + */ + public function log($level, $message, array $context = array()); +}
\ No newline at end of file diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Metadata.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Metadata.php new file mode 100644 index 00000000000..be6903e897e --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Metadata.php @@ -0,0 +1,92 @@ +<?php +/** + * A metadata object, used by other components in Compute and Object Storage + * + * @copyright 2012-2013 Rackspace Hosting, Inc. + * See COPYING for licensing information + * + * @package phpOpenCloud + * @version 1.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + */ + +namespace OpenCloud\Common; + +/** + * The Metadata class represents either Server or Image metadata + * + * @api + * @author Glen Campbell <glen.campbell@rackspace.com> + */ +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 new file mode 100644 index 00000000000..fe4dcccc73f --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Nova.php @@ -0,0 +1,140 @@ +<?php + +/** + * An abstract class that defines shared components for products that use + * OpenStack Nova + * + * @copyright 2012-2013 Rackspace Hosting, Inc. + * See COPYING for licensing information + * + * @package phpOpenCloud + * @version 1.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..0257526d709 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/PersistentObject.php @@ -0,0 +1,939 @@ +<?php +/** + * An abstraction that defines persistent objects associated with a service + * + * @copyright 2012-2013 Rackspace Hosting, Inc. + * See COPYING for licensing information + * + * @package phpOpenCloud + * @version 1.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..bb829afc5f6 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Curl.php @@ -0,0 +1,308 @@ +<?php + +namespace OpenCloud\Common\Request; + +use OpenCloud\Common\Base; +use OpenCloud\Common\Lang; +use OpenCloud\Common\Exceptions\HttpRetryError; +use OpenCloud\Common\Exceptions\HttpUrlError; +use OpenCloud\Common\Exceptions\HttpTimeoutError; +use OpenCloud\Common\Exceptions\HttpError; + +/** + * The CurlRequest class is a simple wrapper to CURL functions. Not only does + * this permit stubbing of the interface as described under the HttpRequest + * interface, it could potentially allow us to replace the interface methods + * with other function calls in the future. + * + * @api + * @author Glen Campbell <glen.campbell@rackspace.com> + */ +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 new file mode 100644 index 00000000000..cbe3b5412a1 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/HttpRequestInterface.php @@ -0,0 +1,23 @@ +<?php + +namespace OpenCloud\Common\Request; + +/** + * The HttpRequest interface defines methods for wrapping CURL; this allows + * those methods to be stubbed out for unit testing, thus allowing us to + * test without actually making live calls. + */ +interface HttpRequestInterface +{ + + public function SetOption($name, $value); + + public function setheaders($arr); + + public function SetHeader($header, $value); + + public function Execute(); + + public function close(); + +} diff --git a/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Blank.php b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Blank.php new file mode 100644 index 00000000000..0c79adcef3a --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Blank.php @@ -0,0 +1,27 @@ +<?php + +namespace OpenCloud\Common\Request\Response; + +class Blank extends Http +{ + public $errno; + public $error; + public $info; + public $body; + public $headers = array(); + public $status = 200; + public $rawdata; + + public function __construct(array $values = array()) + { + foreach($values as $name => $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 new file mode 100644 index 00000000000..a7cb9e96346 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Request/Response/Http.php @@ -0,0 +1,140 @@ +<?php + +namespace OpenCloud\Common\Request\Response; + +use OpenCloud\Common\Base; + +/** + * The HttpResponse returns an object with status information, separated + * headers, and any response body necessary. + * + * @api + * @author Glen Campbell <glen.campbell@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..5b3aa729a97 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/Service.php @@ -0,0 +1,489 @@ +<?php +/** + * PHP OpenCloud library. + * + * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information. + * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0 + * @version 1.6.0 + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ + +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 <glen.campbell@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..3e20bcbc7b9 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Common/ServiceCatalogItem.php @@ -0,0 +1,18 @@ +<?php + +namespace OpenCloud\Common; + +/** + * Holds information on a single service from the Service Catalog + */ +class ServiceCatalogItem +{ + + public function __construct($info = array()) + { + foreach($info as $key => $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 new file mode 100644 index 00000000000..fbdc4355e02 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Globals.php @@ -0,0 +1,252 @@ +<?php +/** + * Defines global constants and functions + * + * @copyright 2012-2013 Rackspace Hosting, Inc. + * See COPYING for licensing information + * + * @package phpOpenCloud + * @version 1.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..4a2298d60ed --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/AbstractService.php @@ -0,0 +1,57 @@ +<?php +/** + * PHP OpenCloud library. + * + * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information. + * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0 + * @version 1.6.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..132d5f47ad6 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/CDNService.php @@ -0,0 +1,62 @@ +<?php +/** + * PHP OpenCloud library. + * + * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information. + * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0 + * @version 1.6.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..c6799b22b7e --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/AbstractStorageObject.php @@ -0,0 +1,170 @@ +<?php +/** + * PHP OpenCloud library. + * + * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information. + * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0 + * @version 1.6.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..9b6367c87e0 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/CDNContainer.php @@ -0,0 +1,298 @@ +<?php +/** + * PHP OpenCloud library. + * + * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information. + * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0 + * @version 1.6.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..3a56ebd9fca --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/Container.php @@ -0,0 +1,401 @@ +<?php +/** + * PHP OpenCloud library. + * + * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information. + * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0 + * @version 1.6.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..443df1f651f --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Resource/DataObject.php @@ -0,0 +1,941 @@ +<?php +/** + * PHP OpenCloud library. + * + * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information. + * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0 + * @version 1.6.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ + +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: + * <code> + * # ... 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"); + * </code> + * + * @param string $filename name of local file to write data to + * @return boolean <kbd>TRUE</kbd> 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: + * <code> + * # ... 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); + * </code> + * + * @param string $filename name of local file to write data to + * @return boolean <kbd>TRUE</kbd> 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 <kbd>TRUE</kbd> 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 new file mode 100644 index 00000000000..571b33378ac --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/ObjectStore/Service.php @@ -0,0 +1,115 @@ +<?php +/** + * PHP OpenCloud library. + * + * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information. + * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0 + * @version 1.6.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ + +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 new file mode 100644 index 00000000000..c3e645a5406 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/OpenStack.php @@ -0,0 +1,1198 @@ +<?php +/** + * PHP OpenCloud library. + * + * @copyright Copyright 2013 Rackspace US, Inc. See COPYING for licensing information. + * @license https://www.apache.org/licenses/LICENSE-2.0 Apache 2.0 + * @version 1.6.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + * @author Jamie Hannaford <jamie.hannaford@rackspace.com> + */ + +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: + * <code> + * $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'); + * </code> + */ +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: + * + * <code> + * define('RAXSDK_COMPUTE_NAME', 'cloudServersOpenStack'); + * include('openstack.php'); + * </code> + */ + 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 new file mode 100644 index 00000000000..41be608b347 --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/OpenCloud/Rackspace.php @@ -0,0 +1,132 @@ +<?php +/** + * The Rackspace cloud/connection class (which uses different authentication + * than the pure OpenStack class) + * + * @copyright 2012-2013 Rackspace Hosting, Inc. + * See COPYING for licensing information + * + * @package phpOpenCloud + * @version 1.0 + * @author Glen Campbell <glen.campbell@rackspace.com> + */ + +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: + * <code> + * $username = 'FRED'; + * $apiKey = '0900af093093788912388fc09dde090ffee09'; + * $conn = new Rackspace( + * 'https://identity.api.rackspacecloud.com/v2.0/', + * array( + * 'username' => $username, + * 'apiKey' => $apiKey + * )); + * </code> + */ +class Rackspace extends OpenStack +{ + + //this is the JSON string for our new credentials +const APIKEYTEMPLATE = <<<ENDCRED +{ "auth": { "RAX-KSKEY:apiKeyCredentials": { "username": "%s", + "apiKey": "%s" + } + } +} +ENDCRED; + + /** + * Generates Rackspace API key credentials + * + * @return string + */ + public function Credentials() + { + $sec = $this->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 new file mode 100644 index 00000000000..738902d244e --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/openstack.php @@ -0,0 +1,8 @@ +<?php +/** + * provided for backwards compatibility + * + * @copyright 2013 Rackspace Hosting, Inc. + * @license http://www.apache.org/licenses/LICENSE-2.0 + */ +require_once __DIR__.'/php-opencloud.php'; diff --git a/apps/files_external/3rdparty/php-opencloud/lib/php-opencloud.php b/apps/files_external/3rdparty/php-opencloud/lib/php-opencloud.php new file mode 100644 index 00000000000..15ff034b92d --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/php-opencloud.php @@ -0,0 +1,15 @@ +<?php +/** + * entry point for PHP-OpenCloud library + * + * @copyright 2013 Rackspace Hosting, Inc. + * @license http://www.apache.org/licenses/LICENSE-2.0 + */ +require_once(__DIR__ . '/Autoload.php'); +require_once(__DIR__ . '/OpenCloud/Globals.php'); + +$classLoader = new ClassLoader; +$classLoader->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 new file mode 100644 index 00000000000..738902d244e --- /dev/null +++ b/apps/files_external/3rdparty/php-opencloud/lib/rackspace.php @@ -0,0 +1,8 @@ +<?php +/** + * provided for backwards compatibility + * + * @copyright 2013 Rackspace Hosting, Inc. + * @license http://www.apache.org/licenses/LICENSE-2.0 + */ +require_once __DIR__.'/php-opencloud.php'; diff --git a/apps/files_external/3rdparty/smb4php/smb.php b/apps/files_external/3rdparty/smb4php/smb.php index e7d1dfa09fe..622942b052a 100644 --- a/apps/files_external/3rdparty/smb4php/smb.php +++ b/apps/files_external/3rdparty/smb4php/smb.php @@ -19,6 +19,10 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # +# Addition 17/12/2012 Frank Karlitschek (frank@owncloud.org) +# On the official website http://www.phpclasses.org/smb4php the +# license is listed as LGPL so we assume that this is +# dual-licensed GPL/LGPL ################################################################### define ('SMB4PHP_VERSION', '0.8'); @@ -126,7 +130,8 @@ class smb { // this put env is necessary to read the output of smbclient correctly $old_locale = getenv('LC_ALL'); putenv('LC_ALL=en_US.UTF-8'); - $output = popen (SMB4PHP_SMBCLIENT." -N {$auth} {$options} {$port} {$options} {$params} 2>/dev/null", 'r'); + $output = popen ('TZ=UTC '.SMB4PHP_SMBCLIENT." -N {$auth} {$options} {$port} {$options} {$params} 2>/dev/null", 'r'); + $gotInfo = false; $info = array (); $info['info']= array (); $mode = ''; @@ -159,7 +164,7 @@ class smb { $i = ($mode == 'servers') ? array ($name, "server") : array ($name, "workgroup", $master); break; case 'files': - list ($attr, $name) = preg_match ("/^(.*)[ ]+([D|A|H|S|R]+)$/", trim ($regs[1]), $regs2) + list ($attr, $name) = preg_match ("/^(.*)[ ]+([D|A|H|N|S|R]+)$/", trim ($regs[1]), $regs2) ? array (trim ($regs2[2]), trim ($regs2[1])) : array ('', trim ($regs[1])); list ($his, $im) = array ( @@ -181,12 +186,19 @@ class smb { return false; }elseif(substr($regs[0],0,31)=='NT_STATUS_OBJECT_PATH_NOT_FOUND'){ return false; + }elseif(substr($regs[0],0,31)=='NT_STATUS_OBJECT_NAME_NOT_FOUND'){ + return false; }elseif(substr($regs[0],0,29)=='NT_STATUS_FILE_IS_A_DIRECTORY'){ return false; } trigger_error($regs[0].' params('.$params.')', E_USER_ERROR); case 'error-connect': - return false; + // connection error can happen after obtaining share list if + // NetBIOS is disabled/blocked on the target server, + // in which case we keep the info and continue + if (!$gotInfo) { + return false; + } } if ($i) switch ($i[1]) { case 'file': @@ -194,6 +206,7 @@ class smb { case 'disk': case 'server': case 'workgroup': $info[$i[1]][] = $i[0]; + $gotInfo = true; } } pclose($output); @@ -293,6 +306,7 @@ class smb { } function rename ($url_from, $url_to) { + $replace = false; list ($from, $to) = array (smb::parse_url($url_from), smb::parse_url($url_to)); if ($from['host'] <> $to['host'] || $from['share'] <> $to['share'] || @@ -305,7 +319,21 @@ class smb { trigger_error('rename(): error in URL', E_USER_ERROR); } smb::clearstatcache ($url_from); - return smb::execute ('rename "'.$from['path'].'" "'.$to['path'].'"', $to); + $cmd = ''; + // check if target file exists + if (smb::url_stat($url_to)) { + // delete target file first + $cmd = 'del "' . $to['path'] . '"; '; + $replace = true; + } + $cmd .= 'rename "' . $from['path'] . '" "' . $to['path'] . '"'; + $result = smb::execute($cmd, $to); + if ($replace) { + // clear again, else the cache will return the info + // from the old file + smb::clearstatcache ($url_to); + } + return $result !== false; } function mkdir ($url, $mode, $options) { @@ -430,7 +458,10 @@ class smb_stream_wrapper extends smb { case 'rb': case 'a': case 'a+': $this->tmpfile = tempnam('/tmp', 'smb.down.'); - smb::execute ('get "'.$pu['path'].'" "'.$this->tmpfile.'"', $pu); + $result = smb::execute ('get "'.$pu['path'].'" "'.$this->tmpfile.'"', $pu); + if($result === false){ + return $result; + } break; case 'w': case 'w+': @@ -454,7 +485,8 @@ class smb_stream_wrapper extends smb { function stream_tell () { return ftell($this->stream); } - function stream_seek ($offset, $whence=null) { return fseek($this->stream, $offset, $whence); } + // PATCH: the wrapper must return true when fseek succeeded by returning 0. + function stream_seek ($offset, $whence=null) { return fseek($this->stream, $offset, $whence) === 0; } function stream_flush () { if ($this->mode <> 'r' && $this->need_flush) { diff --git a/apps/files_external/ajax/dropbox.php b/apps/files_external/ajax/dropbox.php index bc9821c62ec..91c465500d0 100644 --- a/apps/files_external/ajax/dropbox.php +++ b/apps/files_external/ajax/dropbox.php @@ -1,6 +1,6 @@ <?php -require_once 'Dropbox/autoload.php'; +require_once __DIR__ . '/../3rdparty/Dropbox/autoload.php'; OCP\JSON::checkAppEnabled('files_external'); OCP\JSON::checkLoggedIn(); diff --git a/apps/files_external/appinfo/app.php b/apps/files_external/appinfo/app.php index dd0b76ed9d7..5b1cd86a170 100644 --- a/apps/files_external/appinfo/app.php +++ b/apps/files_external/appinfo/app.php @@ -9,8 +9,9 @@ OC::$CLASSPATH['OC\Files\Storage\StreamWrapper'] = 'files_external/lib/streamwrapper.php'; OC::$CLASSPATH['OC\Files\Storage\FTP'] = 'files_external/lib/ftp.php'; OC::$CLASSPATH['OC\Files\Storage\DAV'] = 'files_external/lib/webdav.php'; +OC::$CLASSPATH['OC\Files\Storage\OwnCloud'] = 'files_external/lib/owncloud.php'; OC::$CLASSPATH['OC\Files\Storage\Google'] = 'files_external/lib/google.php'; -OC::$CLASSPATH['OC\Files\Storage\SWIFT'] = 'files_external/lib/swift.php'; +OC::$CLASSPATH['OC\Files\Storage\Swift'] = 'files_external/lib/swift.php'; OC::$CLASSPATH['OC\Files\Storage\SMB'] = 'files_external/lib/smb.php'; OC::$CLASSPATH['OC\Files\Storage\AmazonS3'] = 'files_external/lib/amazons3.php'; OC::$CLASSPATH['OC\Files\Storage\Dropbox'] = 'files_external/lib/dropbox.php'; diff --git a/apps/files_external/css/settings.css b/apps/files_external/css/settings.css index 4a32ac4153f..11aeb10184b 100644 --- a/apps/files_external/css/settings.css +++ b/apps/files_external/css/settings.css @@ -4,7 +4,6 @@ td.status > span { width: 16px; vertical-align: text-bottom; } - span.success { background: #37ce02; border-radius: 8px; @@ -12,9 +11,6 @@ span.success { span.error { background: #ce3702; } -span.waiting { - background: none; -} td.mountPoint, td.backend { width:160px; } td.remove>img { visibility:hidden; padding-top:13px; } @@ -22,3 +18,7 @@ tr:hover>td.remove>img { visibility:visible; cursor:pointer; } #addMountPoint>td { border:none; } #addMountPoint>td.applicable { visibility:hidden; } #selectBackend { margin-left:-10px; } + +#externalStorage label > input[type="checkbox"] { + margin-right: 3px; +} diff --git a/apps/files_external/js/dropbox.js b/apps/files_external/js/dropbox.js index 957daeb4d1f..6baaabe11b6 100644 --- a/apps/files_external/js/dropbox.js +++ b/apps/files_external/js/dropbox.js @@ -23,9 +23,12 @@ $(document).ready(function() { $(token).val(result.access_token); $(token_secret).val(result.access_token_secret); $(configured).val('true'); - OC.MountConfig.saveStorage(tr); - $(tr).find('.configuration input').attr('disabled', 'disabled'); - $(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>'); + OC.MountConfig.saveStorage(tr, function(status) { + if (status) { + $(tr).find('.configuration input').attr('disabled', 'disabled'); + $(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>'); + } + }); } else { OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage')); } @@ -77,7 +80,6 @@ $(document).ready(function() { var tr = $(this).parent().parent(); var app_key = $(this).parent().find('[data-parameter="app_key"]').val(); var app_secret = $(this).parent().find('[data-parameter="app_secret"]').val(); - var statusSpan = $(tr).find('.status span'); if (app_key != '' && app_secret != '') { var tr = $(this).parent().parent(); var configured = $(this).parent().find('[data-parameter="configured"]'); @@ -88,10 +90,9 @@ $(document).ready(function() { $(configured).val('false'); $(token).val(result.data.request_token); $(token_secret).val(result.data.request_token_secret); - OC.MountConfig.saveStorage(tr); - statusSpan.removeClass(); - statusSpan.addClass('waiting'); - window.location = result.data.url; + OC.MountConfig.saveStorage(tr, function() { + window.location = result.data.url; + }); } else { OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage')); } diff --git a/apps/files_external/js/google.js b/apps/files_external/js/google.js index b4be1c1dc41..068c2c13c66 100644 --- a/apps/files_external/js/google.js +++ b/apps/files_external/js/google.js @@ -32,11 +32,14 @@ $(document).ready(function() { if (result && result.status == 'success') { $(token).val(result.data.token); $(configured).val('true'); - OC.MountConfig.saveStorage(tr); - $(tr).find('.configuration input').attr('disabled', 'disabled'); - $(tr).find('.configuration').append($('<span/>') - .attr('id', 'access') - .text(t('files_external', 'Access granted'))); + OC.MountConfig.saveStorage(tr, function(status) { + if (status) { + $(tr).find('.configuration input').attr('disabled', 'disabled'); + $(tr).find('.configuration').append($('<span/>') + .attr('id', 'access') + .text(t('files_external', 'Access granted'))); + } + }); } else { OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Google Drive storage') @@ -99,7 +102,6 @@ $(document).ready(function() { var configured = $(this).parent().find('[data-parameter="configured"]'); var client_id = $(this).parent().find('[data-parameter="client_id"]').val(); var client_secret = $(this).parent().find('[data-parameter="client_secret"]').val(); - var statusSpan = $(tr).find('.status span'); if (client_id != '' && client_secret != '') { var token = $(this).parent().find('[data-parameter="token"]'); $.post(OC.filePath('files_external', 'ajax', 'google.php'), @@ -112,10 +114,9 @@ $(document).ready(function() { if (result && result.status == 'success') { $(configured).val('false'); $(token).val('false'); - OC.MountConfig.saveStorage(tr); - statusSpan.removeClass(); - statusSpan.addClass('waiting'); - window.location = result.data.url; + OC.MountConfig.saveStorage(tr, function(status) { + window.location = result.data.url; + }); } else { OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Google Drive storage') diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index 3e605c59a93..895f97bd2c3 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -1,10 +1,23 @@ +(function(){ + +function updateStatus(statusEl, result){ + statusEl.removeClass('success error loading-small'); + if (result && result.status == 'success' && result.data.message) { + statusEl.addClass('success'); + return true; + } else { + statusEl.addClass('error'); + return false; + } +} + OC.MountConfig={ - saveStorage:function(tr) { + saveStorage:function(tr, callback) { var mountPoint = $(tr).find('.mountPoint input').val(); if (mountPoint == '') { return false; } - var statusSpan = $(tr).find('.status span'); + var statusSpan = $(tr).closest('tr').find('.status span'); var backendClass = $(tr).find('.backend').data('class'); var configuration = $(tr).find('.configuration input'); var addMountPoint = true; @@ -58,6 +71,7 @@ OC.MountConfig={ } users.push(applicable); } + statusSpan.addClass('loading-small').removeClass('error success'); $.ajax({type: 'POST', url: OC.filePath('files_external', 'ajax', 'addMountPoint.php'), data: { @@ -68,14 +82,16 @@ OC.MountConfig={ applicable: applicable, isPersonal: isPersonal }, - async: false, success: function(result) { - statusSpan.removeClass(); - if (result && result.status == 'success' && result.data.message) { - status = true; - statusSpan.addClass('success'); - } else { - statusSpan.addClass('error'); + status = updateStatus(statusSpan, result); + if (callback) { + callback(status); + } + }, + error: function(result){ + status = updateStatus(statusSpan, result); + if (callback) { + callback(status); } } }); @@ -93,8 +109,7 @@ OC.MountConfig={ mountType: mountType, applicable: applicable, isPersonal: isPersonal - }, - async: false + } }); }); var mountType = 'user'; @@ -108,14 +123,14 @@ OC.MountConfig={ mountType: mountType, applicable: applicable, isPersonal: isPersonal - }, - async: false + } }); }); } else { var isPersonal = true; var mountType = 'user'; var applicable = OC.currentUser; + statusSpan.addClass('loading-small').removeClass('error success'); $.ajax({type: 'POST', url: OC.filePath('files_external', 'ajax', 'addMountPoint.php'), data: { @@ -126,14 +141,16 @@ OC.MountConfig={ applicable: applicable, isPersonal: isPersonal }, - async: false, success: function(result) { - statusSpan.removeClass(); - if (result && result.status == 'success' && result.data.message) { - status = true; - statusSpan.addClass('success'); - } else { - statusSpan.addClass('error'); + status = updateStatus(statusSpan, result); + if (callback) { + callback(status); + } + }, + error: function(result){ + status = updateStatus(statusSpan, result); + if (callback) { + callback(status); } } }); @@ -157,7 +174,7 @@ $(document).ready(function() { $(tr).find('.mountPoint input').val(suggestMountPoint(selected)); } $(tr).addClass(backendClass); - $(tr).find('.status').append('<span class="waiting"></span>'); + $(tr).find('.status').append('<span></span>'); $(tr).find('.backend').data('class', backendClass); var configurations = $(this).data('configurations'); var td = $(tr).find('td.configuration'); @@ -293,3 +310,5 @@ $(document).ready(function() { }); }); + +})(); diff --git a/apps/files_external/l10n/ar.php b/apps/files_external/l10n/ar.php index 905d221e886..338526d2afd 100644 --- a/apps/files_external/l10n/ar.php +++ b/apps/files_external/l10n/ar.php @@ -1,5 +1,8 @@ <?php $TRANSLATIONS = array( +"Folder name" => "اسم المجلد", +"Options" => "خيارات", +"All Users" => "كل المستخدمين", "Groups" => "مجموعات", "Users" => "المستخدمين", "Delete" => "إلغاء" diff --git a/apps/files_external/l10n/es_MX.php b/apps/files_external/l10n/es_MX.php new file mode 100644 index 00000000000..b508df8476a --- /dev/null +++ b/apps/files_external/l10n/es_MX.php @@ -0,0 +1,28 @@ +<?php +$TRANSLATIONS = array( +"Access granted" => "Acceso concedido", +"Error configuring Dropbox storage" => "Error configurando el almacenamiento de Dropbox", +"Grant access" => "Conceder acceso", +"Please provide a valid Dropbox app key and secret." => "Por favor, proporcione un una clave válida de la app Dropbox y una clave secreta.", +"Error configuring Google Drive storage" => "Error configurando el almacenamiento de Google Drive", +"<b>Warning:</b> \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "<b>Advertencia:</b> El cliente \"smbclient\" no se encuentra instalado. El montado de carpetas CIFS/SMB no es posible. Por favor pida al administrador de su sistema que lo instale.", +"<b>Warning:</b> The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "<b>Advertencia:</b> El soporte de FTP en PHP no se encuentra instalado. El montado de carpetas FTP no es posible. Por favor pida al administrador de su sistema que lo instale.", +"<b>Warning:</b> The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "<b>Advertencia:</b> El soporte de Curl en PHP no está activado ni instalado. El montado de ownCloud, WebDAV o GoogleDrive no es posible. Pida al administrador de su sistema que lo instale.", +"External Storage" => "Almacenamiento externo", +"Folder name" => "Nombre de la carpeta", +"External storage" => "Almacenamiento externo", +"Configuration" => "Configuración", +"Options" => "Opciones", +"Applicable" => "Aplicable", +"Add storage" => "Añadir almacenamiento", +"None set" => "No se ha configurado", +"All Users" => "Todos los usuarios", +"Groups" => "Grupos", +"Users" => "Usuarios", +"Delete" => "Eliminar", +"Enable User External Storage" => "Habilitar almacenamiento externo de usuario", +"Allow users to mount their own external storage" => "Permitir a los usuarios montar su propio almacenamiento externo", +"SSL root certificates" => "Certificados raíz SSL", +"Import Root Certificate" => "Importar certificado raíz" +); +$PLURAL_FORMS = "nplurals=2; plural=(n != 1);"; diff --git a/apps/files_external/l10n/km.php b/apps/files_external/l10n/km.php new file mode 100644 index 00000000000..f7d9faa38c5 --- /dev/null +++ b/apps/files_external/l10n/km.php @@ -0,0 +1,5 @@ +<?php +$TRANSLATIONS = array( +"Delete" => "លុប" +); +$PLURAL_FORMS = "nplurals=1; plural=0;"; diff --git a/apps/files_external/l10n/sk.php b/apps/files_external/l10n/sk.php new file mode 100644 index 00000000000..3129cf5c411 --- /dev/null +++ b/apps/files_external/l10n/sk.php @@ -0,0 +1,5 @@ +<?php +$TRANSLATIONS = array( +"Delete" => "Odstrániť" +); +$PLURAL_FORMS = "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"; diff --git a/apps/files_external/l10n/sk_SK.php b/apps/files_external/l10n/sk_SK.php index ca445387bca..664d97c43b2 100644 --- a/apps/files_external/l10n/sk_SK.php +++ b/apps/files_external/l10n/sk_SK.php @@ -9,7 +9,7 @@ $TRANSLATIONS = array( "<b>Warning:</b> The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "<b>Upozornenie:</b> Podpora FTP v PHP nie je povolená alebo nainštalovaná. Nie je možné pripojenie oddielov FTP. Požiadajte administrátora systému, nech ho nainštaluje.", "<b>Warning:</b> The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "<b>Varovanie:</b> nie je nainštalovaná, alebo povolená, podpora Curl v PHP. Nie je možné pripojenie oddielov ownCloud, WebDAV, či GoogleDrive. Prosím požiadajte svojho administrátora systému, nech ju nainštaluje.", "External Storage" => "Externé úložisko", -"Folder name" => "Meno priečinka", +"Folder name" => "Názov priečinka", "External storage" => "Externé úložisko", "Configuration" => "Nastavenia", "Options" => "Možnosti", @@ -21,7 +21,7 @@ $TRANSLATIONS = array( "Users" => "Používatelia", "Delete" => "Zmazať", "Enable User External Storage" => "Povoliť externé úložisko", -"Allow users to mount their own external storage" => "Povoliť používateľom pripojiť ich vlastné externé úložisko", +"Allow users to mount their own external storage" => "Povoliť používateľom pripojiť si vlastné externé úložisko", "SSL root certificates" => "Koreňové SSL certifikáty", "Import Root Certificate" => "Importovať koreňový certifikát" ); diff --git a/apps/files_external/l10n/sq.php b/apps/files_external/l10n/sq.php index 42de15edadc..328822dcde8 100644 --- a/apps/files_external/l10n/sq.php +++ b/apps/files_external/l10n/sq.php @@ -1,5 +1,6 @@ <?php $TRANSLATIONS = array( +"Groups" => "Grupet", "Users" => "Përdoruesit", "Delete" => "Elimino" ); diff --git a/apps/files_external/l10n/tr.php b/apps/files_external/l10n/tr.php index cc52c425b8d..5d5e2b726a9 100644 --- a/apps/files_external/l10n/tr.php +++ b/apps/files_external/l10n/tr.php @@ -5,12 +5,12 @@ $TRANSLATIONS = array( "Grant access" => "Erişim sağlandı", "Please provide a valid Dropbox app key and secret." => "Lütfen Dropbox app key ve secret temin ediniz", "Error configuring Google Drive storage" => "Google Drive depo yapılandırma hatası", -"<b>Warning:</b> \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "<b>Uyari.</b>''smbclient''yüklü değil. Mont etme CIFS/SMB hissenin mümkün değildir. Lutfen kullanici sistemin sormak onu yuklemek ici, ", -"<b>Warning:</b> The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "<Uyari.</b>. Sistem FTP PHPden aktif degil veya yuklemedi. Monte etme hissenin FTP mumkun degildir. Lutfen kullaniici sistemin sormak onu yuklemek icin.", -"<b>Warning:</b> The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "<b> Ihbar </b>. Dayanma Curl PHPden aktif veya yuklemedi degil. Monte ownClouden/WebDay veya GoogleDrive mumkun degil. Lutfen sistm yonetici sormak yuklemek icin. ", +"<b>Warning:</b> \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "<b>Uyarı:</b> \"smbclient\" kurulu değil. CIFS/SMB paylaşımlarını bağlama işlemi mümkün olmadı. Lütfen kurulumu için sistem yöneticinize danışın.", +"<b>Warning:</b> The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "<b>Uyarı:</b> PHP içerisinde FTP desteği etkin veya yüklü değil. FTP paylaşımlarını bağlama işlemi mümkün olmadı. Lütfen kurulumu için sistem yöneticinize danışın.", +"<b>Warning:</b> The Curl support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV or GoogleDrive is not possible. Please ask your system administrator to install it." => "<b>Uyarı:</b> PHP içerisinde Curl desteği etkin veya yüklü değil. OwnCloud / WebDAV veya GoogleDrive bağlama işlemi mümkün olmadı. Lütfen kurulumu için sistem yöneticinizde danışın.", "External Storage" => "Harici Depolama", "Folder name" => "Dizin ismi", -"External storage" => "Harici Depolama", +"External storage" => "Harici depolama", "Configuration" => "Yapılandırma", "Options" => "Seçenekler", "Applicable" => "Uygulanabilir", diff --git a/apps/files_external/lib/amazons3.php b/apps/files_external/lib/amazons3.php index c08a266b48c..00baacd488c 100644 --- a/apps/files_external/lib/amazons3.php +++ b/apps/files_external/lib/amazons3.php @@ -81,9 +81,9 @@ class AmazonS3 extends \OC\Files\Storage\Common { $scheme = ($params['use_ssl'] === 'false') ? 'http' : 'https'; $this->test = isset($params['test']); $this->timeout = ( ! isset($params['timeout'])) ? 15 : $params['timeout']; - $params['region'] = ( ! isset($params['region'])) ? 'eu-west-1' : $params['region']; - $params['hostname'] = ( !isset($params['hostname'])) ? 's3.amazonaws.com' : $params['hostname']; - if (!isset($params['port'])) { + $params['region'] = ( ! isset($params['region']) || $params['region'] === '' ) ? 'eu-west-1' : $params['region']; + $params['hostname'] = ( !isset($params['hostname']) || $params['hostname'] === '' ) ? 's3.amazonaws.com' : $params['hostname']; + if (!isset($params['port']) || $params['port'] === '') { $params['port'] = ($params['use_ssl'] === 'false') ? 80 : 443; } $base_url = $scheme.'://'.$params['hostname'].':'.$params['port'].'/'; @@ -300,14 +300,6 @@ class AmazonS3 extends \OC\Files\Storage\Common { return false; } - public function isReadable($path) { - return true; - } - - public function isUpdatable($path) { - return true; - } - public function unlink($path) { $path = $this->normalizePath($path); @@ -515,8 +507,10 @@ class AmazonS3 extends \OC\Files\Storage\Common { } public function test() { - $test = $this->s3->get_canonical_user_id(); - if (isset($test['id']) && $test['id'] != '') { + $test = $this->connection->getBucketAcl(array( + 'Bucket' => $this->bucket, + )); + if (isset($test) && !is_null($test->getPath('Owner/ID'))) { return true; } return false; diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php index 659959e662e..01d588b3721 100755 --- a/apps/files_external/lib/config.php +++ b/apps/files_external/lib/config.php @@ -50,9 +50,9 @@ class OC_Mount_Config { 'key' => 'Access Key', 'secret' => '*Secret Key', 'bucket' => 'Bucket', - 'hostname' => 'Hostname (optional)', - 'port' => 'Port (optional)', - 'region' => 'Region (optional)', + 'hostname' => '&Hostname (optional)', + 'port' => '&Port (optional)', + 'region' => '&Region (optional)', 'use_ssl' => '!Enable SSL', 'use_path_style' => '!Enable Path Style')); @@ -84,14 +84,22 @@ class OC_Mount_Config { 'token' => '#token'), 'custom' => 'google'); - $backends['\OC\Files\Storage\SWIFT']=array( - 'backend' => 'OpenStack Swift', - 'configuration' => array( - 'host' => 'URL', - 'user' => 'Username', - 'token' => '*Token', - 'root' => '&Root', - 'secure' => '!Secure ftps://')); + if(OC_Mount_Config::checkcurl()) { + $backends['\OC\Files\Storage\Swift'] = array( + 'backend' => 'OpenStack Object Storage', + 'configuration' => array( + 'user' => 'Username (required)', + 'bucket' => 'Bucket (required)', + 'region' => '&Region (optional for OpenStack Object Storage)', + 'key' => '*API Key (required for Rackspace Cloud Files)', + 'tenant' => '&Tenantname (required for OpenStack Object Storage)', + 'password' => '*Password (required for OpenStack Object Storage)', + 'service_name' => '&Service Name (required for OpenStack Object Storage)', + 'url' => '&URL of identity endpoint (required for OpenStack Object Storage)', + 'timeout' => '&Timeout of HTTP requests in seconds (optional)', + ) + ); + } if (!OC_Util::runningOnWindows()) { if (OC_Mount_Config::checksmbclient()) { @@ -106,14 +114,24 @@ class OC_Mount_Config { } } - if(OC_Mount_Config::checkcurl()) $backends['\OC\Files\Storage\DAV']=array( - 'backend' => 'ownCloud / WebDAV', - 'configuration' => array( - 'host' => 'URL', - 'user' => 'Username', - 'password' => '*Password', - 'root' => '&Root', - 'secure' => '!Secure https://')); + if(OC_Mount_Config::checkcurl()){ + $backends['\OC\Files\Storage\DAV']=array( + 'backend' => 'WebDAV', + 'configuration' => array( + 'host' => 'URL', + 'user' => 'Username', + 'password' => '*Password', + 'root' => '&Root', + 'secure' => '!Secure https://')); + $backends['\OC\Files\Storage\OwnCloud']=array( + 'backend' => 'ownCloud', + 'configuration' => array( + 'host' => 'URL', + 'user' => 'Username', + 'password' => '*Password', + 'root' => '&Remote subfolder', + 'secure' => '!Secure https://')); + } $backends['\OC\Files\Storage\SFTP']=array( 'backend' => 'SFTP', @@ -236,6 +254,7 @@ class OC_Mount_Config { $storage = new $class($options); return $storage->test(); } catch (Exception $exception) { + \OCP\Util::logException('files_external', $exception); return false; } } @@ -258,6 +277,11 @@ class OC_Mount_Config { $mountType, $applicable, $isPersonal = false) { + $mountPoint = OC\Files\Filesystem::normalizePath($mountPoint); + if ($mountPoint === '' || $mountPoint === '/' || $mountPoint == '/Shared') { + // can't mount at root or "Shared" folder + return false; + } if ($isPersonal) { // Verify that the mount point applies for the current user // Prevent non-admin users from mounting local storage @@ -368,8 +392,7 @@ class OC_Mount_Config { * @return array */ public static function getCertificates() { - $view = \OCP\Files::getStorage('files_external'); - $path=\OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath("").'uploads/'; + $path=OC_User::getHome(OC_User::getUser()) . '/files_external/uploads/'; \OCP\Util::writeLog('files_external', 'checking path '.$path, \OCP\Util::INFO); if ( ! is_dir($path)) { //path might not exist (e.g. non-standard OC_User::getHome() value) @@ -391,8 +414,7 @@ class OC_Mount_Config { * creates certificate bundle */ public static function createCertificateBundle() { - $view = \OCP\Files::getStorage("files_external"); - $path = \OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath(""); + $path=OC_User::getHome(OC_User::getUser()) . '/files_external'; $certs = OC_Mount_Config::getCertificates(); $fh_certs = fopen($path."/rootcerts.crt", 'w'); @@ -417,7 +439,7 @@ class OC_Mount_Config { */ public static function checksmbclient() { if(function_exists('shell_exec')) { - $output=shell_exec('which smbclient'); + $output=shell_exec('which smbclient 2> /dev/null'); return !empty($output); }else{ return false; diff --git a/apps/files_external/lib/dropbox.php b/apps/files_external/lib/dropbox.php index b6deab6e5a7..f7d8d98cf03 100755 --- a/apps/files_external/lib/dropbox.php +++ b/apps/files_external/lib/dropbox.php @@ -50,6 +50,22 @@ class Dropbox extends \OC\Files\Storage\Common { } } + private function deleteMetaData($path) { + $path = $this->root.$path; + if (isset($this->metaData[$path])) { + unset($this->metaData[$path]); + return true; + } + return false; + } + + /** + * @brief Returns the path's metadata + * @param $path path for which to return the metadata + * @param $list if true, also return the directory's contents + * @return directory contents if $list is true, file metadata if $list is + * false, null if the file doesn't exist or "false" if the operation failed + */ private function getMetaData($path, $list = false) { $path = $this->root.$path; if ( ! $list && isset($this->metaData[$path])) { @@ -62,24 +78,35 @@ class Dropbox extends \OC\Files\Storage\Common { \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); return false; } + $contents = array(); if ($response && isset($response['contents'])) { - $contents = $response['contents']; // Cache folder's contents - foreach ($contents as $file) { - $this->metaData[$path.'/'.basename($file['path'])] = $file; + foreach ($response['contents'] as $file) { + if (!isset($file['is_deleted']) || !$file['is_deleted']) { + $this->metaData[$path.'/'.basename($file['path'])] = $file; + $contents[] = $file; + } } unset($response['contents']); + } + if (!isset($response['is_deleted']) || !$response['is_deleted']) { $this->metaData[$path] = $response; } - $this->metaData[$path] = $response; // Return contents of folder only return $contents; } else { try { $response = $this->dropbox->getMetaData($path, 'false'); - $this->metaData[$path] = $response; - return $response; + if (!isset($response['is_deleted']) || !$response['is_deleted']) { + $this->metaData[$path] = $response; + return $response; + } + return null; } catch (\Exception $exception) { + if ($exception instanceof \Dropbox_Exception_NotFound) { + // don't log, might be a file_exist check + return false; + } \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); return false; } @@ -108,7 +135,7 @@ class Dropbox extends \OC\Files\Storage\Common { public function opendir($path) { $contents = $this->getMetaData($path, true); - if ($contents) { + if ($contents !== false) { $files = array(); foreach ($contents as $file) { $files[] = basename($file['path']); @@ -146,14 +173,6 @@ class Dropbox extends \OC\Files\Storage\Common { return false; } - public function isReadable($path) { - return $this->file_exists($path); - } - - public function isUpdatable($path) { - return $this->file_exists($path); - } - public function file_exists($path) { if ($path == '' || $path == '/') { return true; @@ -165,9 +184,9 @@ class Dropbox extends \OC\Files\Storage\Common { } public function unlink($path) { - $path = $this->root.$path; try { - $this->dropbox->delete($path); + $this->dropbox->delete($this->root.$path); + $this->deleteMetaData($path); return true; } catch (\Exception $exception) { \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); @@ -176,10 +195,14 @@ class Dropbox extends \OC\Files\Storage\Common { } public function rename($path1, $path2) { - $path1 = $this->root.$path1; - $path2 = $this->root.$path2; try { - $this->dropbox->move($path1, $path2); + // overwrite if target file exists and is not a directory + $destMetaData = $this->getMetaData($path2); + if (isset($destMetaData) && $destMetaData !== false && !$destMetaData['is_dir']) { + $this->unlink($path2); + } + $this->dropbox->move($this->root.$path1, $this->root.$path2); + $this->deleteMetaData($path1); return true; } catch (\Exception $exception) { \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR); @@ -277,7 +300,12 @@ class Dropbox extends \OC\Files\Storage\Common { } public function touch($path, $mtime = null) { - return false; + if ($this->file_exists($path)) { + return false; + } else { + $this->file_put_contents($path, ''); + } + return true; } } diff --git a/apps/files_external/lib/ftp.php b/apps/files_external/lib/ftp.php index ca6c635eb2b..00bf7a189ce 100644 --- a/apps/files_external/lib/ftp.php +++ b/apps/files_external/lib/ftp.php @@ -35,6 +35,9 @@ class FTP extends \OC\Files\Storage\StreamWrapper{ if ( ! $this->root || $this->root[0]!='/') { $this->root='/'.$this->root; } + if (substr($this->root, -1) !== '/') { + $this->root .= '/'; + } } else { throw new \Exception(); } @@ -58,6 +61,22 @@ class FTP extends \OC\Files\Storage\StreamWrapper{ $url.='://'.$this->user.':'.$this->password.'@'.$this->host.$this->root.$path; return $url; } + + /** + * Unlinks file or directory + * @param string @path + */ + public function unlink($path) { + if ($this->is_dir($path)) { + return $this->rmdir($path); + } + else { + $url = $this->constructUrl($path); + $result = unlink($url); + clearstatcache(true, $url); + return $result; + } + } public function fopen($path,$mode) { switch($mode) { case 'r': diff --git a/apps/files_external/lib/google.php b/apps/files_external/lib/google.php index b63b5885de1..426caf008ec 100644 --- a/apps/files_external/lib/google.php +++ b/apps/files_external/lib/google.php @@ -317,10 +317,6 @@ class Google extends \OC\Files\Storage\Common { } } - public function isReadable($path) { - return $this->file_exists($path); - } - public function isUpdatable($path) { $file = $this->getDriveFile($path); if ($file) { diff --git a/apps/files_external/lib/owncloud.php b/apps/files_external/lib/owncloud.php new file mode 100644 index 00000000000..98314102a64 --- /dev/null +++ b/apps/files_external/lib/owncloud.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright (c) 2013 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage; + +/** + * ownCloud backend for external storage based on DAV backend. + * + * The ownCloud URL consists of three parts: + * http://%host/%context/remote.php/webdav/%root + * + */ +class OwnCloud extends \OC\Files\Storage\DAV{ + const OC_URL_SUFFIX = 'remote.php/webdav'; + + public function __construct($params) { + // extract context path from host if specified + // (owncloud install path on host) + $host = $params['host']; + $contextPath = ''; + $hostSlashPos = strpos($host, '/'); + if ($hostSlashPos !== false){ + $contextPath = substr($host, $hostSlashPos); + $host = substr($host, 0, $hostSlashPos); + } + + if (substr($contextPath , 1) !== '/'){ + $contextPath .= '/'; + } + + if (isset($params['root'])){ + $root = $params['root']; + if (substr($root, 1) !== '/'){ + $root = '/' . $root; + } + } + else{ + $root = '/'; + } + + $params['host'] = $host; + $params['root'] = $contextPath . self::OC_URL_SUFFIX . $root; + + parent::__construct($params); + } +} diff --git a/apps/files_external/lib/sftp.php b/apps/files_external/lib/sftp.php index f7f329b8993..95e0cefa398 100644 --- a/apps/files_external/lib/sftp.php +++ b/apps/files_external/lib/sftp.php @@ -29,83 +29,97 @@ class SFTP extends \OC\Files\Storage\Common { } $this->user = $params['user']; $this->password = $params['password']; - $this->root = isset($params['root']) ? $this->cleanPath($params['root']) : '/'; - if ($this->root[0] != '/') $this->root = '/' . $this->root; - if (substr($this->root, -1, 1) != '/') $this->root .= '/'; + $this->root + = isset($params['root']) ? $this->cleanPath($params['root']) : '/'; - $host_keys = $this->read_host_keys(); + if ($this->root[0] != '/') { + $this->root = '/' . $this->root; + } + + if (substr($this->root, -1, 1) != '/') { + $this->root .= '/'; + } + $hostKeys = $this->readHostKeys(); $this->client = new \Net_SFTP($this->host); + if (!$this->client->login($this->user, $this->password)) { throw new \Exception('Login failed'); } - $current_host_key = $this->client->getServerPublicHostKey(); + $currentHostKey = $this->client->getServerPublicHostKey(); - if (array_key_exists($this->host, $host_keys)) { - if ($host_keys[$this->host] != $current_host_key) { + if (array_key_exists($this->host, $hostKeys)) { + if ($hostKeys[$this->host] != $currentHostKey) { throw new \Exception('Host public key does not match known key'); } } else { - $host_keys[$this->host] = $current_host_key; - $this->write_host_keys($host_keys); + $hostKeys[$this->host] = $currentHostKey; + $this->writeHostKeys($hostKeys); } } public function test() { - if (!isset($params['host']) || !isset($params['user']) || !isset($params['password'])) { - throw new \Exception("Required parameters not set"); + if ( + !isset($this->host) + || !isset($this->user) + || !isset($this->password) + ) { + return false; } + return $this->client->nlist() !== false; } public function getId(){ return 'sftp::' . $this->user . '@' . $this->host . '/' . $this->root; } - private function abs_path($path) { + private function absPath($path) { return $this->root . $this->cleanPath($path); } - private function host_keys_path() { + private function hostKeysPath() { try { $storage_view = \OCP\Files::getStorage('files_external'); if ($storage_view) { return \OCP\Config::getSystemValue('datadirectory') . $storage_view->getAbsolutePath('') . - 'ssh_host_keys'; + 'ssh_hostKeys'; } } catch (\Exception $e) { } return false; } - private function write_host_keys($keys) { + private function writeHostKeys($keys) { try { - $key_path = $this->host_keys_path(); - $fp = fopen($key_path, 'w'); - foreach ($keys as $host => $key) { - fwrite($fp, $host . '::' . $key . "\n"); + $keyPath = $this->hostKeysPath(); + if ($keyPath && file_exists($keyPath)) { + $fp = fopen($keyPath, 'w'); + foreach ($keys as $host => $key) { + fwrite($fp, $host . '::' . $key . "\n"); + } + fclose($fp); + return true; } - fclose($fp); - return true; } catch (\Exception $e) { - return false; } + return false; } - private function read_host_keys() { + private function readHostKeys() { try { - $key_path = $this->host_keys_path(); - if (file_exists($key_path)) { + $keyPath = $this->hostKeysPath(); + if (file_exists($keyPath)) { $hosts = array(); $keys = array(); - $lines = file($key_path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $lines = file($keyPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); if ($lines) { foreach ($lines as $line) { - $host_key_arr = explode("::", $line, 2); - if (count($host_key_arr) == 2) { - $hosts[] = $host_key_arr[0]; - $keys[] = $host_key_arr[1]; + $hostKeyArray = explode("::", $line, 2); + if (count($hostKeyArray) == 2) { + $hosts[] = $hostKeyArray[0]; + $keys[] = $hostKeyArray[1]; } } return array_combine($hosts, $keys); @@ -118,7 +132,7 @@ class SFTP extends \OC\Files\Storage\Common { public function mkdir($path) { try { - return $this->client->mkdir($this->abs_path($path)); + return $this->client->mkdir($this->absPath($path)); } catch (\Exception $e) { return false; } @@ -126,7 +140,7 @@ class SFTP extends \OC\Files\Storage\Common { public function rmdir($path) { try { - return $this->client->delete($this->abs_path($path), true); + return $this->client->delete($this->absPath($path), true); } catch (\Exception $e) { return false; } @@ -134,16 +148,16 @@ class SFTP extends \OC\Files\Storage\Common { public function opendir($path) { try { - $list = $this->client->nlist($this->abs_path($path)); + $list = $this->client->nlist($this->absPath($path)); $id = md5('sftp:' . $path); - $dir_stream = array(); + $dirStream = array(); foreach($list as $file) { if ($file != '.' && $file != '..') { - $dir_stream[] = $file; + $dirStream[] = $file; } } - \OC\Files\Stream\Dir::register($id, $dir_stream); + \OC\Files\Stream\Dir::register($id, $dirStream); return opendir('fakedir://' . $id); } catch(\Exception $e) { return false; @@ -152,25 +166,23 @@ class SFTP extends \OC\Files\Storage\Common { public function filetype($path) { try { - $stat = $this->client->stat($this->abs_path($path)); - if ($stat['type'] == NET_SFTP_TYPE_REGULAR) return 'file'; - if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) return 'dir'; + $stat = $this->client->stat($this->absPath($path)); + if ($stat['type'] == NET_SFTP_TYPE_REGULAR) { + return 'file'; + } + + if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) { + return 'dir'; + } } catch (\Exeption $e) { + } return false; } - public function isReadable($path) { - return true; - } - - public function isUpdatable($path) { - return true; - } - public function file_exists($path) { try { - return $this->client->stat($this->abs_path($path)) !== false; + return $this->client->stat($this->absPath($path)) !== false; } catch (\Exception $e) { return false; } @@ -178,7 +190,7 @@ class SFTP extends \OC\Files\Storage\Common { public function unlink($path) { try { - return $this->client->delete($this->abs_path($path), true); + return $this->client->delete($this->absPath($path), true); } catch (\Exception $e) { return false; } @@ -186,18 +198,21 @@ class SFTP extends \OC\Files\Storage\Common { public function fopen($path, $mode) { try { - $abs_path = $this->abs_path($path); + $absPath = $this->absPath($path); switch($mode) { case 'r': case 'rb': - if ( !$this->file_exists($path)) return false; + if ( !$this->file_exists($path)) { + return false; + } + if (strrpos($path, '.')!==false) { $ext=substr($path, strrpos($path, '.')); } else { $ext=''; } $tmp = \OC_Helper::tmpFile($ext); - $this->getFile($abs_path, $tmp); + $this->getFile($absPath, $tmp); return fopen($tmp, $mode); case 'w': @@ -217,12 +232,18 @@ class SFTP extends \OC\Files\Storage\Common { } else { $ext=''; } + $tmpFile=\OC_Helper::tmpFile($ext); - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); + \OC\Files\Stream\Close::registerCallback( + $tmpFile, + array($this, 'writeBack') + ); + if ($this->file_exists($path)) { - $this->getFile($abs_path, $tmpFile); + $this->getFile($absPath, $tmpFile); } - self::$tempFiles[$tmpFile]=$abs_path; + + self::$tempFiles[$tmpFile]=$absPath; return fopen('close://'.$tmpFile, $mode); } } catch (\Exception $e) { @@ -240,9 +261,11 @@ class SFTP extends \OC\Files\Storage\Common { public function touch($path, $mtime=null) { try { - if (!is_null($mtime)) return false; + if (!is_null($mtime)) { + return false; + } if (!$this->file_exists($path)) { - $this->client->put($this->abs_path($path), ''); + $this->client->put($this->absPath($path), ''); } else { return false; } @@ -262,7 +285,13 @@ class SFTP extends \OC\Files\Storage\Common { public function rename($source, $target) { try { - return $this->client->rename($this->abs_path($source), $this->abs_path($target)); + if (!$this->is_dir($target) && $this->file_exists($target)) { + $this->unlink($target); + } + return $this->client->rename( + $this->absPath($source), + $this->absPath($target) + ); } catch (\Exception $e) { return false; } @@ -270,7 +299,7 @@ class SFTP extends \OC\Files\Storage\Common { public function stat($path) { try { - $stat = $this->client->stat($this->abs_path($path)); + $stat = $this->client->stat($this->absPath($path)); $mtime = $stat ? $stat['mtime'] : -1; $size = $stat ? $stat['size'] : 0; @@ -279,6 +308,5 @@ class SFTP extends \OC\Files\Storage\Common { } catch (\Exception $e) { return false; } - } } diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index ecd4dae0484..c5fba92ee68 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -47,8 +47,13 @@ class SMB extends \OC\Files\Storage\StreamWrapper{ public function constructUrl($path) { if (substr($path, -1)=='/') { - $path=substr($path, 0, -1); + $path = substr($path, 0, -1); } + if (substr($path, 0, 1)=='/') { + $path = substr($path, 1); + } + // remove trailing dots which some versions of samba don't seem to like + $path = rtrim($path, '.'); $path = urlencode($path); $user = urlencode($this->user); $pass = urlencode($this->password); @@ -77,6 +82,24 @@ class SMB extends \OC\Files\Storage\StreamWrapper{ } /** + * Unlinks file or directory + * @param string @path + */ + public function unlink($path) { + if ($this->is_dir($path)) { + $this->rmdir($path); + } + else { + $url = $this->constructUrl($path); + unlink($url); + clearstatcache(false, $url); + } + // smb4php still returns false even on success so + // check here whether file was really deleted + return !file_exists($path); + } + + /** * check if a file or folder has been updated since $time * @param string $path * @param int $time diff --git a/apps/files_external/lib/streamwrapper.php b/apps/files_external/lib/streamwrapper.php index beb4ec5605f..e484325e2fb 100644 --- a/apps/files_external/lib/streamwrapper.php +++ b/apps/files_external/lib/streamwrapper.php @@ -8,7 +8,7 @@ namespace OC\Files\Storage; -abstract class StreamWrapper extends Common{ +abstract class StreamWrapper extends Common { abstract public function constructUrl($path); public function mkdir($path) { @@ -16,9 +16,18 @@ abstract class StreamWrapper extends Common{ } public function rmdir($path) { - if($this->file_exists($path)) { - $success = rmdir($this->constructUrl($path)); - clearstatcache(); + if ($this->file_exists($path)) { + $dh = $this->opendir($path); + while (($file = readdir($dh)) !== false) { + if ($this->is_dir($path . '/' . $file)) { + $this->rmdir($path . '/' . $file); + } else { + $this->unlink($path . '/' . $file); + } + } + $url = $this->constructUrl($path); + $success = rmdir($url); + clearstatcache(false, $url); return $success; } else { return false; @@ -30,15 +39,7 @@ abstract class StreamWrapper extends Common{ } public function filetype($path) { - return filetype($this->constructUrl($path)); - } - - public function isReadable($path) { - return true;//not properly supported - } - - public function isUpdatable($path) { - return true;//not properly supported + return @filetype($this->constructUrl($path)); } public function file_exists($path) { @@ -46,8 +47,11 @@ abstract class StreamWrapper extends Common{ } public function unlink($path) { - $success = unlink($this->constructUrl($path)); - clearstatcache(); + $url = $this->constructUrl($path); + $success = unlink($url); + // normally unlink() is supposed to do this implicitly, + // but doing it anyway just to be sure + clearstatcache(false, $url); return $success; } @@ -55,15 +59,20 @@ abstract class StreamWrapper extends Common{ return fopen($this->constructUrl($path), $mode); } - public function touch($path, $mtime=null) { - if(is_null($mtime)) { - $fh = $this->fopen($path, 'a'); - fwrite($fh, ''); - fclose($fh); - - return true; + public function touch($path, $mtime = null) { + if ($this->file_exists($path)) { + if (is_null($mtime)) { + $fh = $this->fopen($path, 'a'); + fwrite($fh, ''); + fclose($fh); + + return true; + } else { + return false; //not supported + } } else { - return false;//not supported + $this->file_put_contents($path, ''); + return true; } } diff --git a/apps/files_external/lib/swift.php b/apps/files_external/lib/swift.php index a9cfe5bd20f..b615d24ce76 100644 --- a/apps/files_external/lib/swift.php +++ b/apps/files_external/lib/swift.php @@ -1,462 +1,311 @@ <?php + /** - * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. + * ownCloud + * + * @author Christian Berendt + * @copyright 2013 Christian Berendt berendt@b1-systems.de + * + * 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 <http://www.gnu.org/licenses/>. */ namespace OC\Files\Storage; -require_once 'php-cloudfiles/cloudfiles.php'; - -class SWIFT extends \OC\Files\Storage\Common{ - private $id; - private $host; - private $root; - private $user; - private $token; - private $secure; - private $ready = false; - /** - * @var \CF_Authentication auth - */ - private $auth; - /** - * @var \CF_Connection conn - */ - private $conn; - /** - * @var \CF_Container rootContainer - */ - private $rootContainer; - - private static $tempFiles=array(); - private $objects=array(); - private $containers=array(); - - const SUBCONTAINER_FILE='.subcontainers'; - - /** - * translate directory path to container name - * @param string $path - * @return string - */ - private function getContainerName($path) { - $path=trim(trim($this->root, '/') . "/".$path, '/.'); - return str_replace('/', '\\', $path); - } +set_include_path(get_include_path() . PATH_SEPARATOR . + \OC_App::getAppPath('files_external') . '/3rdparty/php-opencloud/lib'); +require_once 'openstack.php'; - /** - * get container by path - * @param string $path - * @return \CF_Container - */ - private function getContainer($path) { - if ($path=='' or $path=='/') { - return $this->rootContainer; - } - if (isset($this->containers[$path])) { - return $this->containers[$path]; - } - try { - $container=$this->conn->get_container($this->getContainerName($path)); - $this->containers[$path]=$container; - return $container; - } catch(\NoSuchContainerException $e) { - return null; - } - } +use \OpenCloud; +use \OpenCloud\Common\Exceptions; - /** - * create container - * @param string $path - * @return \CF_Container - */ - private function createContainer($path) { - if ($path=='' or $path=='/' or $path=='.') { - return $this->conn->create_container($this->getContainerName($path)); - } - $parent=dirname($path); - if ($parent=='' or $parent=='/' or $parent=='.') { - $parentContainer=$this->rootContainer; - } else { - if ( ! $this->containerExists($parent)) { - $parentContainer=$this->createContainer($parent); - } else { - $parentContainer=$this->getContainer($parent); - } +class Swift extends \OC\Files\Storage\Common { + + /** + * @var \OpenCloud\ObjectStore + */ + private $connection; + /** + * @var \OpenCloud\ObjectStore\Container + */ + private $container; + /** + * @var \OpenCloud\OpenStack + */ + private $anchor; + /** + * @var string + */ + private $bucket; + /** + * @var array + */ + private static $tmpFiles = array(); + + private function normalizePath($path) { + $path = trim($path, '/'); + + if (!$path) { + $path = '.'; } - $this->addSubContainer($parentContainer, basename($path)); - return $this->conn->create_container($this->getContainerName($path)); + + return $path; } - /** - * get object by path - * @param string $path - * @return \CF_Object - */ - private function getObject($path) { - if (isset($this->objects[$path])) { - return $this->objects[$path]; - } - $container=$this->getContainer(dirname($path)); - if (is_null($container)) { - return null; - } else { - if ($path=="/" or $path=='') { - return null; - } - try { - $obj=$container->get_object(basename($path)); - $this->objects[$path]=$obj; - return $obj; - } catch(\NoSuchObjectException $e) { - return null; - } + private function doesObjectExist($path) { + try { + $object = $this->container->DataObject($path); + return true; + } catch (Exceptions\ObjFetchError $e) { + \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); + return false; + } catch (Exceptions\HttpError $e) { + \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); + return false; } } - /** - * get the names of all objects in a container - * @param CF_Container - * @return array - */ - private function getObjects($container) { - if (is_null($container)) { - return array(); - } else { - $files=$container->get_objects(); - foreach ($files as &$file) { - $file=$file->name; - } - return $files; + public function __construct($params) { + if ((!isset($params['key']) and !isset($params['password'])) + or !isset($params['user']) or !isset($params['bucket']) + or !isset($params['region'])) { + throw new \Exception("API Key or password, Username, Bucket and Region have to be configured."); } - } - /** - * create object - * @param string $path - * @return \CF_Object - */ - private function createObject($path) { - $container=$this->getContainer(dirname($path)); - if ( ! is_null($container)) { - $container=$this->createContainer(dirname($path)); - } - return $container->create_object(basename($path)); - } + $this->id = 'swift::' . $params['user'] . md5($params['bucket']); + $this->bucket = $params['bucket']; - /** - * check if an object exists - * @param string - * @return bool - */ - private function objectExists($path) { - return !is_null($this->getObject($path)); - } + if (!isset($params['url'])) { + $params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/'; + } - /** - * check if container for path exists - * @param string $path - * @return bool - */ - private function containerExists($path) { - return !is_null($this->getContainer($path)); - } + if (!isset($params['service_name'])) { + $params['service_name'] = 'cloudFiles'; + } - /** - * get the list of emulated sub containers - * @param \CF_Container $container - * @return array - */ - private function getSubContainers($container) { - $tmpFile=\OCP\Files::tmpFile(); - $obj=$this->getSubContainerFile($container); - try { - $obj->save_to_filename($tmpFile); - } catch(\Exception $e) { - return array(); + $settings = array( + 'username' => $params['user'], + + ); + + if (isset($params['password'])) { + $settings['password'] = $params['password']; + } else if (isset($params['key'])) { + $settings['apiKey'] = $params['key']; } - $obj->save_to_filename($tmpFile); - $containers=file($tmpFile); - unlink($tmpFile); - foreach ($containers as &$sub) { - $sub=trim($sub); + + if (isset($params['tenant'])) { + $settings['tenantName'] = $params['tenant']; } - return $containers; - } - /** - * add an emulated sub container - * @param \CF_Container $container - * @param string $name - * @return bool - */ - private function addSubContainer($container, $name) { - if ( ! $name) { - return false; + $this->anchor = new \OpenCloud\OpenStack($params['url'], $settings); + + if (isset($params['timeout'])) { + $this->anchor->setHttpTimeout($params['timeout']); } - $tmpFile=\OCP\Files::tmpFile(); - $obj=$this->getSubContainerFile($container); + + $this->connection = $this->anchor->ObjectStore($params['service_name'], $params['region'], 'publicURL'); + try { - $obj->save_to_filename($tmpFile); - $containers=file($tmpFile); - foreach ($containers as &$sub) { - $sub=trim($sub); - } - if(array_search($name, $containers) !== false) { - unlink($tmpFile); - return false; - } else { - $fh=fopen($tmpFile, 'a'); - fwrite($fh, $name . "\n"); - } - } catch(\Exception $e) { - file_put_contents($tmpFile, $name . "\n"); + $this->container = $this->connection->Container($this->bucket); + } catch (Exceptions\ContainerNotFoundError $e) { + $this->container = $this->connection->Container(); + $this->container->Create(array('name' => $this->bucket)); } - $obj->load_from_filename($tmpFile); - unlink($tmpFile); - return true; + if (!$this->file_exists('.')) { + $this->mkdir('.'); + } } - /** - * remove an emulated sub container - * @param \CF_Container $container - * @param string $name - * @return bool - */ - private function removeSubContainer($container, $name) { - if ( ! $name) { - return false; - } - $tmpFile=\OCP\Files::tmpFile(); - $obj=$this->getSubContainerFile($container); - try { - $obj->save_to_filename($tmpFile); - $containers=file($tmpFile); - } catch (\Exception $e) { + public function mkdir($path) { + $path = $this->normalizePath($path); + + if ($this->is_dir($path)) { return false; } - foreach ($containers as &$sub) { - $sub=trim($sub); + + if($path !== '.') { + $path .= '/'; } - $i=array_search($name, $containers); - if ($i===false) { - unlink($tmpFile); + + try { + $object = $this->container->DataObject(); + $object->Create(array( + 'name' => $path, + 'content_type' => 'httpd/unix-directory' + )); + } catch (Exceptions\CreateUpdateError $e) { + \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; - } else { - unset($containers[$i]); - file_put_contents($tmpFile, implode("\n", $containers)."\n"); } - $obj->load_from_filename($tmpFile); - unlink($tmpFile); return true; } - /** - * ensure a subcontainer file exists and return it's object - * @param \CF_Container $container - * @return \CF_Object - */ - private function getSubContainerFile($container) { - try { - return $container->get_object(self::SUBCONTAINER_FILE); - } catch(\NoSuchObjectException $e) { - return $container->create_object(self::SUBCONTAINER_FILE); - } - } + public function file_exists($path) { + $path = $this->normalizePath($path); - public function __construct($params) { - if (isset($params['token']) && isset($params['host']) && isset($params['user'])) { - $this->token=$params['token']; - $this->host=$params['host']; - $this->user=$params['user']; - $this->root=isset($params['root'])?$params['root']:'/'; - if (isset($params['secure'])) { - if (is_string($params['secure'])) { - $this->secure = ($params['secure'] === 'true'); - } else { - $this->secure = (bool)$params['secure']; - } - } else { - $this->secure = false; - } - if ( ! $this->root || $this->root[0]!='/') { - $this->root='/'.$this->root; - } - $this->id = 'swift:' . $this->host . ':'.$this->root . ':' . $this->user; - } else { - throw new \Exception(); + if ($path !== '.' && $this->is_dir($path)) { + $path .= '/'; } + return $this->doesObjectExist($path); } - private function init(){ - if($this->ready) { - return; + public function rmdir($path) { + $path = $this->normalizePath($path); + + if (!$this->is_dir($path)) { + return false; } - $this->ready = true; - $this->auth = new \CF_Authentication($this->user, $this->token, null, $this->host); - $this->auth->authenticate(); + $dh = $this->opendir($path); + while ($file = readdir($dh)) { + if ($file === '.' || $file === '..') { + continue; + } - $this->conn = new \CF_Connection($this->auth); + if ($this->is_dir($path . '/' . $file)) { + $this->rmdir($path . '/' . $file); + } else { + $this->unlink($path . '/' . $file); + } + } - if ( ! $this->containerExists('/')) { - $this->rootContainer=$this->createContainer('/'); - } else { - $this->rootContainer=$this->getContainer('/'); + try { + $object = $this->container->DataObject($path . '/'); + $object->Delete(); + } catch (Exceptions\DeleteError $e) { + \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); + return false; } - } - public function getId(){ - return $this->id; + return true; } + public function opendir($path) { + $path = $this->normalizePath($path); - public function mkdir($path) { - $this->init(); - if ($this->containerExists($path)) { - return false; + if ($path === '.') { + $path = ''; } else { - $this->createContainer($path); - return true; + $path .= '/'; } - } - public function rmdir($path) { - $this->init(); - if (!$this->containerExists($path)) { - return false; - } else { - $this->emptyContainer($path); - if ($path!='' and $path!='/') { - $parentContainer=$this->getContainer(dirname($path)); - $this->removeSubContainer($parentContainer, basename($path)); + try { + $files = array(); + $objects = $this->container->ObjectList(array( + 'prefix' => $path, + 'delimiter' => '/' + )); + + while ($object = $objects->Next()) { + $file = basename($object->Name()); + if ($file !== basename($path)) { + $files[] = $file; + } } - $this->conn->delete_container($this->getContainerName($path)); - unset($this->containers[$path]); - return true; + \OC\Files\Stream\Dir::register('swift' . $path, $files); + return opendir('fakedir://swift' . $path); + } catch (Exception $e) { + \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); + return false; } + } - private function emptyContainer($path) { - $container=$this->getContainer($path); - if (is_null($container)) { - return; - } - $subContainers=$this->getSubContainers($container); - foreach ($subContainers as $sub) { - if ($sub) { - $this->emptyContainer($path.'/'.$sub); - $this->conn->delete_container($this->getContainerName($path.'/'.$sub)); - unset($this->containers[$path.'/'.$sub]); - } - } + public function stat($path) { + $path = $this->normalizePath($path); - $objects=$this->getObjects($container); - foreach ($objects as $object) { - $container->delete_object($object); - unset($this->objects[$path.'/'.$object]); + if ($this->is_dir($path) && $path != '.') { + $path .= '/'; } - } - public function opendir($path) { - $this->init(); - $container=$this->getContainer($path); - $files=$this->getObjects($container); - $i=array_search(self::SUBCONTAINER_FILE, $files); - if ($i!==false) { - unset($files[$i]); - } - $subContainers=$this->getSubContainers($container); - $files=array_merge($files, $subContainers); - $id=$this->getContainerName($path); - \OC\Files\Stream\Dir::register($id, $files); - return opendir('fakedir://'.$id); - } + try { + $object = $this->container->DataObject($path); + } catch (Exceptions\ObjFetchError $e) { + \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); + return false; + } - public function filetype($path) { - $this->init(); - if ($this->containerExists($path)) { - return 'dir'; - } else { - return 'file'; + $mtime = $object->extra_headers['X-Timestamp']; + if (isset($object->extra_headers['X-Object-Meta-Timestamp'])) { + $mtime = $object->extra_headers['X-Object-Meta-Timestamp']; } - } - public function isReadable($path) { - return true; + $stat = array(); + $stat['size'] = $object->content_length; + $stat['mtime'] = $mtime; + $stat['atime'] = time(); + return $stat; } - public function isUpdatable($path) { - return true; - } + public function filetype($path) { + $path = $this->normalizePath($path); - public function file_exists($path) { - $this->init(); - if ($this->is_dir($path)) { - return true; - } else { - return $this->objectExists($path); + if ($path !== '.' && $this->doesObjectExist($path)) { + return 'file'; } - } - public function file_get_contents($path) { - $this->init(); - $obj=$this->getObject($path); - if (is_null($obj)) { - return false; + if ($path !== '.') { + $path .= '/'; } - return $obj->read(); - } - public function file_put_contents($path, $content) { - $this->init(); - $obj=$this->getObject($path); - if (is_null($obj)) { - $container=$this->getContainer(dirname($path)); - if (is_null($container)) { - return false; - } - $obj=$container->create_object(basename($path)); + if ($this->doesObjectExist($path)) { + return 'dir'; } - $this->resetMTime($obj); - return $obj->write($content); } public function unlink($path) { - $this->init(); - if ($this->containerExists($path)) { - return $this->rmdir($path); - } - if ($this->objectExists($path)) { - $container=$this->getContainer(dirname($path)); - $container->delete_object(basename($path)); - unset($this->objects[$path]); - } else { + $path = $this->normalizePath($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) { + \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; } + + return true; } public function fopen($path, $mode) { - $this->init(); - switch($mode) { + $path = $this->normalizePath($path); + + switch ($mode) { case 'r': case 'rb': - $obj=$this->getObject($path); - if (is_null($obj)) { + $tmpFile = \OC_Helper::tmpFile(); + self::$tmpFiles[$tmpFile] = $path; + try { + $object = $this->container->DataObject($path); + } catch (Exceptions\ObjFetchError $e) { + \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); return false; } - $fp = fopen('php://temp', 'r+'); - $obj->stream($fp); - - rewind($fp); - return $fp; + try { + $object->SaveToFilename($tmpFile); + } catch (Exceptions\IOError $e) { + \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); + return false; + } + return fopen($tmpFile, 'r'); case 'w': case 'wb': case 'a': @@ -469,119 +318,166 @@ class SWIFT extends \OC\Files\Storage\Common{ case 'x+': case 'c': case 'c+': - $tmpFile=$this->getTmpFile($path); + 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')); - self::$tempFiles[$tmpFile]=$path; - return fopen('close://'.$tmpFile, $mode); + if ($this->file_exists($path)) { + $source = $this->fopen($path, 'r'); + file_put_contents($tmpFile, $source); + } + self::$tmpFiles[$tmpFile] = $path; + + return fopen('close://' . $tmpFile, $mode); } } - public function writeBack($tmpFile) { - if (isset(self::$tempFiles[$tmpFile])) { - $this->fromTmpFile($tmpFile, self::$tempFiles[$tmpFile]); - unlink($tmpFile); + public function getMimeType($path) { + $path = $this->normalizePath($path); + + 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"]; } + return false; } - public function touch($path, $mtime=null) { - $this->init(); - $obj=$this->getObject($path); - if (is_null($obj)) { - return false; + public function touch($path, $mtime = null) { + $path = $this->normalizePath($path); + 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->Update($settings); + } 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); } - if (is_null($mtime)) { - $mtime=time(); + } + + public function copy($path1, $path2) { + $path1 = $this->normalizePath($path1); + $path2 = $this->normalizePath($path2); + + if ($this->is_file($path1)) { + try { + $source = $this->container->DataObject($path1); + $target = $this->container->DataObject(); + $target->Create(array( + 'name' => $path2, + )); + $source->Copy($target); + } catch (Exceptions\ObjectCopyError $e) { + \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); + return false; + } + } else { + if ($this->file_exists($path2)) { + return false; + } + + try { + $source = $this->container->DataObject($path1 . '/'); + $target = $this->container->DataObject(); + $target->Create(array( + 'name' => $path2 . '/', + )); + $source->Copy($target); + } catch (Exceptions\ObjectCopyError $e) { + \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); + return false; + } + + $dh = $this->opendir($path1); + while ($file = readdir($dh)) { + if ($file === '.' || $file === '..') { + continue; + } + + $source = $path1 . '/' . $file; + $target = $path2 . '/' . $file; + $this->copy($source, $target); + } } - //emulate setting mtime with metadata - $obj->metadata['Mtime']=$mtime; - $obj->sync_metadata(); + return true; } public function rename($path1, $path2) { - $this->init(); - $sourceContainer=$this->getContainer(dirname($path1)); - $targetContainer=$this->getContainer(dirname($path2)); - $result=$sourceContainer->move_object_to(basename($path1), $targetContainer, basename($path2)); - unset($this->objects[$path1]); - if ($result) { - $targetObj=$this->getObject($path2); - $this->resetMTime($targetObj); - } - return $result; - } + $path1 = $this->normalizePath($path1); + $path2 = $this->normalizePath($path2); - public function copy($path1, $path2) { - $this->init(); - $sourceContainer=$this->getContainer(dirname($path1)); - $targetContainer=$this->getContainer(dirname($path2)); - $result=$sourceContainer->copy_object_to(basename($path1), $targetContainer, basename($path2)); - if ($result) { - $targetObj=$this->getObject($path2); - $this->resetMTime($targetObj); - } - return $result; - } + if ($this->is_file($path1)) { + if ($this->copy($path1, $path2) === false) { + return false; + } - public function stat($path) { - $this->init(); - $container=$this->getContainer($path); - if ( ! is_null($container)) { - return array( - 'mtime'=>-1, - 'size'=>$container->bytes_used, - 'ctime'=>-1 - ); - } + if ($this->unlink($path1) === false) { + $this->unlink($path2); + return false; + } + } else { + if ($this->file_exists($path2)) { + return false; + } - $obj=$this->getObject($path); + if ($this->copy($path1, $path2) === false) { + return false; + } - if (is_null($obj)) { - return false; + if ($this->rmdir($path1) === false) { + $this->rmdir($path2); + return false; + } } - if (isset($obj->metadata['Mtime']) and $obj->metadata['Mtime']>-1) { - $mtime=$obj->metadata['Mtime']; - } else { - $mtime=strtotime($obj->last_modified); - } - return array( - 'mtime'=>$mtime, - 'size'=>$obj->content_length, - 'ctime'=>-1, - ); + return true; } - private function getTmpFile($path) { - $this->init(); - $obj=$this->getObject($path); - if ( ! is_null($obj)) { - $tmpFile=\OCP\Files::tmpFile(); - $obj->save_to_filename($tmpFile); - return $tmpFile; - } else { - return \OCP\Files::tmpFile(); - } + public function getId() { + return $this->id; } - private function fromTmpFile($tmpFile, $path) { - $this->init(); - $obj=$this->getObject($path); - if (is_null($obj)) { - $obj=$this->createObject($path); - } - $obj->load_from_filename($tmpFile); - $this->resetMTime($obj); + public function getConnection() { + return $this->connection; } - /** - * remove custom mtime metadata - * @param \CF_Object $obj - */ - private function resetMTime($obj) { - if (isset($obj->metadata['Mtime'])) { - $obj->metadata['Mtime']=-1; - $obj->sync_metadata(); + public function writeBack($tmpFile) { + 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); + unlink($tmpFile); } } diff --git a/apps/files_external/lib/webdav.php b/apps/files_external/lib/webdav.php index 66920fc9f64..0f8034e57d9 100644 --- a/apps/files_external/lib/webdav.php +++ b/apps/files_external/lib/webdav.php @@ -14,6 +14,7 @@ class DAV extends \OC\Files\Storage\Common{ private $host; private $secure; private $root; + private $certPath; private $ready; /** * @var \Sabre_DAV_Client @@ -40,6 +41,12 @@ class DAV extends \OC\Files\Storage\Common{ } else { $this->secure = false; } + if ($this->secure === true) { + $certPath=\OC_User::getHome(\OC_User::getUser()) . '/files_external/rootcerts.crt'; + if (file_exists($certPath)) { + $this->certPath=$certPath; + } + } $this->root=isset($params['root'])?$params['root']:'/'; if ( ! $this->root || $this->root[0]!='/') { $this->root='/'.$this->root; @@ -58,20 +65,16 @@ class DAV extends \OC\Files\Storage\Common{ } $this->ready = true; - $settings = array( - 'baseUri' => $this->createBaseUri(), - 'userName' => $this->user, - 'password' => $this->password, - ); + $settings = array( + 'baseUri' => $this->createBaseUri(), + 'userName' => $this->user, + 'password' => $this->password, + ); $this->client = new \Sabre_DAV_Client($settings); - $caview = \OCP\Files::getStorage('files_external'); - if ($caview) { - $certPath=\OCP\Config::getSystemValue('datadirectory').$caview->getAbsolutePath("").'rootcerts.crt'; - if (file_exists($certPath)) { - $this->client->addTrustedCertificates($certPath); - } + if ($this->secure === true && $this->certPath) { + $this->client->addTrustedCertificates($this->certPath); } } @@ -79,7 +82,7 @@ class DAV extends \OC\Files\Storage\Common{ return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root; } - private function createBaseUri() { + protected function createBaseUri() { $baseUri='http'; if ($this->secure) { $baseUri.='s'; @@ -134,14 +137,6 @@ class DAV extends \OC\Files\Storage\Common{ } } - public function isReadable($path) { - return true;//not properly supported - } - - public function isUpdatable($path) { - return true;//not properly supported - } - public function file_exists($path) { $this->init(); $path=$this->cleanPath($path); @@ -174,7 +169,14 @@ class DAV extends \OC\Files\Storage\Common{ curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().str_replace(' ', '%20', $path)); curl_setopt($curl, CURLOPT_FILE, $fp); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); - + if ($this->secure === true) { + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); + if($this->certPath){ + curl_setopt($curl, CURLOPT_CAINFO, $this->certPath); + } + } + curl_exec ($curl); curl_close ($curl); rewind($fp); @@ -242,6 +244,7 @@ class DAV extends \OC\Files\Storage\Common{ } else { $this->file_put_contents($path, ''); } + return true; } public function getFile($path, $target) { @@ -261,6 +264,13 @@ class DAV extends \OC\Files\Storage\Common{ curl_setopt($curl, CURLOPT_INFILE, $source); // file pointer curl_setopt($curl, CURLOPT_INFILESIZE, filesize($path)); curl_setopt($curl, CURLOPT_PUT, true); + if ($this->secure === true) { + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); + if($this->certPath){ + curl_setopt($curl, CURLOPT_CAINFO, $this->certPath); + } + } curl_exec ($curl); curl_close ($curl); } @@ -268,7 +278,7 @@ class DAV extends \OC\Files\Storage\Common{ public function rename($path1, $path2) { $this->init(); $path1=$this->cleanPath($path1); - $path2=$this->root.$this->cleanPath($path2); + $path2=$this->createBaseUri().$this->cleanPath($path2); try { $this->client->request('MOVE', $path1, null, array('Destination'=>$path2)); return true; @@ -280,7 +290,7 @@ class DAV extends \OC\Files\Storage\Common{ public function copy($path1, $path2) { $this->init(); $path1=$this->cleanPath($path1); - $path2=$this->root.$this->cleanPath($path2); + $path2=$this->createBaseUri().$this->cleanPath($path2); try { $this->client->request('COPY', $path1, null, array('Destination'=>$path2)); return true; @@ -323,11 +333,9 @@ class DAV extends \OC\Files\Storage\Common{ } public function cleanPath($path) { - if ( ! $path || $path[0]=='/') { - return substr($path, 1); - } else { - return $path; - } + $path = \OC\Files\Filesystem::normalizePath($path); + // remove leading slash + return substr($path, 1); } private function simpleResponse($method, $path, $body, $expected) { @@ -340,3 +348,4 @@ class DAV extends \OC\Files\Storage\Common{ } } } + diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php index 028a384cf34..3ca16c3c7a8 100644 --- a/apps/files_external/templates/settings.php +++ b/apps/files_external/templates/settings.php @@ -2,7 +2,7 @@ <fieldset class="personalblock"> <h2><?php p($l->t('External Storage')); ?></h2> <?php if (isset($_['dependencies']) and ($_['dependencies']<>'')) print_unescaped(''.$_['dependencies'].''); ?> - <table id="externalStorage" data-admin='<?php print_unescaped(json_encode($_['isAdminPage'])); ?>'> + <table id="externalStorage" class="grid" data-admin='<?php print_unescaped(json_encode($_['isAdminPage'])); ?>'> <thead> <tr> <th></th> @@ -60,7 +60,7 @@ class="optional" data-parameter="<?php p($parameter); ?>" value="<?php p($value); ?>" - placeholder="<?php p(substr($placeholder, 5)); ?>" /> + placeholder="<?php p(substr($placeholder, 1)); ?>" /> <?php elseif (strpos($placeholder, '#') !== false): ?> <input type="hidden" data-parameter="<?php p($parameter); ?>" diff --git a/apps/files_external/tests/config.php b/apps/files_external/tests/config.php index d4a69d29c0f..e296bfcb5b2 100644 --- a/apps/files_external/tests/config.php +++ b/apps/files_external/tests/config.php @@ -23,6 +23,13 @@ return array( 'password'=>'test', 'root'=>'/owncloud/files/webdav.php', ), + 'owncloud'=>array( + 'run'=>true, + 'host'=>'localhost/owncloud', + 'user'=>'test', + 'password'=>'test', + 'root'=>'', + ), 'google'=>array( 'run'=> false, 'configured' => 'true', @@ -30,12 +37,17 @@ return array( 'client_secret' => '', 'token' => '', ), - 'swift'=>array( - 'run'=>false, - 'user'=>'test:tester', - 'token'=>'testing', - 'host'=>'localhost.local:8080/auth', - 'root'=>'/', + 'swift' => array( + 'run' => false, + 'user' => 'test', + 'bucket' => 'test', + 'region' => 'DFW', + 'key' => 'test', //to be used only with Rackspace Cloud Files + //'tenant' => 'test', //to be used only with OpenStack Object Storage + //'password' => 'test', //to be use only with OpenStack Object Storage + //'service_name' => 'swift', //should be 'swift' for OpenStack Object Storage and 'cloudFiles' for Rackspace Cloud Files (default value) + //'url' => 'https://identity.api.rackspacecloud.com/v2.0/', //to be used with Rackspace Cloud Files and OpenStack Object Storage + //'timeout' => 5 // timeout of HTTP requests in seconds ), 'smb'=>array( 'run'=>false, diff --git a/apps/files_external/tests/dropbox.php b/apps/files_external/tests/dropbox.php index e4e598b06b0..4b052282019 100644 --- a/apps/files_external/tests/dropbox.php +++ b/apps/files_external/tests/dropbox.php @@ -21,6 +21,22 @@ class Dropbox extends Storage { $this->instance = new \OC\Files\Storage\Dropbox($this->config['dropbox']); } + public function directoryProvider() { + // doesn't support leading/trailing spaces + return array(array('folder')); + } + + public function testDropboxTouchReturnValue() { + $this->assertFalse($this->instance->file_exists('foo')); + + // true because succeeded + $this->assertTrue($this->instance->touch('foo')); + $this->assertTrue($this->instance->file_exists('foo')); + + // false because not supported + $this->assertFalse($this->instance->touch('foo')); + } + public function tearDown() { if ($this->instance) { $this->instance->unlink('/'); diff --git a/apps/files_external/tests/ftp.php b/apps/files_external/tests/ftp.php index e146725473a..3037793120a 100644 --- a/apps/files_external/tests/ftp.php +++ b/apps/files_external/tests/ftp.php @@ -34,19 +34,31 @@ class FTP extends Storage { 'password' => 'ftp', 'root' => '/', 'secure' => false ); - $instance = new OC_Filestorage_FTP($config); + $instance = new \OC\Files\Storage\FTP($config); $this->assertEquals('ftp://ftp:ftp@localhost/', $instance->constructUrl('')); $config['secure'] = true; - $instance = new OC_Filestorage_FTP($config); + $instance = new \OC\Files\Storage\FTP($config); $this->assertEquals('ftps://ftp:ftp@localhost/', $instance->constructUrl('')); $config['secure'] = 'false'; - $instance = new OC_Filestorage_FTP($config); + $instance = new \OC\Files\Storage\FTP($config); $this->assertEquals('ftp://ftp:ftp@localhost/', $instance->constructUrl('')); $config['secure'] = 'true'; - $instance = new OC_Filestorage_FTP($config); + $instance = new \OC\Files\Storage\FTP($config); $this->assertEquals('ftps://ftp:ftp@localhost/', $instance->constructUrl('')); + + $config['root'] = ''; + $instance = new \OC\Files\Storage\FTP($config); + $this->assertEquals('ftps://ftp:ftp@localhost/somefile.txt', $instance->constructUrl('somefile.txt')); + + $config['root'] = '/abc'; + $instance = new \OC\Files\Storage\FTP($config); + $this->assertEquals('ftps://ftp:ftp@localhost/abc/somefile.txt', $instance->constructUrl('somefile.txt')); + + $config['root'] = '/abc/'; + $instance = new \OC\Files\Storage\FTP($config); + $this->assertEquals('ftps://ftp:ftp@localhost/abc/somefile.txt', $instance->constructUrl('somefile.txt')); } } diff --git a/apps/files_external/tests/mountconfig.php b/apps/files_external/tests/mountconfig.php new file mode 100644 index 00000000000..941aec680bb --- /dev/null +++ b/apps/files_external/tests/mountconfig.php @@ -0,0 +1,51 @@ +<?php +/** + * ownCloud + * + * @author Vincent Petry + * Copyright (c) 2013 Vincent Petry <pvince81@owncloud.com> + * + * 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 <http://www.gnu.org/licenses/>. + * + */ + +require_once __DIR__ . '/../../../lib/base.php'; + +require __DIR__ . '/../lib/config.php'; + +class Test_Mount_Config_Dummy_Storage { + public function test() { + return true; + } +} + +/** + * Class Test_Mount_Config + */ +class Test_Mount_Config extends \PHPUnit_Framework_TestCase { + /** + * Test mount point validation + */ + public function testAddMountPointValidation() { + $storageClass = 'Test_Mount_Config_Dummy_Storage'; + $mountType = 'user'; + $applicable = 'all'; + $isPersonal = false; + $this->assertEquals(false, OC_Mount_Config::addMountPoint('', $storageClass, array(), $mountType, $applicable, $isPersonal)); + $this->assertEquals(false, OC_Mount_Config::addMountPoint('/', $storageClass, array(), $mountType, $applicable, $isPersonal)); + $this->assertEquals(false, OC_Mount_Config::addMountPoint('Shared', $storageClass, array(), $mountType, $applicable, $isPersonal)); + $this->assertEquals(false, OC_Mount_Config::addMountPoint('/Shared', $storageClass, array(), $mountType, $applicable, $isPersonal)); + + } +} diff --git a/apps/files_external/tests/owncloud.php b/apps/files_external/tests/owncloud.php new file mode 100644 index 00000000000..408a55864f2 --- /dev/null +++ b/apps/files_external/tests/owncloud.php @@ -0,0 +1,31 @@ +<?php +/** + * Copyright (c) 2013 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Storage; + +class OwnCloud extends Storage { + + private $config; + + public function setUp() { + $id = uniqid(); + $this->config = include('files_external/tests/config.php'); + if ( ! is_array($this->config) or ! isset($this->config['owncloud']) or ! $this->config['owncloud']['run']) { + $this->markTestSkipped('ownCloud backend not configured'); + } + $this->config['owncloud']['root'] .= '/' . $id; //make sure we have an new empty folder to work in + $this->instance = new \OC\Files\Storage\OwnCloud($this->config['owncloud']); + $this->instance->mkdir('/'); + } + + public function tearDown() { + if ($this->instance) { + $this->instance->rmdir('/'); + } + } +} diff --git a/apps/files_external/tests/smb.php b/apps/files_external/tests/smb.php index ca2a93c8944..199e35af676 100644 --- a/apps/files_external/tests/smb.php +++ b/apps/files_external/tests/smb.php @@ -15,7 +15,7 @@ class SMB extends Storage { public function setUp() { $id = uniqid(); $this->config = include('files_external/tests/config.php'); - if ( ! is_array($this->config) or ! isset($this->config['smb']) or ! $this->config['smb']['run']) { + if (!is_array($this->config) or !isset($this->config['smb']) or !$this->config['smb']['run']) { $this->markTestSkipped('Samba backend not configured'); } $this->config['smb']['root'] .= $id; //make sure we have an new empty folder to work in @@ -28,4 +28,16 @@ class SMB extends Storage { \OCP\Files::rmdirr($this->instance->constructUrl('')); } } + + public function directoryProvider() { + // doesn't support leading/trailing spaces + return array(array('folder')); + } + + public function testRenameWithSpaces() { + $this->instance->mkdir('with spaces'); + $result = $this->instance->rename('with spaces', 'foo bar'); + $this->assertTrue($result); + $this->assertTrue($this->instance->is_dir('foo bar')); + } } diff --git a/apps/files_external/tests/smbfunctions.php b/apps/files_external/tests/smbfunctions.php new file mode 100644 index 00000000000..749906d0136 --- /dev/null +++ b/apps/files_external/tests/smbfunctions.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright (c) 2013 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Storage; + +class SMBFunctions extends \PHPUnit_Framework_TestCase { + + public function setUp() { + $id = uniqid(); + // dummy config + $this->config = array( + 'run'=>false, + 'user'=>'test', + 'password'=>'testpassword', + 'host'=>'smbhost', + 'share'=>'/sharename', + 'root'=>'/rootdir/', + ); + + $this->instance = new \OC\Files\Storage\SMB($this->config); + } + + public function tearDown() { + } + + public function testGetId() { + $this->assertEquals('smb::test@smbhost//sharename//rootdir/', $this->instance->getId()); + } + + public function testConstructUrl() { + $this->assertEquals("smb://test:testpassword@smbhost/sharename/rootdir/abc", $this->instance->constructUrl('/abc')); + $this->assertEquals("smb://test:testpassword@smbhost/sharename/rootdir/abc", $this->instance->constructUrl('/abc/')); + $this->assertEquals("smb://test:testpassword@smbhost/sharename/rootdir/abc%2F", $this->instance->constructUrl('/abc/.')); + $this->assertEquals("smb://test:testpassword@smbhost/sharename/rootdir/abc%2Fdef", $this->instance->constructUrl('/abc/def')); + } +} diff --git a/apps/files_external/tests/swift.php b/apps/files_external/tests/swift.php index 5c782840246..bdfdbdeebe9 100644 --- a/apps/files_external/tests/swift.php +++ b/apps/files_external/tests/swift.php @@ -1,30 +1,51 @@ <?php + /** - * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. + * ownCloud + * + * @author Christian Berendt + * @copyright 2013 Christian Berendt berendt@b1-systems.de + * + * 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 <http://www.gnu.org/licenses/>. */ namespace Test\Files\Storage; -class SWIFT extends Storage { +class Swift extends Storage { + private $config; public function setUp() { - $id = uniqid(); $this->config = include('files_external/tests/config.php'); - if ( ! is_array($this->config) or ! isset($this->config['swift']) or ! $this->config['swift']['run']) { - $this->markTestSkipped('OpenStack SWIFT backend not configured'); + if (!is_array($this->config) or !isset($this->config['swift']) + or !$this->config['swift']['run']) { + $this->markTestSkipped('OpenStack Object Storage backend not configured'); } - $this->config['swift']['root'] .= '/' . $id; //make sure we have an new empty folder to work in - $this->instance = new \OC\Files\Storage\SWIFT($this->config['swift']); + $this->instance = new \OC\Files\Storage\Swift($this->config['swift']); } - public function tearDown() { if ($this->instance) { - $this->instance->rmdir(''); + $connection = $this->instance->getConnection(); + $container = $connection->Container($this->config['swift']['bucket']); + + $objects = $container->ObjectList(); + while($object = $objects->Next()) { + $object->Delete(); + } + + $container->Delete(); } } } |