Browse Source

Missing files of Zend_Service_Rackspace

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@24495 44c647ce-9c0f-0410-b52a-842ac1e357ba
ezimuel 14 years ago
parent
commit
8856904f5b

+ 344 - 0
library/Zend/Service/Rackspace/Abstract.php

@@ -0,0 +1,344 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service
+ * @subpackage Rackspace
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Http/Client.php';
+
+abstract class Zend_Service_Rackspace_Abstract
+{
+    const VERSION                = 'v1.0';
+    const US_AUTH_URL            = 'https://auth.api.rackspacecloud.com';
+    const UK_AUTH_URL            = 'https://lon.auth.api.rackspacecloud.com';
+    const API_FORMAT             = 'json';
+    const USER_AGENT             = 'Zend_Service_Rackspace';
+    const STORAGE_URL            = "X-Storage-Url";
+    const AUTHTOKEN              = "X-Auth-Token";
+    const AUTHUSER_HEADER        = "X-Auth-User";
+    const AUTHKEY_HEADER         = "X-Auth-Key";
+    const AUTHUSER_HEADER_LEGACY = "X-Storage-User";
+    const AUTHKEY_HEADER_LEGACY  = "X-Storage-Pass";
+    const AUTHTOKEN_LEGACY       = "X-Storage-Token";
+    const CDNM_URL               = "X-CDN-Management-Url";
+    const MANAGEMENT_URL         = "X-Server-Management-Url";
+    /**
+     * Rackspace Key
+     *
+     * @var string
+     */
+    protected $key;
+    /**
+     * Rackspace account name
+     *
+     * @var string
+     */
+    protected $user;
+    /**
+     * Token of authentication
+     *
+     * @var string
+     */
+    protected $token;
+    /**
+     * Authentication URL
+     *
+     * @var string
+     */
+    protected $authUrl;
+    /**
+     * @var Zend_Http_Client
+     */
+    protected $httpClient;
+    /**
+     * Error Msg
+     *
+     * @var string
+     */
+    protected $errorMsg;
+    /**
+     * HTTP error code
+     *
+     * @var string
+     */
+    protected $errorCode;
+    /**
+     * Storage URL
+     *
+     * @var string
+     */
+    protected $storageUrl;
+    /**
+     * CDN URL
+     *
+     * @var string
+     */
+    protected $cdnUrl;
+    /**
+     * Server management URL
+     * 
+     * @var string 
+     */
+    protected $managementUrl;
+    /**
+     * Constructor
+     *
+     * You must pass the account and the Rackspace authentication key.
+     * Optional: the authentication url (default is US)
+     *
+     * @param string $user
+     * @param string $key
+     * @param string $authUrl
+     */
+    public function __construct($user, $key, $authUrl=self::US_AUTH_URL)
+    {
+        if (!isset($user)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception("The user cannot be empty");
+        }
+        if (!isset($key)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception("The key cannot be empty");
+        }
+        if (!in_array($authUrl, array(self::US_AUTH_URL, self::UK_AUTH_URL))) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception("The authentication URL should be valid");
+        }
+        $this->setUser($user);
+        $this->setKey($key);
+        $this->setAuthUrl($authUrl);
+    }
+    /**
+     * Get User account
+     *
+     * @return string
+     */
+    public function getUser()
+    {
+        return $this->user;
+    }
+    /**
+     * Get user key
+     *
+     * @return string
+     */
+    public function getKey()
+    {
+        return $this->key;
+    }
+    /**
+     * Get authentication URL
+     *
+     * @return string
+     */
+    public function getAuthUrl()
+    {
+        return $this->authUrl;
+    }
+    /**
+     * Get the storage URL
+     *
+     * @return string|boolean
+     */
+    public function getStorageUrl() 
+    {
+        if (empty($this->storageUrl)) {
+            if (!$this->authenticate()) {
+                return false;
+            }
+        }
+        return $this->storageUrl;
+    }
+    /**
+     * Get the CDN URL
+     *
+     * @return string|boolean
+     */
+    public function getCdnUrl() 
+    {
+        if (empty($this->cdnUrl)) {
+            if (!$this->authenticate()) {
+                return false;
+            }
+        }
+        return $this->cdnUrl;
+    }
+    /**
+     * Get the management server URL
+     * 
+     * @return string|boolean
+     */     
+    public function getManagementUrl()
+    {
+        if (empty($this->managementUrl)) {
+            if (!$this->authenticate()) {
+                return false;
+            }
+        }
+        return $this->managementUrl;
+    }
+    /**
+     * Set the user account
+     *
+     * @param string $user
+     * @return void
+     */
+    public function setUser($user)
+    {
+        if (!empty($user)) {
+            $this->user = $user;
+        }
+    }
+    /**
+     * Set the authentication key
+     *
+     * @param string $key
+     * @return void
+     */
+    public function setKey($key)
+    {
+        if (!empty($key)) {
+            $this->key = $key;
+        }
+    }
+    /**
+     * Set the Authentication URL
+     *
+     * @param string $url
+     * @return void
+     */
+    public function setAuthUrl($url)
+    {
+        if (!empty($url) && in_array($url, array(self::US_AUTH_URL, self::UK_AUTH_URL))) {
+            $this->authUrl = $url;
+        } else {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception("The authentication URL is not valid");
+        }
+    }
+    /**
+     * Get the authentication token
+     *
+     * @return string
+     */
+    public function getToken()
+    {
+        if (empty($this->token)) {
+            if (!$this->authenticate()) {
+                return false;
+            }
+        }
+        return $this->token;
+    }
+    /**
+     * Get the error msg of the last HTTP call
+     *
+     * @return string
+     */
+    public function getErrorMsg() 
+    {
+        return $this->errorMsg;
+    }
+    /**
+     * Get the error code of the last HTTP call
+     * 
+     * @return strig 
+     */
+    public function getErrorCode() 
+    {
+        return $this->errorCode;
+    }
+    /**
+     * get the HttpClient instance
+     *
+     * @return Zend_Http_Client
+     */
+    public function getHttpClient()
+    {
+        if (empty($this->httpClient)) {
+            $this->httpClient = new Zend_Http_Client();
+        }
+        return $this->httpClient;
+    }
+    /**
+     * Return true is the last call was successful
+     * 
+     * @return boolean 
+     */
+    public function isSuccessful()
+    {
+        return ($this->errorMsg=='');
+    }
+    /**
+     * HTTP call
+     *
+     * @param string $url
+     * @param string $method
+     * @param array $headers
+     * @param array $get
+     * @param string $body
+     * @return Zend_Http_Response
+     */
+    protected function httpCall($url,$method,$headers=array(),$data=array(),$body=null)
+    {
+        $client = $this->getHttpClient();
+        $client->resetParameters(true);
+        if (empty($headers[self::AUTHUSER_HEADER])) {
+            $headers[self::AUTHTOKEN]= $this->getToken();
+        } 
+        $client->setMethod($method);
+        if (empty($data['format'])) {
+            $data['format']= self::API_FORMAT;
+        }
+        $client->setParameterGet($data);    
+        if (!empty($body)) {
+            $client->setRawData($body);
+            if (!isset($headers['Content-Type'])) {
+                $headers['Content-Type']= 'application/json';
+            }
+        }
+        $client->setHeaders($headers);
+        $client->setUri($url);
+        $this->errorMsg='';
+        $this->errorCode='';
+        return $client->request();
+    }
+    /**
+     * Authentication
+     *
+     * @return boolean
+     */
+    public function authenticate()
+    {
+        $headers = array (
+            self::AUTHUSER_HEADER => $this->user,
+            self::AUTHKEY_HEADER => $this->key
+        );
+        $result = $this->httpCall($this->authUrl.'/'.self::VERSION,'GET', $headers);
+        if ($result->getStatus()==204) {
+            $this->token = $result->getHeader(self::AUTHTOKEN);
+            $this->storageUrl = $result->getHeader(self::STORAGE_URL);
+            $this->cdnUrl = $result->getHeader(self::CDNM_URL);
+            $this->managementUrl = $result->getHeader(self::MANAGEMENT_URL);
+            return true;
+        }
+        $this->errorMsg = $result->getBody();
+        $this->errorCode = $result->getStatus();
+        return false;
+    } 
+}

+ 682 - 0
library/Zend/Service/Rackspace/Files.php

@@ -0,0 +1,682 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service
+ * @subpackage Rackspace
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Service/Rackspace/Abstract.php';
+require_once 'Zend/Service/Rackspace/Files/ContainerList.php';
+require_once 'Zend/Service/Rackspace/Files/ObjectList.php';
+require_once 'Zend/Service/Rackspace/Files/Container.php';
+require_once 'Zend/Service/Rackspace/Files/Object.php';
+
+class Zend_Service_Rackspace_Files extends Zend_Service_Rackspace_Abstract
+{
+    const ERROR_CONTAINER_NOT_EMPTY            = 'The container is not empty, I cannot delete it.';
+    const ERROR_CONTAINER_NOT_FOUND            = 'The container was not found.';
+    const ERROR_OBJECT_NOT_FOUND               = 'The object was not found.';
+    const ERROR_OBJECT_MISSING_PARAM           = 'Missing Content-Length or Content-Type header in the request';
+    const ERROR_OBJECT_CHECKSUM                = 'Checksum of the file content failed';
+    const ERROR_CONTAINER_EXIST                = 'The container already exists';
+    const ERROR_PARAM_NO_NAME_CONTAINER        = 'You must specify the container name';
+    const ERROR_PARAM_NO_NAME_OBJECT           = 'You must specify the object name';
+    const ERROR_PARAM_NO_CONTENT               = 'You must specify the content of the object';
+    const ERROR_PARAM_NO_NAME_SOURCE_CONTAINER = 'You must specify the source container name';
+    const ERROR_PARAM_NO_NAME_SOURCE_OBJECT    = 'You must specify the source object name';
+    const ERROR_PARAM_NO_NAME_DEST_CONTAINER   = 'You must specify the destination container name';
+    const ERROR_PARAM_NO_NAME_DEST_OBJECT      = 'You must specify the destination object name';
+    const ERROR_PARAM_NO_METADATA              = 'You must specify the metadata array';
+    const ERROR_CDN_TTL_OUT_OF_RANGE           = 'TTL must be a number in seconds, min is 900 sec and maximum is 1577836800 (50 years)';
+    const ERROR_PARAM_UPDATE_CDN               = 'You must specify at least one the parameters: ttl, cdn_enabled or log_retention';
+    const HEADER_CONTENT_TYPE                  = 'Content-type';
+    const HEADER_HASH                          = 'Etag';
+    const HEADER_LAST_MODIFIED                 = 'Last-modified';
+    const HEADER_CONTENT_LENGTH                = 'Content-length';
+    const HEADER_COPY_FROM                     = 'X-Copy-From';
+    const METADATA_OBJECT_HEADER               = "X-object-meta-";
+    const METADATA_CONTAINER_HEADER            = "X-container-meta-";
+    const CDN_URI                              = "X-CDN-URI";
+    const CDN_SSL_URI                          = "X-CDN-SSL-URI";
+    const CDN_ENABLED                          = "X-CDN-Enabled";
+    const CDN_LOG_RETENTION                    = "X-Log-Retention";
+    const CDN_ACL_USER_AGENT                   = "X-User-Agent-ACL";
+    const CDN_ACL_REFERRER                     = "X-Referrer-ACL";
+    const CDN_TTL                              = "X-TTL";
+    const CDN_TTL_MIN                          = 900;
+    const CDN_TTL_MAX                          = 1577836800;
+    const CDN_EMAIL                            = "X-Purge-Email";
+    const ACCOUNT_CONTAINER_COUNT              = "X-Account-Container-Count";
+    const ACCOUNT_BYTES_USED                   = "X-Account-Bytes-Used";
+    const ACCOUNT_OBJ_COUNT                    = "X-Account-Object-Count";
+    const CONTAINER_OBJ_COUNT                  = "X-Container-Object-Count";
+    const CONTAINER_BYTES_USE                  = "X-Container-Bytes-Used";
+    const MANIFEST_OBJECT_HEADER               = "X-Object-Manifest";
+
+    /**
+     * Return the total count of containers
+     *
+     * @return integer
+     */
+    public function getCountContainers()
+    {
+        $data= $this->getInfoAccount();
+        return $data['tot_containers'];
+    }
+    /**
+     * Return the size in bytes of all the containers
+     *
+     * @return integer
+     */
+    public function getSizeContainers()
+    {
+        $data= $this->getInfoAccount();
+        return $data['size_containers'];
+    }
+    /**
+     * Return the count of objects contained in all the containers
+     *
+     * @return integer
+     */
+    public function getCountObjects()
+    {
+        $data= $this->getInfoAccount();
+        return $data['tot_objects'];
+    }
+    /**
+     * Get all the containers
+     *
+     * @param array $options
+     * @return Zend_Service_Rackspace_Files_ContainerList|boolean
+     */
+    public function getContainers($options=array())
+    {
+        $result= $this->httpCall($this->getStorageUrl(),'GET',null,$options);
+        if ($result->isSuccessful()) {
+            return new Zend_Service_Rackspace_Files_ContainerList($this,json_decode($result->getBody(),true));
+        }
+        return false;
+    }
+    /**
+     * Get all the CDN containers
+     *
+     * @param array $options
+     * @return array|boolean
+     */
+    public function getCdnContainers($options=array())
+    {
+        $options['enabled_only']= true;
+        $result= $this->httpCall($this->getCdnUrl(),'GET',null,$options);
+        if ($result->isSuccessful()) {
+            return new Zend_Service_Rackspace_Files_ContainerList($this,json_decode($result->getBody(),true));
+        }
+        return false;
+    }
+    /**
+     * Get the metadata information of the accounts:
+     * - total count containers
+     * - size in bytes of all the containers
+     * - total objects in all the containers
+     * 
+     * @return array|boolean
+     */
+    public function getInfoAccount()
+    {
+        $result= $this->httpCall($this->getStorageUrl(),'HEAD');
+        if ($result->isSuccessful()) {
+            $output= array(
+                'tot_containers'  => $result->getHeader(self::ACCOUNT_CONTAINER_COUNT),
+                'size_containers' => $result->getHeader(self::ACCOUNT_BYTES_USED),
+                'tot_objects'     => $result->getHeader(self::ACCOUNT_OBJ_COUNT)
+            );
+            return $output;
+        }
+        return false;
+    }
+    /**
+     * Get all the objects of a container
+     *
+     * @param string $container
+     * @param array $options
+     * @return  Zend_Service_Rackspace_Files_ObjectList|boolean
+     */
+    public function getObjects($container,$options=array())
+    {
+        if (empty($container)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_CONTAINER);
+        }
+        $result= $this->httpCall($this->getStorageUrl().'/'.rawurlencode($container),'GET',null,$options);
+        if ($result->isSuccessful()) {
+            return new Zend_Service_Rackspace_Files_ObjectList($this,json_decode($result->getBody(),true),$container);
+        }
+        return false;
+    }
+    /**
+     * Create a container
+     *
+     * @param string $container
+     * @param array $metadata
+     * @return Zend_Service_Rackspace_Files_Container|boolean
+     */
+    public function createContainer($container,$metadata=array())
+    {
+        if (empty($container)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_CONTAINER);
+        }
+        $headers=array();
+        if (!empty($metadata)) {
+            foreach ($metadata as $key => $value) {
+                $headers[self::METADATA_CONTAINER_HEADER.rawurlencode(strtolower($key))]= rawurlencode($value);
+            }
+        }
+        $result= $this->httpCall($this->getStorageUrl().'/'.rawurlencode($container),'PUT',$headers);
+        $status= $result->getStatus();
+        switch ($status) {
+            case '201': // break intentionally omitted
+                $data= array(
+                    'name' => $container
+                );
+                return new Zend_Service_Rackspace_Files_Container($this,$data);
+            case '202':
+                $this->errorMsg= self::ERROR_CONTAINER_EXIST;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Delete a container (only if it's empty)
+     *
+     * @param sting $container
+     * @return boolean
+     */
+    public function deleteContainer($container)
+    {
+        if (empty($container)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_CONTAINER);
+        }
+        $result= $this->httpCall($this->getStorageUrl().'/'.rawurlencode($container),'DELETE');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '204': // break intentionally omitted
+                return true;
+            case '409':
+                $this->errorMsg= self::ERROR_CONTAINER_NOT_EMPTY;
+                break;
+            case '404':
+                $this->errorMsg= self::ERROR_CONTAINER_NOT_FOUND;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Get the metadata of a container
+     *
+     * @param string $container
+     * @return array|boolean
+     */
+    public function getMetadataContainer($container)
+    {
+        if (empty($container)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_CONTAINER);
+        }
+        $result= $this->httpCall($this->getStorageUrl().'/'.rawurlencode($container),'HEAD');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '204': // break intentionally omitted
+                $headers= $result->getHeaders();
+                $count= strlen(self::METADATA_CONTAINER_HEADER);
+                $metadata= array();
+                foreach ($headers as $type => $value) {
+                    if (strpos($type,self::METADATA_CONTAINER_HEADER)!==false) {
+                        $metadata[strtolower(substr($type, $count))]= $value;
+                    }
+                }
+                $data= array (
+                    'name'     => $container,
+                    'count'    => $result->getHeader(self::CONTAINER_OBJ_COUNT),
+                    'bytes'    => $result->getHeader(self::CONTAINER_BYTES_USE),
+                    'metadata' => $metadata
+                );
+                return $data;
+            case '404':
+                $this->errorMsg= self::ERROR_CONTAINER_NOT_FOUND;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Get a container
+     * 
+     * @param string $container
+     * @return Container|boolean
+     */
+    public function getContainer($container) {
+        $result= $this->getMetadataContainer($container);
+        if (!empty($result)) {
+            return new Zend_Service_Rackspace_Files_Container($this,$result);
+        }
+        return false;
+    }
+    /**
+     * Get an object in a container
+     *
+     * @param string $container
+     * @param string $object
+     * @param array $headers
+     * @return Zend_Service_Rackspace_Files_Object|boolean
+     */
+    public function getObject($container,$object,$headers=array())
+    {
+        if (empty($container)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_CONTAINER);
+        }
+        if (empty($object)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_OBJECT);
+        }
+        $result= $this->httpCall($this->getStorageUrl().'/'.rawurlencode($container).'/'.rawurlencode($object),'GET',$headers);
+        $status= $result->getStatus();
+        switch ($status) {
+            case '200': // break intentionally omitted
+                $data= array(
+                    'name'          => $object,
+                    'container'     => $container,
+                    'hash'          => $result->getHeader(self::HEADER_HASH),
+                    'bytes'         => $result->getHeader(self::HEADER_CONTENT_LENGTH),
+                    'last_modified' => $result->getHeader(self::HEADER_LAST_MODIFIED),
+                    'content_type'  => $result->getHeader(self::HEADER_CONTENT_TYPE),
+                    'content'       => $result->getBody()
+                );
+                return new Zend_Service_Rackspace_Files_Object($this,$data);
+            case '404':
+                $this->errorMsg= self::ERROR_OBJECT_NOT_FOUND;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Store a file in a container 
+     *
+     * @param string $container
+     * @param string $object
+     * @param string $content
+     * @param array $metadata
+     * @return boolean
+     */
+    public function storeObject($container,$object,$content,$metadata=array()) {
+        if (empty($container)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_CONTAINER);
+        }
+        if (empty($object)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_OBJECT);
+        }
+        if (empty($content)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_CONTENT);
+        }
+        if (!empty($metadata) && is_array($metadata)) {
+            foreach ($metadata as $key => $value) {
+                $headers[self::METADATA_OBJECT_HEADER.$key]= $value;
+            }
+        }
+        $headers[self::HEADER_HASH]= md5($content);
+        $headers[self::HEADER_CONTENT_LENGTH]= strlen($content);
+        $result= $this->httpCall($this->getStorageUrl().'/'.rawurlencode($container).'/'.rawurlencode($object),'PUT',$headers,null,$content);
+        $status= $result->getStatus();
+        switch ($status) {
+            case '201': // break intentionally omitted
+                return true;
+            case '412':
+                $this->errorMsg= self::ERROR_OBJECT_MISSING_PARAM;
+                break;
+            case '422':
+                $this->errorMsg= self::ERROR_OBJECT_CHECKSUM;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Delete an object in a container
+     *
+     * @param string $container
+     * @param string $object
+     * @return boolean
+     */
+    public function deleteObject($container,$object) {
+        if (empty($container)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_CONTAINER);
+        }
+        if (empty($object)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_OBJECT);
+        }
+        $result= $this->httpCall($this->getStorageUrl().'/'.rawurlencode($container).'/'.rawurlencode($object),'DELETE');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '204': // break intentionally omitted
+                return true;
+            case '404':
+                $this->errorMsg= self::ERROR_OBJECT_NOT_FOUND;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Copy an object from a container to another
+     *
+     * @param string $container_source
+     * @param string $obj_source
+     * @param string $container_dest
+     * @param string $obj_dest
+     * @param array $metadata
+     * @param string $content_type
+     * @return boolean
+     */
+    public function copyObject($container_source,$obj_source,$container_dest,$obj_dest,$metadata=array(),$content_type=null) {
+        if (empty($container_source)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_SOURCE_CONTAINER);
+        }
+        if (empty($obj_source)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_SOURCE_OBJECT);
+        }
+        if (empty($container_dest)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_DEST_CONTAINER);
+        }
+        if (empty($obj_dest)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_DEST_OBJECT);
+        }
+        $headers= array(
+            self::HEADER_COPY_FROM => '/'.rawurlencode($container_source).'/'.rawurlencode($obj_source),
+            self::HEADER_CONTENT_LENGTH => 0
+        );
+        if (!empty($content_type)) {
+            $headers[self::HEADER_CONTENT_TYPE]= $content_type;
+        }
+        if (!empty($metadata) && is_array($metadata)) {
+            foreach ($metadata as $key => $value) {
+                $headers[self::METADATA_OBJECT_HEADER.$key]= $value;
+            }
+        }
+        $result= $this->httpCall($this->getStorageUrl().'/'.rawurlencode($container_dest).'/'.rawurlencode($obj_dest),'PUT',$headers);
+        $status= $result->getStatus();
+        switch ($status) {
+            case '201': // break intentionally omitted
+                return true;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Get the metadata of an object
+     *
+     * @param string $container
+     * @param string $object
+     * @return array|boolean
+     */
+    public function getMetadataObject($container,$object) {
+        if (empty($container)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_CONTAINER);
+        }
+        if (empty($object)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_OBJECT);
+        }
+        $result= $this->httpCall($this->getStorageUrl().'/'.rawurlencode($container).'/'.rawurlencode($object),'HEAD');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '200': // break intentionally omitted
+                $headers= $result->getHeaders();
+                $count= strlen(self::METADATA_OBJECT_HEADER);
+                $metadata= array();
+                foreach ($headers as $type => $value) {
+                    if (strpos($type,self::METADATA_OBJECT_HEADER)!==false) {
+                        $metadata[strtolower(substr($type, $count))]= $value;
+                    }
+                }
+                $data= array (
+                    'name'          => $object,
+                    'container'     => $container,
+                    'hash'          => $result->getHeader(self::HEADER_HASH),
+                    'bytes'         => $result->getHeader(self::HEADER_CONTENT_LENGTH),
+                    'content_type'  => $result->getHeader(self::HEADER_CONTENT_TYPE),
+                    'last_modified' => $result->getHeader(self::HEADER_LAST_MODIFIED),
+                    'metadata'      => $metadata
+                );
+                return $data;
+            case '404':
+                $this->errorMsg= self::ERROR_OBJECT_NOT_FOUND;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Set the metadata of a object in a container
+     * The old metadata values are replaced with the new one
+     * 
+     * @param string $container
+     * @param string $object
+     * @param array $metadata
+     * @return boolean
+     */
+    public function setMetadataObject($container,$object,$metadata)
+    {
+        if (empty($container)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_CONTAINER);
+        }
+        if (empty($object)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_OBJECT);
+        }
+        if (empty($metadata) || !is_array($metadata)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_OBJECT);
+        }
+        $headers=array();
+        foreach ($metadata as $key => $value) {
+            $headers[self::METADATA_OBJECT_HEADER.$key]= $value;
+        }
+        $result= $this->httpCall($this->getStorageUrl().'/'.rawurlencode($container).'/'.rawurlencode($object),'POST',$headers);
+        $status= $result->getStatus();
+        switch ($status) {
+            case '202': // break intentionally omitted
+                return true;
+            case '404':
+                $this->errorMsg= self::ERROR_OBJECT_NOT_FOUND;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Enable the CDN for a container
+     *
+     * @param  string $container
+     * @param  integer $ttl
+     * @return array|boolean
+     */
+    public function enableCdnContainer ($container,$ttl=self::CDN_TTL_MIN) {
+        if (empty($container)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_CONTAINER);
+        }
+        $headers=array();
+        if (is_numeric($ttl) && ($ttl>=self::CDN_TTL_MIN) && ($ttl<=self::CDN_TTL_MAX)) {
+            $headers[self::CDN_TTL]= $ttl;
+        } else {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_CDN_TTL_OUT_OF_RANGE);
+        }
+        $result= $this->httpCall($this->getCdnUrl().'/'.rawurlencode($container),'PUT',$headers);
+        $status= $result->getStatus();
+        switch ($status) {
+            case '201':
+            case '202': // break intentionally omitted
+                $data= array (
+                    'cdn_uri'     => $result->getHeader(self::CDN_URI),
+                    'cdn_uri_ssl' => $result->getHeader(self::CDN_SSL_URI)
+                );
+                return $data;
+            case '404':
+                $this->errorMsg= self::ERROR_CONTAINER_NOT_FOUND;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Update the attribute of a CDN container
+     *
+     * @param  string $container
+     * @param  integer $ttl
+     * @param  boolean $cdn_enabled
+     * @param  boolean $log
+     * @return boolean
+     */
+    public function updateCdnContainer($container,$ttl=null,$cdn_enabled=null,$log=null)
+    {
+        if (empty($container)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_CONTAINER);
+        }
+        if (empty($ttl) && (!isset($cdn_enabled)) && (!isset($log))) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_UPDATE_CDN);
+        }
+        $headers=array();
+        if (isset($ttl)) {
+            if (is_numeric($ttl) && ($ttl>=self::CDN_TTL_MIN) && ($ttl<=self::CDN_TTL_MAX)) {
+                $headers[self::CDN_TTL]= $ttl;
+            } else {
+                require_once 'Zend/Service/Rackspace/Exception.php';
+                throw new Zend_Service_Rackspace_Exception(self::ERROR_CDN_TTL_OUT_OF_RANGE);
+            }
+        }
+        if (isset($cdn_enabled)) {
+            if ($cdn_enabled===true) {
+                $headers[self::CDN_ENABLED]= 'true';
+            } else {
+                $headers[self::CDN_ENABLED]= 'false';
+            }
+        }
+        if (isset($log)) {
+            if ($log===true) {
+                $headers[self::CDN_LOG_RETENTION]= 'true';
+            } else  {
+                $headers[self::CDN_LOG_RETENTION]= 'false';
+            }
+        }
+        $result= $this->httpCall($this->getCdnUrl().'/'.rawurlencode($container),'POST',$headers);
+        $status= $result->getStatus();
+        switch ($status) {
+            case '200':
+            case '202': // break intentionally omitted
+                return true;
+            case '404':
+                $this->errorMsg= self::ERROR_CONTAINER_NOT_FOUND;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Get the information of a Cdn container
+     *
+     * @param string $container
+     * @return array|boolean
+     */
+    public function getInfoCdnContainer($container) {
+        if (empty($container)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME_CONTAINER);
+        }
+        $result= $this->httpCall($this->getCdnUrl().'/'.rawurlencode($container),'HEAD');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '204': // break intentionally omitted
+                $data= array (
+                    'ttl'         => $result->getHeader(self::CDN_TTL),
+                    'cdn_uri'     => $result->getHeader(self::CDN_URI),
+                    'cdn_uri_ssl' => $result->getHeader(self::CDN_SSL_URI)
+                );
+                $data['cdn_enabled']= (strtolower($result->getHeader(self::CDN_ENABLED))!=='false');
+                $data['log_retention']= (strtolower($result->getHeader(self::CDN_LOG_RETENTION))!=='false');
+                return $data;
+            case '404':
+                $this->errorMsg= self::ERROR_CONTAINER_NOT_FOUND;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+}

+ 329 - 0
library/Zend/Service/Rackspace/Files/Container.php

@@ -0,0 +1,329 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Files
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Service/Rackspace/Files.php';
+
+class Zend_Service_Rackspace_Files_Container
+{
+    const ERROR_PARAM_FILE_CONSTRUCT  = 'The Zend_Service_Rackspace_Files passed in construction is not valid';
+    const ERROR_PARAM_ARRAY_CONSTRUCT = 'The array passed in construction is not valid';
+    const ERROR_PARAM_NO_NAME         = 'The container name is empty';
+    /**
+     * @var string
+     */
+    protected $name;
+    /**
+     * Construct
+     *
+     * @param Zend_Service_Rackspace_Files $service
+     * @param string $name
+     */
+    public function __construct($service, $data)
+    {
+        if (!($service instanceof Zend_Service_Rackspace_Files)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception(self::ERROR_PARAM_FILE_CONSTRUCT);
+        }
+        if (!is_array($data)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception(self::ERROR_PARAM_ARRAY_CONSTRUCT);
+        }
+        if (!array_key_exists('name', $data)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception(self::ERROR_PARAM_NO_NAME);
+        }    
+        $this->service = $service;
+        $this->name = $data['name'];
+    }
+    /**
+     * Get the name of the container
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+    /**
+     * Get the size in bytes of the container
+     *
+     * @return integer|boolean
+     */
+    public function getSize()
+    {
+        $data = $this->getInfo();
+        if (isset($data['bytes'])) {
+            return $data['bytes'];
+        }
+        return false;
+    }
+    /**
+     * Get the total count of objects in the container
+     *
+     * @return integer|boolean
+     */
+    public function getObjectCount()
+    {
+        $data = $this->getInfo();
+        if (isset($data['count'])) {
+            return $data['count'];
+        }
+        return false;
+    }
+    /**
+     * Return true if the container is CDN enabled
+     * 
+     * @return boolean
+     */
+    public function isCdnEnabled()
+    {
+        $data = $this->getCdnInfo();
+        if (isset($data['cdn_enabled'])) {
+            return $data['cdn_enabled'];
+        }
+        return false;
+    }
+    /**
+     * Get the TTL of the CDN
+     * 
+     * @return integer|boolean 
+     */
+    public function getCdnTtl() 
+    {
+        $data = $this->getCdnInfo();
+        if (!isset($data['ttl'])) {
+            return $data['ttl'];
+        }
+        return false;
+    }
+    /**
+     * Return true if the log retention is enabled for the CDN
+     *
+     * @return boolean
+     */
+    public function isCdnLogEnabled()
+    {
+        $data = $this->getCdnInfo();
+        if (!isset($data['log_retention'])) {
+            return $data['log_retention'];
+        }
+        return false;
+    }
+    /**
+     * Get the CDN URI
+     * 
+     * @return string|boolean
+     */
+    public function getCdnUri()
+    {
+        $data = $this->getCdnInfo();
+        if (!isset($data['cdn_uri'])) {
+            return $data['cdn_uri'];
+        }
+        return false;
+    }
+    /**
+     * Get the CDN URI SSL
+     *
+     * @return string|boolean
+     */
+    public function getCdnUriSsl()
+    {
+        $data = $this->getCdnInfo();
+        if (!isset($data['cdn_uri_ssl'])) {
+            return $data['cdn_uri_ssl'];
+        }
+        return false;
+    }
+    /**
+     * Get the metadata of the container
+     *
+     * If $key is empty return the array of metadata
+     *
+     * @param string $key
+     * @return array|string|boolean
+     */
+    public function getMetadata($key=null)
+    {
+        $result = $this->service->getMetadataContainer($this->getName());
+        if (!empty($result) && is_array($result)) {
+            if (empty($key)) {
+                return $result['metadata'];
+            } else {
+                if (isset ($result['metadata'][$key])) {
+                    return $result['metadata'][$key];
+                }
+            }    
+        }    
+        return false;
+    }
+    /**
+     * Get the information of the container (total of objects, total size)
+     * 
+     * @return array|boolean 
+     */
+    public function getInfo()
+    {
+        $result = $this->service->getMetadataContainer($this->getName());
+        if (!empty($result) && is_array($result)) {
+           return $result;
+        }
+        return false;
+    }
+    /**
+     * Get all the object of the container
+     *
+     * @return Zend_Service_Rackspace_Files_ObjectList
+     */
+    public function getObjects()
+    {
+        return $this->service->getObjects($this->getName());
+    }
+    /**
+     * Get an object of the container
+     * 
+     * @param string $name
+     * @param array $headers
+     * @return Zend_Service_Rackspace_Files_Object|boolean
+     */
+    public function getObject($name, $headers=array())
+    {
+        return $this->service->getObject($this->getName(), $name, $headers);
+    }
+    /**
+     * Add an object in the container
+     *
+     * @param string $name
+     * @param string $file the content of the object
+     * @param array $metadata
+     * @return boolen
+     */
+    public function addObject($name, $file, $metadata=array())
+    {
+        return $this->service->storeObject($this->getName(), $name, $file, $metadata);
+    }
+    /**
+     * Delete an object in the container
+     *
+     * @param string $obj
+     * @return boolean
+     */
+    public function deleteObject($obj)
+    {
+        return $this->service->deleteObject($this->getName(), $obj);
+    }
+    /**
+     * Copy an object to another container
+     *
+     * @param string $obj_source
+     * @param string $container_dest
+     * @param string $obj_dest
+     * @param array $metadata
+     * @param string $content_type
+     * @return boolean
+     */
+    public function copyObject($obj_source, $container_dest, $obj_dest, $metadata=array(), $content_type=null)
+    {
+        return $this->service->copyObject($this->getName(), $obj_source, $container_dest, $obj_dest, $metadata, $content_type);
+    }
+    /**
+     * Get the metadata of an object in the container
+     *
+     * @param string $object
+     * @return array
+     */
+    public function getMetadataObject($object)
+    {
+        return $this->service->getMetadataObject($this->getName(),$object);
+    }
+    /**
+     * Set the metadata of an object in the container
+     *
+     * @param string $object
+     * @param array $metadata
+     * @return boolean
+     */
+    public function setMetadataObject($object,$metadata=array()) 
+    {
+        return $this->service->setMetadataObject($this->getName(),$object,$metadata);
+    }
+    /**
+     * Enable the CDN for the container
+     *
+     * @param integer $ttl
+     * @return array|boolean
+     */
+    public function enableCdn($ttl=Zend_Service_Rackspace_Files::CDN_TTL_MIN) 
+    {
+        return $this->service->enableCdnContainer($this->getName(),$ttl);
+    }
+    /**
+     * Disable the CDN for the container
+     * 
+     * @return boolean
+     */
+    public function disableCdn() 
+    {
+        $result = $this->service->updateCdnContainer($this->getName(),null,false);
+        return ($result!==false);
+    }
+    /**
+     * Change the TTL for the CDN container
+     *
+     * @param integer $ttl
+     * @return boolean
+     */
+    public function changeTtlCdn($ttl) 
+    {
+        $result =  $this->service->updateCdnContainer($this->getName(),$ttl);
+        return ($result!==false);
+    }
+    /**
+     * Enable the log retention for the CDN
+     *
+     * @return boolean
+     */
+    public function enableLogCdn() 
+    {
+        $result =  $this->service->updateCdnContainer($this->getName(),null,null,true);
+        return ($result!==false);
+    }
+    /**
+     * Disable the log retention for the CDN
+     *
+     * @return boolean
+     */
+    public function disableLogCdn() 
+    {
+        $result =  $this->service->updateCdnContainer($this->getName(),null,null,false);
+        return ($result!==false);
+    }
+    /**
+     * Get the CDN information
+     *
+     * @return array|boolean
+     */
+    public function getCdnInfo() 
+    {
+        return $this->service->getInfoCdnContainer($this->getName());
+    }
+}

+ 221 - 0
library/Zend/Service/Rackspace/Files/ContainerList.php

@@ -0,0 +1,221 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Files
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Service/Rackspace/Files/Container.php';
+require_once 'Zend/Service/Rackspace/Files.php';
+
+/**
+ * List of servers retrived from the Rackspace web service
+ *
+ * @uses       ArrayAccess
+ * @uses       Countable
+ * @uses       Iterator
+ * @uses       OutOfBoundsException
+ * @uses       Zend_Service_Rackspace_Files_Container
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Files
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_Rackspace_Files_ContainerList implements Countable, Iterator, ArrayAccess
+{
+    /**
+     * @var array Array of Zend_Service_Rackspace_Files_Container
+     */
+    protected $objects = array();
+    /**
+     * @var int Iterator key
+     */
+    protected $iteratorKey = 0;
+    /**
+     * @var RackspaceFiles
+     */
+    protected $service;
+    /**
+     * Constructor
+     *
+     * @param  array $list
+     * @return boolean
+     */
+    public function __construct($service,$list = array())
+    {
+        if (!($service instanceof Zend_Service_Rackspace_Files ) || !is_array($list)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception("You must pass a Zend_Service_Rackspace_Files_Exception object and an array");
+        }
+        $this->service= $service;
+        $this->_constructFromArray($list);
+    }
+    /**
+     * Transforms the Array to array of container
+     *
+     * @param  array $list
+     * @return void
+     */
+    private function _constructFromArray(array $list)
+    {
+        foreach ($list as $container) {
+            $this->_addObject(new Zend_Service_Rackspace_Files_Container($this->service,$container));
+        }
+    }
+    /**
+     * Add an object
+     *
+     * @param  Zend_Service_Rackspace_Files_Container $obj
+     * @return Zend_Service_Rackspace_Files_ContainerList
+     */
+    protected function _addObject (Zend_Service_Rackspace_Files_Container $obj)
+    {
+        $this->objects[] = $obj;
+        return $this;
+    }
+    /**
+     * Return number of servers
+     *
+     * Implement Countable::count()
+     *
+     * @return int
+     */
+    public function count()
+    {
+        return count($this->objects);
+    }
+    /**
+     * Return the current element
+     *
+     * Implement Iterator::current()
+     *
+     * @return Zend_Service_Rackspace_Files_Container
+     */
+    public function current()
+    {
+        return $this->objects[$this->iteratorKey];
+    }
+    /**
+     * Return the key of the current element
+     *
+     * Implement Iterator::key()
+     *
+     * @return int
+     */
+    public function key()
+    {
+        return $this->iteratorKey;
+    }
+    /**
+     * Move forward to next element
+     *
+     * Implement Iterator::next()
+     *
+     * @return void
+     */
+    public function next()
+    {
+        $this->iteratorKey += 1;
+    }
+    /**
+     * Rewind the Iterator to the first element
+     *
+     * Implement Iterator::rewind()
+     *
+     * @return void
+     */
+    public function rewind()
+    {
+        $this->iteratorKey = 0;
+    }
+    /**
+     * Check if there is a current element after calls to rewind() or next()
+     *
+     * Implement Iterator::valid()
+     *
+     * @return bool
+     */
+    public function valid()
+    {
+        $numItems = $this->count();
+        if ($numItems > 0 && $this->iteratorKey < $numItems) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+    /**
+     * Whether the offset exists
+     *
+     * Implement ArrayAccess::offsetExists()
+     *
+     * @param   int     $offset
+     * @return  bool
+     */
+    public function offsetExists($offset)
+    {
+        return ($offset < $this->count());
+    }
+    /**
+     * Return value at given offset
+     *
+     * Implement ArrayAccess::offsetGet()
+     *
+     * @param   int     $offset
+     * @throws  Zend_Service_Rackspace_Files_Exception
+     * @return  Zend_Service_Rackspace_Files_Container
+     */
+    public function offsetGet($offset)
+    {
+        if ($this->offsetExists($offset)) {
+            return $this->objects[$offset];
+        } else {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception('Illegal index');
+        }
+    }
+
+    /**
+     * Throws exception because all values are read-only
+     *
+     * Implement ArrayAccess::offsetSet()
+     *
+     * @param   int     $offset
+     * @param   string  $value
+     * @throws  Zend_Service_Rackspace_Files_Exception
+     */
+    public function offsetSet($offset, $value)
+    {
+        require_once 'Zend/Service/Rackspace/Files/Exception.php';
+        throw new Zend_Service_Rackspace_Files_Exception('You are trying to set read-only property');
+    }
+
+    /**
+     * Throws exception because all values are read-only
+     *
+     * Implement ArrayAccess::offsetUnset()
+     *
+     * @param   int     $offset
+     * @throws  Zend_Service_Rackspace_Files_Exception
+     */
+    public function offsetUnset($offset)
+    {
+        require_once 'Zend/Service/Rackspace/Files/Exception.php';
+        throw new Zend_Service_Rackspace_Files_Exception('You are trying to unset read-only property');
+    }
+}

+ 271 - 0
library/Zend/Service/Rackspace/Files/Object.php

@@ -0,0 +1,271 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Files
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Service/Rackspace/Files.php';
+
+class Zend_Service_Rackspace_Files_Object
+{
+    /**
+     * The service that has created the object
+     *
+     * @var Zend_Service_Rackspace_Files
+     */
+    protected $service;
+    /**
+     * Name of the object
+     *
+     * @var string
+     */
+    protected $name;
+    /**
+     * MD5 value of the object's content
+     *
+     * @var string
+     */
+    protected $hash;
+    /**
+     * Size in bytes of the object's content
+     *
+     * @var integer
+     */
+    protected $size;
+    /**
+     * Content type of the object's content
+     *
+     * @var string
+     */
+    protected $contentType;
+    /**
+     * Date of the last modified of the object
+     *
+     * @var string
+     */
+    protected $lastModified;
+    /**
+     * Object content
+     *
+     * @var string
+     */
+    protected $content;
+    /**
+     * Name of the container where the object is stored
+     *
+     * @var string
+     */
+    protected $container;
+    /**
+     * Constructor
+     * 
+     * You must pass the Zend_Service_Rackspace_Files object of the caller and an associative
+     * array with the keys "name", "container", "hash", "bytes", "content_type",
+     * "last_modified", "file" where:
+     * name= name of the object
+     * container= name of the container where the object is stored
+     * hash= the MD5 of the object's content
+     * bytes= size in bytes of the object's content
+     * content_type= content type of the object's content
+     * last_modified= date of the last modified of the object
+     * content= content of the object
+     * 
+     * @param Zend_Service_Rackspace_Files $service
+     * @param array $data 
+     */
+    public function __construct($service,$data)
+    {
+        if (!($service instanceof Zend_Service_Rackspace_Files) || !is_array($data)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception("You must pass a RackspaceFiles and an array");
+        }
+        if (!array_key_exists('name', $data)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception("You must pass the name of the object in the array (name)");
+        }
+        if (!array_key_exists('container', $data)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception("You must pass the container of the object in the array (container)");
+        }
+        if (!array_key_exists('hash', $data)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception("You must pass the hash of the object in the array (hash)");
+        }
+        if (!array_key_exists('bytes', $data)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception("You must pass the byte size of the object in the array (bytes)");
+        }
+        if (!array_key_exists('content_type', $data)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception("You must pass the content type of the object in the array (content_type)");
+        }
+        if (!array_key_exists('last_modified', $data)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception("You must pass the last modified data of the object in the array (last_modified)");
+        }
+        $this->name= $data['name'];
+        $this->container= $data['container'];
+        $this->hash= $data['hash'];
+        $this->size= $data['bytes'];
+        $this->contentType= $data['content_type'];
+        $this->lastModified= $data['last_modified'];
+        if (!empty($data['content'])) {
+            $this->content= $data['content'];
+        }
+        $this->service= $service;
+    }
+    /**
+     * Get name
+     *
+     * @return string
+     */
+    public function getName() 
+    {
+        return $this->name;
+    }
+    /**
+     * Get the name of the container
+     *
+     * @return string
+     */
+    public function getContainer() 
+    {
+        return $this->container;
+    }
+    /**
+     * Get the MD5 of the object's content
+     *
+     * @return string|boolean
+     */
+    public function getHash() 
+    {
+        return $this->hash;
+    }
+    /**
+     * Get the size (in bytes) of the object's content
+     *
+     * @return integer|boolean
+     */
+    public function getSize() 
+    {
+        return $this->size;
+    }
+    /**
+     * Get the content type of the object's content
+     *
+     * @return string
+     */
+    public function getContentType() 
+    {
+        return $this->contentType;
+    }
+    /**
+     * Get the data of the last modified of the object
+     *
+     * @return string
+     */
+    public function getLastModified() 
+    {
+        return $this->lastModified;
+    }
+    /**
+     * Get the content of the object
+     *
+     * @return string
+     */
+    public function getContent() 
+    {
+        return $this->content;
+    }
+    /**
+     * Get the metadata of the object
+     * If you don't pass the $key it returns the entire array of metadata value
+     *
+     * @param  string $key
+     * @return string|array|boolean
+     */
+    public function getMetadata($key=null) 
+    {
+        $result= $this->service->getMetadataObject($this->container,$this->name);
+        if (!empty($result)) {
+            if (empty($key)) {
+                return $result['metadata'];
+            }
+            if (isset($result['metadata'][$key])) {
+                return $result['metadata'][$key];
+            }
+        }
+        return false;
+    }
+    /**
+     * Set the metadata value
+     * The old metadata values are replaced with the new one
+     * 
+     * @param array $metadata
+     * @return boolean
+     */
+    public function setMetadata($metadata) 
+    {
+        return $this->service->setMetadataObject($this->container,$this->name,$metadata);
+    }
+    /**
+     * Copy the object to another container
+     * You can add metadata information to the destination object, change the
+     * content_type and the name of the object
+     *
+     * @param  string $container_dest
+     * @param  string $name_dest
+     * @param  array $metadata
+     * @param  string $content_type
+     * @return boolean
+     */
+    public function copyTo($container_dest,$name_dest,$metadata=array(),$content_type=null) 
+    {
+        return $this->service->copyObject($this->container,$this->name,$container_dest,$name_dest,$metadata,$content_type);
+    }
+    /**
+     * Get the CDN URL of the object
+     *
+     * @return string
+     */
+    public function getCdnUrl() 
+    {
+        $result= $this->service->getInfoCdnContainer($this->container);
+        if ($result!==false) {
+            if ($result['cdn_enabled']) {
+                return $result['cdn_uri'].'/'.$this->name;
+            }
+        }
+        return false;
+    }
+    /**
+     * Get the CDN SSL URL of the object
+     *
+     * @return string
+     */
+    public function getCdnUrlSsl() 
+    {
+        $result= $this->service->getInfoCdnContainer($this->container);
+        if ($result!==false) {
+            if ($result['cdn_enabled']) {
+                return $result['cdn_uri_ssl'].'/'.$this->name;
+            }
+        }
+        return false;
+    }
+}

+ 237 - 0
library/Zend/Service/Rackspace/Files/ObjectList.php

@@ -0,0 +1,237 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Files
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Service/Rackspace/Files/Object.php';
+require_once 'Zend/Service/Rackspace/Files.php';
+
+/**
+ * List of servers retrived from the GoGrid web service
+ *
+ * @uses       ArrayAccess
+ * @uses       Countable
+ * @uses       Iterator
+ * @uses       OutOfBoundsException
+ * @uses       Zend_Service_Rackspace_Files
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Files
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_Rackspace_Files_ObjectList implements Countable, Iterator, ArrayAccess
+{
+    /**
+     * @var array of Zend_Service_Rackspace_Files_Object
+     */
+    protected $objects = array();
+    /**
+     * @var int Iterator key
+     */
+    protected $iteratorKey = 0;
+    /**
+     * @var RackspaceFiles
+     */
+    protected $service;
+    /**
+     * The container name of the object list
+     * 
+     * @var string
+     */
+    protected $container;
+    /**
+     * Construct
+     *
+     * @param  array $list
+     * @return boolean
+     */
+    public function __construct($service,$list,$container)
+    {
+        if (!($service instanceof Zend_Service_Rackspace_Files)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception("You must pass a Zend_Service_Rackspace_Files object");
+        }
+        if (empty($list)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception("You must pass an array of data objects");
+        }
+        if (empty($container)) {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception("You must pass the container of the object list");
+        }
+        $this->service= $service;
+        $this->container= $container;
+        $this->_constructFromArray($list);
+    }
+    /**
+     * Transforms the Array to array of container
+     *
+     * @param  array $list
+     * @return void
+     */
+    private function _constructFromArray(array $list)
+    {
+        foreach ($list as $obj) {
+            $obj['container']= $this->container;
+            $this->_addObject(new Zend_Service_Rackspace_Files_Object($this->service,$obj));
+        }
+    }
+    /**
+     * Add an object
+     *
+     * @param  Zend_Service_Rackspace_Files_Object $obj
+     * @return Zend_Service_Rackspace_Files_ObjectList
+     */
+    protected function _addObject (Zend_Service_Rackspace_Files_Object $obj)
+    {
+        $this->objects[] = $obj;
+        return $this;
+    }
+    /**
+     * Return number of servers
+     *
+     * Implement Countable::count()
+     *
+     * @return int
+     */
+    public function count()
+    {
+        return count($this->objects);
+    }
+    /**
+     * Return the current element
+     *
+     * Implement Iterator::current()
+     *
+     * @return Zend_Service_Rackspace_Files_Object
+     */
+    public function current()
+    {
+        return $this->objects[$this->iteratorKey];
+    }
+    /**
+     * Return the key of the current element
+     *
+     * Implement Iterator::key()
+     *
+     * @return int
+     */
+    public function key()
+    {
+        return $this->iteratorKey;
+    }
+    /**
+     * Move forward to next element
+     *
+     * Implement Iterator::next()
+     *
+     * @return void
+     */
+    public function next()
+    {
+        $this->iteratorKey += 1;
+    }
+    /**
+     * Rewind the Iterator to the first element
+     *
+     * Implement Iterator::rewind()
+     *
+     * @return void
+     */
+    public function rewind()
+    {
+        $this->iteratorKey = 0;
+    }
+    /**
+     * Check if there is a current element after calls to rewind() or next()
+     *
+     * Implement Iterator::valid()
+     *
+     * @return bool
+     */
+    public function valid()
+    {
+        $numItems = $this->count();
+        if ($numItems > 0 && $this->iteratorKey < $numItems) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+    /**
+     * Whether the offset exists
+     *
+     * Implement ArrayAccess::offsetExists()
+     *
+     * @param   int     $offset
+     * @return  bool
+     */
+    public function offsetExists($offset)
+    {
+        return ($offset < $this->count());
+    }
+    /**
+     * Return value at given offset
+     *
+     * Implement ArrayAccess::offsetGet()
+     *
+     * @param   int     $offset
+     * @throws  Zend_Service_Rackspace_Files_Exception
+     * @return  Zend_Service_Rackspace_Files_Object
+     */
+    public function offsetGet($offset)
+    {
+        if ($this->offsetExists($offset)) {
+            return $this->objects[$offset];
+        } else {
+            require_once 'Zend/Service/Rackspace/Files/Exception.php';
+            throw new Zend_Service_Rackspace_Files_Exception('Illegal index');
+        }
+    }
+
+    /**
+     * Throws exception because all values are read-only
+     *
+     * Implement ArrayAccess::offsetSet()
+     *
+     * @param   int     $offset
+     * @param   string  $value
+     * @throws  Zend_Service_Rackspace_Files_Exception
+     */
+    public function offsetSet($offset, $value)
+    {
+        require_once 'Zend/Service/Rackspace/Files/Exception.php';
+        throw new Zend_Service_Rackspace_Files_Exception('You are trying to set read-only property');
+    }
+
+    /**
+     * Throws exception because all values are read-only
+     *
+     * Implement ArrayAccess::offsetUnset()
+     *
+     * @param   int     $offset
+     * @throws  Zend_Service_Rackspace_Files_Exception
+     */
+    public function offsetUnset($offset)
+    {
+        require_once 'Zend/Service/Rackspace/Files/Exception.php';
+        throw new Zend_Service_Rackspace_Files_Exception('You are trying to unset read-only property');
+    }
+}

+ 1281 - 0
library/Zend/Service/Rackspace/Servers.php

@@ -0,0 +1,1281 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service
+ * @subpackage Rackspace
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Service/Rackspace/Abstract.php';
+require_once 'Zend/Service/Rackspace/Servers/Server.php';
+require_once 'Zend/Service/Rackspace/Servers/ServerList.php';
+require_once 'Zend/Service/Rackspace/Servers/Image.php';
+require_once 'Zend/Service/Rackspace/Servers/ImageList.php';
+require_once 'Zend/Service/Rackspace/Servers/SharedIpGroup.php';
+require_once 'Zend/Service/Rackspace/Servers/SharedIpGroupList.php';
+require_once 'Zend/Validate/Ip.php';
+
+class Zend_Service_Rackspace_Servers extends Zend_Service_Rackspace_Abstract
+{
+    const LIMIT_FILE_SIZE           = 10240;
+    const LIMIT_NUM_FILE            = 5;
+    const ERROR_SERVICE_UNAVAILABLE = 'The service is unavailable';
+    const ERROR_UNAUTHORIZED        = 'Unauthorized';
+    const ERROR_OVERLIMIT           = 'You reached the limit of requests, please wait some time before retry';
+    const ERROR_PARAM_NO_ID         = 'You must specify the item\'s id';
+    const ERROR_PARAM_NO_NAME       = 'You must specify the name';
+    const ERROR_PARAM_NO_SERVERID   = 'You must specify the server Id';
+    const ERROR_PARAM_NO_IMAGEID    = 'You must specify the server\'s image ID';
+    const ERROR_PARAM_NO_FLAVORID   = 'You must specify the server\'s flavor ID';
+    const ERROR_PARAM_NO_ARRAY      = 'You must specify an array of parameters';
+    const ERROR_PARAM_NO_WEEKLY     = 'You must specify a weekly backup schedule';
+    const ERROR_PARAM_NO_DAILY      = 'You must specify a daily backup schedule';
+    const ERROR_ITEM_NOT_FOUND      = 'The item specified doesn\'t exist.';
+    const ERROR_NO_FILE_EXISTS      = 'The file specified doesn\'t exist';
+    const ERROR_LIMIT_FILE_SIZE     = 'You reached the size length of a file';
+    const ERROR_IN_PROGRESS         = 'The item specified is still in progress';
+    const ERROR_BUILD_IN_PROGRESS   = 'The build is still in progress';
+    const ERROR_RESIZE_NOT_ALLOWED  = 'The resize is not allowed';
+    /**
+     * Get the list of the servers
+     * If $details is true returns detail info
+     * 
+     * @param  boolean $details
+     * @return Zend_Service_Rackspace_Servers_ServerList|boolean
+     */
+    public function listServers($details=false)
+    {
+        $url= '/servers';
+        if ($details) {
+            $url.= '/detail';
+        } 
+        $result= $this->httpCall($this->getManagementUrl().$url,'GET');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '200' : 
+            case '203' : // break intentionally omitted   
+                $servers= json_decode($result->getBody(),true);
+                return new Zend_Service_Rackspace_Servers_ServerList($this,$servers['servers']);
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Get the specified server
+     * 
+     * @param  string $id 
+     * @return Zend_Service_Rackspace_Servers_Server
+     */
+    public function getServer($id) 
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_ID);
+        }
+        $result= $this->httpCall($this->getManagementUrl().'/servers/'.rawurlencode($id),'GET');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '200' : 
+            case '203' : // break intentionally omitted   
+                $server = json_decode($result->getBody(),true);
+                return new Zend_Service_Rackspace_Servers_Server($this,$server['server']);
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Create a new server
+     * 
+     * The required parameters are specified in $data (name, imageId, falvorId)
+     * The $files is an associative array with 'serverPath' => 'localPath'
+     * 
+     * @param  array $data 
+     * @param  array $metadata
+     * @param  array $files
+     * @return Zend_Service_Rackspace_Servers_Server|boolean
+     */
+    public function createServer(array $data, $metadata=array(),$files=array())
+    {
+        if (empty($data) || !is_array($data) || !is_array($metadata) || !is_array($files)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_ARRAY);
+        }
+        if (!isset($data['name'])) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME);
+        }
+        if (!isset($data['flavorId'])) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_FLAVORID);
+        }
+        if (!isset($data['imageId'])) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_IMAGEID);
+        }
+        if (count($files)>self::LIMIT_NUM_FILE) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You can attach '.self::LIMIT_NUM_FILE.' files maximum');
+        }
+        if (!empty($metadata)) {
+            $data['metadata']= $metadata;
+        }
+        $data['flavorId']= (integer) $data['flavorId'];
+        $data['imageId']= (integer) $data['imageId'];
+        if (!empty($files)) {
+            foreach ($files as $serverPath => $filePath) {
+                if (!file_exists($filePath)) {
+                    require_once 'Zend/Service/Rackspace/Exception.php';
+                    throw new Zend_Service_Rackspace_Exception(
+                            sprintf("The file %s doesn't exist",$filePath));
+                }
+                $content= file_get_contents($filePath);
+                if (strlen($content) > self::LIMIT_FILE_SIZE) {
+                    require_once 'Zend/Service/Rackspace/Exception.php';
+                    throw new Zend_Service_Rackspace_Exception(
+                            sprintf("The size of the file %s is greater than the max size of %d bytes",
+                                    $filePath,self::LIMIT_FILE_SIZE));
+                }
+                $data['personality'][] = array (
+                    'path'     => $serverPath,
+                    'contents' => base64_encode(file_get_contents($filePath))
+                );
+            }
+        }
+        $result = $this->httpCall($this->getManagementUrl().'/servers','POST',
+                null,null,json_encode(array ('server' => $data)));
+        $status = $result->getStatus();
+        switch ($status) {
+            case '200' :
+            case '202' : // break intentionally omitted   
+                $server = json_decode($result->getBody(),true);
+                return new Zend_Service_Rackspace_Servers_Server($this,$server['server']);
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Change the name or the admin password for a server
+     * 
+     * @param  string $id
+     * @param  string $name
+     * @param  string $password
+     * @return boolean 
+     */
+    protected function updateServer($id,$name=null,$password=null)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You must specify the ID of the server');
+        }
+        if (empty($name) && empty($password)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception("You must specify the new name or password of server");
+        }
+        $data= array();
+        if (!empty($name)) {
+            $data['name']= $name;
+        }
+        if (!empty($password)) {
+            $data['adminPass']= $password;
+        }
+        $result = $this->httpCall($this->getManagementUrl().'/servers/'.rawurlencode($id),'PUT',
+                null,null,json_encode(array('server' => $data)));
+        $status = $result->getStatus();
+        switch ($status) {
+            case '204' : // break intentionally omitted   
+                return true;
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '409' :
+                $this->errorMsg= self::ERROR_IN_PROGRESS;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Change the server's name
+     * 
+     * @param  string $id
+     * @param  string $name
+     * @return boolean 
+     */
+    public function changeServerName($id,$name)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You must specify the ID of the server');
+        }
+        if (empty($name)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception("You must specify the new name of the server");
+        }
+        return $this->updateServer($id, $name);
+    }
+    /**
+     * Change the admin password of the server
+     * 
+     * @param  string $id
+     * @param  string $password
+     * @return boolean 
+     */
+    public function changeServerPassword($id,$password)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You must specify the ID of the server');
+        }
+        if (empty($password)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception("You must specify the new password of the server");
+        }
+        return $this->updateServer($id, null,$password);
+    }
+    /**
+     * Delete a server
+     * 
+     * @param  string $id
+     * @return boolean 
+     */
+    public function deleteServer($id)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You must specify the ID of the server');
+        }
+        $result = $this->httpCall($this->getManagementUrl().'/servers/'.rawurlencode($id),'DELETE');
+        $status = $result->getStatus();
+        switch ($status) {
+            case '202' : // break intentionally omitted   
+                return true;
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '409' :
+                $this->errorMsg= self::ERROR_IN_PROGRESS;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Get the server's IPs (public and private)
+     * 
+     * @param  string $id
+     * @return array|boolean 
+     */
+    public function getServerIp($id)
+    {
+        $result= $this->getServer($id);
+        if ($result===false) {
+            return false;
+        }
+        $result= $result->toArray();
+        return $result['addresses'];
+    }
+    /**
+     * Get the Public IPs of a server
+     * 
+     * @param  string $id
+     * @return array|boolean
+     */
+    public function getServerPublicIp($id)
+    {
+        $addresses= $this->getServerIp($id);
+        if ($addresses===false) {
+            return false;
+        }
+        return $addresses['public'];
+    }
+    /**
+     * Get the Private IPs of a server
+     * 
+     * @param  string $id
+     * @return array|boolean
+     */
+    public function getServerPrivateIp($id)
+    {
+        $addresses= $this->getServerIp($id);
+        if ($addresses===false) {
+            return false;
+        }
+        return $addresses['private'];
+    }
+    /**
+     * Share an ip address for a server (id)
+     * 
+     * @param  string $id server
+     * @param  string $ip 
+     * @param  string $groupId
+     * @return boolean
+     */
+    public function shareIpAddress($id,$ip,$groupId,$configure=true)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You didn\'t specified the ID of the server');
+        }
+        if (empty($ip)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You didn\'t specified the IP address to share');
+        }
+        $validator = new Zend_Validate_Ip();
+        if (!$validator->isValid($ip)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception("The parameter $ip specified is not a valid IP address");
+        }
+        if (empty($groupId)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You didn\'t specified the group id to use');
+        }
+        $data= array (
+            'sharedIpGroupId' => (integer) $groupId,
+            'configureServer' => $configure
+        );
+        $result = $this->httpCall($this->getManagementUrl().'/servers/'.rawurlencode($id).'/ips/public/'.rawurlencode($ip),'PUT',
+                null,null,json_encode(array('shareIp' => $data)));
+        $status = $result->getStatus();
+        switch ($status) {
+            case '202' : // break intentionally omitted   
+                return true;
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Unshare IP address for a server ($id)
+     * 
+     * @param  string $id
+     * @param  string $ip
+     * @return boolean 
+     */
+    public function unshareIpAddress($id,$ip)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You didn\'t specified the ID of the server');
+        }
+        if (empty($ip)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You didn\'t specified the IP address to share');
+        }
+        $validator = new Zend_Validate_Ip();
+        if (!$validator->isValid($ip)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception("The parameter $ip specified is not a valid IP address");
+        }
+        $result = $this->httpCall($this->getManagementUrl().'/servers/'.rawurlencode($id).'/ips/public/'.rawurlencode($ip),
+                'DELETE');
+        $status = $result->getStatus();
+        switch ($status) {
+            case '202' : // break intentionally omitted   
+                return true;
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Reboot a server
+     * 
+     * $hard true is the equivalent of power cycling the server
+     * $hard false is a graceful shutdown
+     * 
+     * @param  string $id
+     * @param  boolean $hard 
+     * @return boolean
+     */
+    public function rebootServer($id,$hard=false)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You didn\'t specified the ID of the server');
+        }
+        if (!$hard) {
+            $type= 'SOFT';
+        } else {
+            $type= 'HARD';
+        }
+        $data= array (
+            'reboot' => array (
+                'type' => $type
+            )
+        );
+        $result = $this->httpCall($this->getManagementUrl().'/servers/'.rawurlencode($id).'/action',
+                                  'POST', null, null, json_encode($data));
+        $status = $result->getStatus();
+        switch ($status) {
+            case '200' :
+            case '202' : // break intentionally omitted   
+                return true;
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '409' :
+                $this->errorMsg= self::ERROR_BUILD_IN_PROGRESS;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Rebuild a server
+     * 
+     * The rebuild function removes all data on the server and replaces it with the specified image,
+     * serverId and IP addresses will remain the same.
+     * 
+     * @param  string $id
+     * @param  string $imageId
+     * @return boolean
+     */
+    public function rebuildServer($id,$imageId)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You didn\'t specified the ID of the server');
+        }
+        if (empty($imageId)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You didn\'t specified the new imageId of the server');
+        }
+        $data= array (
+            'rebuild' => array (
+                'imageId' => (integer) $imageId
+            )
+        );
+        $result = $this->httpCall($this->getManagementUrl().'/servers/'.rawurlencode($id).'/action',
+                                  'POST', null, null, json_encode($data));
+        $status = $result->getStatus();
+        switch ($status) {
+            case '202' : // break intentionally omitted   
+                return true;
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '409' :
+                $this->errorMsg= self::ERROR_BUILD_IN_PROGRESS;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Resize a server
+     * 
+     * The resize function converts an existing server to a different flavor, in essence, scaling the
+     * server up or down. The original server is saved for a period of time to allow rollback if there
+     * is a problem. All resizes should be tested and explicitly confirmed, at which time the original
+     * server is removed. All resizes are automatically confirmed after 24 hours if they are not
+     * explicitly confirmed or reverted.
+     * 
+     * @param  string $id
+     * @param  string $flavorId
+     * @return boolean
+     */
+    public function resizeServer($id,$flavorId)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You didn\'t specified the ID of the server');
+        }
+        if (empty($flavorId)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You didn\'t specified the new flavorId of the server');
+        }
+        $data= array (
+            'resize' => array (
+                'flavorId' => (integer) $flavorId
+            )
+        );
+        $result = $this->httpCall($this->getManagementUrl().'/servers/'.rawurlencode($id).'/action',
+                                  'POST', null, null, json_encode($data));
+        $status = $result->getStatus();
+        switch ($status) {
+            case '202' : // break intentionally omitted   
+                return true;
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '403' :
+                $this->errorMsg= self::ERROR_RESIZE_NOT_ALLOWED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '409' :
+                $this->errorMsg= self::ERROR_BUILD_IN_PROGRESS;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Confirm resize of a server
+     * 
+     * During a resize operation, the original server is saved for a period of time to allow roll
+     * back if there is a problem. Once the newly resized server is tested and has been confirmed
+     * to be functioning properly, use this operation to confirm the resize. After confirmation,
+     * the original server is removed and cannot be rolled back to. All resizes are automatically
+     * confirmed after 24 hours if they are not explicitly confirmed or reverted.
+     *
+     * @param  string $id
+     * @return boolean 
+     */
+    public function confirmResizeServer($id)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You didn\'t specified the ID of the server');
+        }
+        $data= array (
+            'confirmResize' => null
+        );
+        $result = $this->httpCall($this->getManagementUrl().'/servers/'.rawurlencode($id).'/action',
+                                  'POST', null, null, json_encode($data));
+        $status = $result->getStatus();
+        switch ($status) {
+            case '204' : // break intentionally omitted   
+                return true;
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '403' :
+                $this->errorMsg= self::ERROR_RESIZE_NOT_ALLOWED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '409' :
+                $this->errorMsg= self::ERROR_BUILD_IN_PROGRESS;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Revert resize of a server
+     * 
+     * During a resize operation, the original server is saved for a period of time to allow for roll
+     * back if there is a problem. If you determine there is a problem with a newly resized server,
+     * use this operation to revert the resize and roll back to the original server. All resizes are
+     * automatically confirmed after 24 hours if they have not already been confirmed explicitly or
+     * reverted.
+     *
+     * @param  string $id
+     * @return boolean 
+     */
+    public function revertResizeServer($id)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You didn\'t specified the ID of the server');
+        }
+        $data= array (
+            'revertResize' => null
+        );
+        $result = $this->httpCall($this->getManagementUrl().'/servers/'.rawurlencode($id).'/action',
+                                  'POST', null, null, json_encode($data));
+        $status = $result->getStatus();
+        switch ($status) {
+            case '202' : // break intentionally omitted   
+                return true;
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '403' :
+                $this->errorMsg= self::ERROR_RESIZE_NOT_ALLOWED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '409' :
+                $this->errorMsg= self::ERROR_BUILD_IN_PROGRESS;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Get the list of the flavors
+     * 
+     * If $details is true returns detail info
+     * 
+     * @param  boolean $details
+     * @return array|boolean
+     */
+    public function listFlavors($details=false)
+    {
+        $url= '/flavors';
+        if ($details) {
+            $url.= '/detail';
+        } 
+        $result= $this->httpCall($this->getManagementUrl().$url,'GET');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '200' : 
+            case '203' : // break intentionally omitted   
+                $flavors= json_decode($result->getBody(),true);
+                return $flavors['flavors'];
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Get the detail of a flavor
+     * 
+     * @param  string $flavorId
+     * @return array|boolean
+     */
+    public function getFlavor($flavorId)
+    {
+        if (empty($flavorId)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception('You didn\'t specified the new flavorId of the server');
+        }
+        $result= $this->httpCall($this->getManagementUrl().'/flavors/'.rawurlencode($flavorId),'GET');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '200' : 
+            case '203' : // break intentionally omitted   
+                $flavor= json_decode($result->getBody(),true);
+                return $flavor['flavor'];
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Get the list of the images
+     * 
+     * @param  boolean $details
+     * @return Zend_Service_Rackspace_Servers_ImageList|boolean 
+     */
+    public function listImages($details=false)
+    {
+        $url= '/images';
+        if ($details) {
+            $url.= '/detail';
+        } 
+        $result= $this->httpCall($this->getManagementUrl().$url,'GET');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '200' : 
+            case '203' : // break intentionally omitted   
+                $images= json_decode($result->getBody(),true);
+                return new Zend_Service_Rackspace_Servers_ImageList($this,$images['images']);
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Get detail about an image
+     * 
+     * @param  string $id
+     * @return Zend_Service_Rackspace_Servers_Image|boolean
+     */
+    public function getImage($id)
+    {
+        $result= $this->httpCall($this->getManagementUrl().'/images/'.rawurlencode($id),'GET');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '200' : 
+            case '203' : // break intentionally omitted   
+                $image= json_decode($result->getBody(),true);
+                return new Zend_Service_Rackspace_Servers_Image($this,$image['image']);
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                 $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Create an image for a serverId
+     * 
+     * @param  string $serverId
+     * @param  string $name 
+     * @return Zend_Service_Rackspace_Servers_Image
+     */
+    public function createImage($serverId,$name)
+    {
+        if (empty($serverId)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_SERVERID);
+        }
+        if (empty($name)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME);
+        }
+        $data = array(
+            'image' => array (
+                'serverId' => (integer) $serverId,
+                'name'     => $name
+            )
+        );
+        $result = $this->httpCall($this->getManagementUrl().'/images', 'POST',
+                                  null, null, json_encode($data));
+        $status = $result->getStatus();
+        switch ($status) {
+            case '202' : // break intentionally omitted   
+                $image= json_decode($result->getBody(),true);
+                return new Zend_Service_Rackspace_Servers_Image($this,$image['image']);
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '403' :
+                $this->errorMsg= self::ERROR_RESIZE_NOT_ALLOWED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '409' :
+                $this->errorMsg= self::ERROR_BUILD_IN_PROGRESS;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Delete an image
+     * 
+     * @param  string $id
+     * @return boolean 
+     */
+    public function deleteImage($id)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_ID);
+        }
+        $result = $this->httpCall($this->getManagementUrl().'/images/'.rawurlencode($id),'DELETE');
+        $status = $result->getStatus();
+        switch ($status) {
+            case '204' : // break intentionally omitted   
+                return true;
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Get the backup schedule of a server
+     * 
+     * @param  string $id server's Id
+     * @return array|boolean 
+     */
+    public function getBackupSchedule($id)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_ID);
+        }
+        $result= $this->httpCall($this->getManagementUrl().'/servers/'.rawurlencode($id).'/backup_schedule',
+                                 'GET');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '200' : 
+            case '203' : // break intentionally omitted   
+                $backup = json_decode($result->getBody(),true);
+                return $image['backupSchedule'];
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Change the backup schedule of a server
+     * 
+     * @param  string $id server's Id
+     * @param  string $weekly
+     * @param  string $daily
+     * @return boolean 
+     */
+    public function changeBackupSchedule($id,$weekly,$daily)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_ID);
+        }
+        if (empty($weekly)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_WEEKLY);
+        }
+        if (empty($daily)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_DAILY);
+        }
+        $data = array (
+            'backupSchedule' => array (
+                'enabled' => true,
+                'weekly'  => $weekly,
+                'daily'   => $daily
+            )
+        );
+        $result= $this->httpCall($this->getManagementUrl().'/servers/'.rawurlencode($id).'/backup_schedule',
+                                 'POST',null,null,json_encode($data));
+        $status= $result->getStatus();
+        switch ($status) {
+            case '204' : // break intentionally omitted   
+                return true;
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '409' :
+                $this->errorMsg= self::ERROR_BUILD_IN_PROGRESS;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Disable the backup schedule for a server
+     * 
+     * @param  string $id server's Id
+     * @return boolean
+     */
+    public function disableBackupSchedule($id)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_ID);
+        }
+        $result = $this->httpCall($this->getManagementUrl().'/servers/'.rawurlencode($id).'/backup_schedule',
+                                  'DELETE');
+        $status = $result->getStatus();
+        switch ($status) {
+            case '204' : // break intentionally omitted   
+                return true;
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '409' :
+                $this->errorMsg= self::ERROR_BUILD_IN_PROGRESS;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Get the list of shared IP groups
+     * 
+     * @param  boolean $details
+     * @return Zend_Service_Rackspace_Servers_SharedIpGroupList|boolean 
+     */
+    public function listSharedIpGroups($details=false)
+    {
+        $url= '/shared_ip_groups';
+        if ($details) {
+            $url.= '/detail';
+        } 
+        $result= $this->httpCall($this->getManagementUrl().$url,'GET');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '200' : 
+            case '203' : // break intentionally omitted   
+                $groups= json_decode($result->getBody(),true);
+                return new Zend_Service_Rackspace_Servers_SharedIpGroupList($this,$groups['sharedIpGroups']);
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Get the shared IP group
+     * 
+     * @param  integer $id
+     * @return Zend_Service_Rackspace_Servers_SharedIpGroup|boolean 
+     */
+    public function getSharedIpGroup($id)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_ID);
+        }
+        $result= $this->httpCall($this->getManagementUrl().'/shared_ip_groups/'.rawurlencode($id),'GET');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '200' : 
+            case '203' : // break intentionally omitted   
+                $group= json_decode($result->getBody(),true);
+                return new Zend_Service_Rackspace_Servers_SharedIpGroup($this,$group['sharedIpGroup']);
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Create a shared Ip group
+     * 
+     * @param  string $name
+     * @param  string $serverId
+     * @return array|boolean 
+     */
+    public function createSharedIpGroup($name,$serverId)
+    {
+        if (empty($name)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_NAME);
+        }
+        if (empty($serverId)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_ID);
+        }
+        $data = array (
+            'sharedIpGroup' => array (
+                'name'   => $name,
+                'server' => (integer) $serverId
+            )
+        );
+        $result= $this->httpCall($this->getManagementUrl().'/shared_ip_groups',
+                                 'POST',null,null,json_encode($data));
+        $status= $result->getStatus();
+        switch ($status) {
+            case '201' : // break intentionally omitted   
+                $group = json_decode($result->getBody(),true);
+                return new Zend_Service_Rackspace_Servers_SharedIpGroup($this,$group['sharedIpGroup']);
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+    /**
+     * Delete a Shared Ip Group
+     * 
+     * @param  integer $id 
+     * @return boolean
+     */
+    public function deleteSharedIpGroup($id)
+    {
+        if (empty($id)) {
+            require_once 'Zend/Service/Rackspace/Exception.php';
+            throw new Zend_Service_Rackspace_Exception(self::ERROR_PARAM_NO_ID);
+        }
+        $result= $this->httpCall($this->getManagementUrl().'/shared_ip_groups/'.rawurlencode($id),'DELETE');
+        $status= $result->getStatus();
+        switch ($status) {
+            case '204' : // break intentionally omitted   
+                return true;
+            case '503' :
+                $this->errorMsg= self::ERROR_SERVICE_UNAVAILABLE;
+                break;
+            case '401' :
+                $this->errorMsg= self::ERROR_UNAUTHORIZED;
+                break;
+            case '404' :
+                $this->errorMsg= self::ERROR_ITEM_NOT_FOUND;
+                break;
+            case '413' :
+                $this->errorMsg= self::ERROR_OVERLIMIT;
+                break;
+            default:
+                $this->errorMsg= $result->getBody();
+                break;
+        }
+        $this->errorCode= $status;
+        return false;
+    }
+}

+ 209 - 0
library/Zend/Service/Rackspace/Servers/Image.php

@@ -0,0 +1,209 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Servers
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Service/Rackspace/Servers.php';
+
+class Zend_Service_Rackspace_Servers_Image
+{
+    const ERROR_PARAM_CONSTRUCT = 'You must pass a Zend_Service_Rackspace_Servers object and an array';
+    const ERROR_PARAM_NO_NAME   = 'You must pass the image\'s name in the array (name)';
+    const ERROR_PARAM_NO_ID     = 'You must pass the image\'s id in the array (id)';
+    /**
+     * Name of the image
+     * 
+     * @var string 
+     */
+    protected $name;
+    /**
+     * Id of the image
+     * 
+     * @var string 
+     */
+    protected $id;
+    /**
+     * Server Id of the image
+     * 
+     * @var string 
+     */
+    protected $serverId;
+    /**
+     * Updated data
+     * 
+     * @var string 
+     */
+    protected $updated;
+    /**
+     * Created data
+     * 
+     * @var string 
+     */
+    protected $created;
+    /**
+     * Status
+     * 
+     * @var string 
+     */
+    protected $status;
+    /**
+     * Status progress
+     * 
+     * @var integer 
+     */
+    protected $progress;
+    /**
+     * The service that has created the image object
+     *
+     * @var Zend_Service_Rackspace_Servers
+     */
+    protected $service;
+    /**
+     * Construct
+     * 
+     * @param array $data
+     * @return void
+     */
+    public function __construct($service, $data)
+    {
+        if (!($service instanceof Zend_Service_Rackspace_Servers) || !is_array($data)) {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception(self::ERROR_PARAM_CONSTRUCT);
+        }
+        if (!array_key_exists('name', $data)) {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception(self::ERROR_PARAM_NO_NAME);
+        }
+        if (!array_key_exists('id', $data)) {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception(self::ERROR_PARAM_NO_ID);
+        }
+        $this->service= $service;
+        $this->name = $data['name'];
+        $this->id = $data['id'];
+        if (isset($data['serverId'])) {
+            $this->serverId= $data['serverId'];
+        }
+        if (isset($data['updated'])) {
+            $this->updated= $data['updated'];
+        }
+        if (isset($data['created'])) {
+            $this->created= $data['created'];
+        }
+        if (isset($data['status'])) {
+            $this->status= $data['status'];
+        }
+        if (isset($data['progress'])) {
+            $this->progress= $data['progress'];
+        }
+    }
+    /**
+     * Get the name of the image
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+    /**
+     * Get the image's id
+     * 
+     * @return string 
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+    /**
+     * Get the server's id of the image
+     * 
+     * @return string 
+     */
+    public function getServerId()
+    {
+        return $this->serverId;
+    }
+    /**
+     * Get the updated data
+     * 
+     * @return string 
+     */
+    public function getUpdated()
+    {
+        return $this->updated;
+    }
+    /**
+     * Get the created data
+     * 
+     * @return string 
+     */
+    public function getCreated()
+    {
+        return $this->created;
+    }
+    /**
+     * Get the image's status
+     * 
+     * @return string|boolean
+     */
+    public function getStatus()
+    {
+        $data= $this->service->getImage($this->id);
+        if ($data!==false) {
+            $data= $data->toArray();
+            $this->status= $data['status'];
+            return $this->status;
+        }
+        return false;
+    }
+    /**
+     * Get the progress's status
+     * 
+     * @return integer|boolean
+     */
+    public function getProgress()
+    {
+        $data= $this->service->getImage($this->id);
+        if ($data!==false) {
+            $data= $data->toArray();
+            $this->progress= $data['progress'];
+            return $this->progress;
+        }
+        return false;
+    }
+    /**
+     * To Array
+     * 
+     * @return array 
+     */
+    public function toArray()
+    {
+        return array (
+            'name'     => $this->name,
+            'id'       => $this->id,
+            'serverId' => $this->serverId,
+            'updated'  => $this->updated,
+            'created'  => $this->created,
+            'status'   => $this->status,
+            'progress' => $this->progress
+        );
+    }
+}

+ 234 - 0
library/Zend/Service/Rackspace/Servers/ImageList.php

@@ -0,0 +1,234 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Servers
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Service/Rackspace/Servers.php';
+require_once 'Zend/Service/Rackspace/Servers/Image.php';
+
+/**
+ * List of images of Rackspace
+ *
+ * @uses       ArrayAccess
+ * @uses       Countable
+ * @uses       Iterator
+ * @uses       Zend_Service_Rackspace_Servers
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Servers
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_Rackspace_Servers_ImageList implements Countable, Iterator, ArrayAccess
+{
+    /**
+     * @var array of Zend_Service_Rackspace_Servers_Image
+     */
+    protected $images = array();
+    /**
+     * @var int Iterator key
+     */
+    protected $iteratorKey = 0;
+    /**
+     * @var Zend_Service_Rackspace_Servers
+     */
+    protected $service;
+    /**
+     * Construct
+     *
+     * @param  RackspaceServers $service
+     * @param  array $list
+     * @return void
+     */
+    public function __construct($service,$list = array())
+    {
+        if (!($service instanceof Zend_Service_Rackspace_Servers) || !is_array($list)) {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception("You must pass a Zend_Service_Rackspace_Servers object and an array");
+        }
+        $this->service= $service;
+        $this->constructFromArray($list);
+    }
+    /**
+     * Transforms the array to array of Server
+     *
+     * @param  array $list
+     * @return void
+     */
+    private function constructFromArray(array $list)
+    {
+        foreach ($list as $image) {
+            $this->addImage(new Zend_Service_Rackspace_Servers_Image($this->service,$image));
+        }
+    }
+    /**
+     * Add an image
+     *
+     * @param  Zend_Service_Rackspace_Servers_Image $image
+     * @return Zend_Service_Rackspace_Servers_ImageList
+     */
+    protected function addImage (Zend_Service_Rackspace_Servers_Image $image)
+    {
+        $this->images[] = $image;
+        return $this;
+    }
+    /**
+     * To Array
+     * 
+     * @return array 
+     */
+    public function toArray()
+    {
+        $array= array();
+        foreach ($this->images as $image) {
+            $array[]= $image->toArray();
+        }
+        return $array;
+    }
+    /**
+     * Return number of images
+     *
+     * Implement Countable::count()
+     *
+     * @return int
+     */
+    public function count()
+    {
+        return count($this->images);
+    }
+    /**
+     * Return the current element
+     *
+     * Implement Iterator::current()
+     *
+     * @return Zend_Service_Rackspace_Servers_Image
+     */
+    public function current()
+    {
+        return $this->images[$this->iteratorKey];
+    }
+    /**
+     * Return the key of the current element
+     *
+     * Implement Iterator::key()
+     *
+     * @return int
+     */
+    public function key()
+    {
+        return $this->iteratorKey;
+    }
+    /**
+     * Move forward to next element
+     *
+     * Implement Iterator::next()
+     *
+     * @return void
+     */
+    public function next()
+    {
+        $this->iteratorKey += 1;
+    }
+    /**
+     * Rewind the Iterator to the first element
+     *
+     * Implement Iterator::rewind()
+     *
+     * @return void
+     */
+    public function rewind()
+    {
+        $this->iteratorKey = 0;
+    }
+    /**
+     * Check if there is a current element after calls to rewind() or next()
+     *
+     * Implement Iterator::valid()
+     *
+     * @return bool
+     */
+    public function valid()
+    {
+        $numItems = $this->count();
+        if ($numItems > 0 && $this->iteratorKey < $numItems) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+    /**
+     * Whether the offset exists
+     *
+     * Implement ArrayAccess::offsetExists()
+     *
+     * @param   int     $offset
+     * @return  bool
+     */
+    public function offsetExists($offset)
+    {
+        return ($offset < $this->count());
+    }
+    /**
+     * Return value at given offset
+     *
+     * Implement ArrayAccess::offsetGet()
+     *
+     * @param   int     $offset
+     * @throws  Zend_Service_Rackspace_Servers_Exception
+     * @return  Zend_Service_Rackspace_Servers_Image
+     */
+    public function offsetGet($offset)
+    {
+        if ($this->offsetExists($offset)) {
+            return $this->images[$offset];
+        } else {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception('Illegal index');
+        }
+    }
+
+    /**
+     * Throws exception because all values are read-only
+     *
+     * Implement ArrayAccess::offsetSet()
+     *
+     * @param   int     $offset
+     * @param   string  $value
+     * @throws  Zend_Service_Rackspace_Servers_Exception
+     */
+    public function offsetSet($offset, $value)
+    {
+        require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+        throw new Zend_Service_Rackspace_Servers_Exception('You are trying to set read-only property');
+    }
+
+    /**
+     * Throws exception because all values are read-only
+     *
+     * Implement ArrayAccess::offsetUnset()
+     *
+     * @param   int     $offset
+     * @throws  Zend_Service_Rackspace_Servers_Exception
+     */
+    public function offsetUnset($offset)
+    {
+        require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+        throw new Zend_Service_Rackspace_Servers_Exception('You are trying to unset read-only property');
+    }
+}

+ 325 - 0
library/Zend/Service/Rackspace/Servers/Server.php

@@ -0,0 +1,325 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Servers
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Service/Rackspace/Servers.php';
+
+class Zend_Service_Rackspace_Servers_Server
+{
+    const ERROR_PARAM_CONSTRUCT = 'You must pass a Zend_Service_Rackspace_Servers object and an array';
+    const ERROR_PARAM_NO_NAME   = 'You must pass the server\'s name in the array (name)';
+    const ERROR_PARAM_NO_ID     = 'You must pass the server\'s id in the array (id)';
+    /**
+     * Server's name
+     * 
+     * @var string
+     */
+    protected $name;
+    /**
+     * Server's id
+     *
+     * @var string
+     */
+    protected $id;
+    /**
+     * Image id of the server
+     *
+     * @var string
+     */
+    protected $imageId;
+    /**
+     * Flavor id of the server
+     * 
+     * @var string 
+     */
+    protected $flavorId;
+    /**
+     * Host id
+     * 
+     * @var string
+     */
+    protected $hostId;
+    /**
+     * Server's status
+     * 
+     * @var string 
+     */
+    protected $status;
+    /**
+     * Progress of the status
+     * 
+     * @var integer
+     */
+    protected $progress;
+    /**
+     * Admin password, generated on a new server
+     * 
+     * @var string 
+     */
+    protected $adminPass;
+    /**
+     * Public and private IP addresses
+     * 
+     * @var array 
+     */
+    protected $addresses = array();
+    /**
+     * @var array
+     */
+    protected $metadata = array();
+    /**
+     * The service that has created the server object
+     *
+     * @var Zend_Service_Rackspace_Servers
+     */
+    protected $service;
+    /**
+     * Constructor
+     *
+     * @param  Zend_Service_Rackspace_Servers $service
+     * @param  array $data
+     * @return void
+     */
+    public function __construct($service, $data)
+    {
+        if (!($service instanceof Zend_Service_Rackspace_Servers) || !is_array($data)) {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception(self::ERROR_PARAM_CONSTRUCT);
+        }
+        if (!array_key_exists('name', $data)) {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception(self::ERROR_PARAM_NO_NAME);
+        }
+        if (!array_key_exists('id', $data)) {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception(self::ERROR_PARAM_NO_ID);
+        }
+        $this->service = $service;
+        $this->name = $data['name'];
+        $this->id = $data['id'];
+        if (isset($data['imageId'])) {
+            $this->imageId= $data['imageId'];
+        }
+        if (isset($data['flavorId'])) {
+            $this->flavorId= $data['flavorId'];
+        }
+        if (isset($data['hostId'])) {
+            $this->hostId= $data['hostId'];
+        }
+        if (isset($data['status'])) {
+            $this->status= $data['status'];
+        }
+        if (isset($data['progress'])) {
+            $this->progress= $data['progress'];
+        }
+        if (isset($data['adminPass'])) {
+            $this->adminPass= $data['adminPass'];
+        }
+        if (isset($data['addresses']) && is_array($data['addresses'])) {
+            $this->addresses= $data['addresses'];
+        }
+        if (isset($data['metadata']) && is_array($data['metadata'])) {
+            $this->metadata= $data['metadata'];
+        } 
+    }
+    /**
+     * Get the name of the server
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+    /**
+     * Get the server's id
+     * 
+     * @return string 
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+    /**
+     * Get the server's image Id
+     * 
+     * @return string 
+     */
+    public function getImageId()
+    {
+        return $this->imageId;
+    }
+    /**
+     * Get the server's flavor Id
+     * 
+     * @return string 
+     */
+    public function getFlavorId()
+    {
+        return $this->flavorId;
+    }
+    /**
+     * Get the server's host Id
+     * 
+     * @return string 
+     */
+    public function getHostId()
+    {
+        return $this->hostId;
+    }
+    /**
+     * Ge the server's admin password
+     * 
+     * @return string 
+     */
+    public function getAdminPass()
+    {
+        return $this->adminPass;
+    }
+    /**
+     * Get the server's status
+     * 
+     * @return string|boolean
+     */
+    public function getStatus()
+    {
+        $data= $this->service->getServer($this->id);
+        if ($data!==false) {
+            $data= $data->toArray();
+            $this->status= $data['status'];
+            return $this->status;
+        }
+        return false;
+    }
+    /**
+     * Get the progress's status
+     * 
+     * @return integer|boolean
+     */
+    public function getProgress()
+    {
+        $data= $this->service->getServer($this->id);
+        if ($data!==false) {
+            $data= $data->toArray();
+            $this->progress= $data['progress'];
+            return $this->progress;
+        }
+        return false;
+    }
+    /**
+     * Get the private IPs
+     * 
+     * @return array|boolean
+     */
+    public function getPrivateIp()
+    {
+        if (isset($this->addresses['private'])) {
+            return $this->addresses['private'];
+        }
+        return false;
+    }
+    /**
+     * Get the public IPs
+     * 
+     * @return array|boolean
+     */
+    public function getPublicIp()
+    {
+        if (isset($this->addresses['public'])) {
+            return $this->addresses['public'];
+        }
+        return false;
+    }
+    /**
+     * Get the metadata of the container
+     *
+     * If $key is empty return the array of metadata
+     *
+     * @param string $key
+     * @return array|string
+     */
+    public function getMetadata($key=null)
+    {
+        if (!empty($key) && isset($this->metadata[$key])) {
+            return $this->metadata[$key];
+        }
+        return $this->metadata;
+    }
+    /**
+     * Change the name of the server
+     * 
+     * @param string $name
+     * @return boolean 
+     */
+    public function changeName($name) 
+    {
+        $result= $this->service->changeServerName($this->id, $name);
+        if ($result!==false) {
+            $this->name= $name;
+            return true;
+        }
+        return false;
+    }
+    /**
+     * Change the admin password of the server
+     * 
+     * @param string $password
+     * @return boolean 
+     */
+    public function changePassword($password)
+    {
+        $result=  $this->service->changeServerPassword($this->id, $password);
+        if ($result!==false) {
+            $this->adminPass= $password;
+            return true;
+        }
+        return false;
+    }
+    /**
+     * Reboot the server
+     * 
+     * @return boolean 
+     */
+    public function reboot($hard=false)
+    {
+        return $this->service->rebootServer($this->id,$hard);
+    }
+    /**
+     * To Array
+     * 
+     * @return array 
+     */
+    public function toArray()
+    {
+        return array (
+            'name'      => $this->name,
+            'id'        => $this->id,
+            'imageId'   => $this->imageId,
+            'flavorId'  => $this->flavorId,
+            'hostId'    => $this->hostId,
+            'status'    => $this->status,
+            'progress'  => $this->progress,
+            'adminPass' => $this->adminPass,
+            'addresses' => $this->addresses,
+            'metadata'  => $this->metadata
+        );
+    }
+}

+ 235 - 0
library/Zend/Service/Rackspace/Servers/ServerList.php

@@ -0,0 +1,235 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Servers
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Service/Rackspace/Servers.php';
+require_once 'Zend/Service/Rackspace/Servers/Server.php';
+
+/**
+ * List of servers of Rackspace
+ *
+ * @uses       ArrayAccess
+ * @uses       Countable
+ * @uses       Iterator
+ * @uses       OutOfBoundsException
+ * @uses       Zend_Service_Rackspace_Servers
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Servers
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_Rackspace_Servers_ServerList implements Countable, Iterator, ArrayAccess
+{
+    /**
+     * @var array of Zend_Service_Rackspace_Servers_Server
+     */
+    protected $servers = array();
+    /**
+     * @var int Iterator key
+     */
+    protected $iteratorKey = 0;
+    /**
+     * @var Zend_Service_Rackspace_Servers
+     */
+    protected $service;
+    /**
+     * Construct
+     *
+     * @param  Zend_Service_Rackspace_Servers $service
+     * @param  array $list
+     * @return void
+     */
+    public function __construct($service,$list = array())
+    {
+        if (!($service instanceof Zend_Service_Rackspace_Servers) || !is_array($list)) {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception("You must pass a Zend_Service_Rackspace_Servers object and an array");
+        }
+        $this->service= $service;
+        $this->constructFromArray($list);
+    }
+    /**
+     * Transforms the array to array of Server
+     *
+     * @param  array $list
+     * @return void
+     */
+    private function constructFromArray(array $list)
+    {
+        foreach ($list as $server) {
+            $this->addServer(new Zend_Service_Rackspace_Servers_Server($this->service,$server));
+        }
+    }
+    /**
+     * Add a server
+     *
+     * @param  Zend_Service_Rackspace_Servers_Server $server
+     * @return Zend_Service_Rackspace_Servers_ServerList
+     */
+    protected function addServer (Zend_Service_Rackspace_Servers_Server $server)
+    {
+        $this->servers[] = $server;
+        return $this;
+    }
+    /**
+     * To Array
+     * 
+     * @return array 
+     */
+    public function toArray()
+    {
+        $array= array();
+        foreach ($this->servers as $server) {
+            $array[]= $server->toArray();
+        }
+        return $array;
+    }
+    /**
+     * Return number of servers
+     *
+     * Implement Countable::count()
+     *
+     * @return int
+     */
+    public function count()
+    {
+        return count($this->servers);
+    }
+    /**
+     * Return the current element
+     *
+     * Implement Iterator::current()
+     *
+     * @return Zend_Service_Rackspace_Servers_Server
+     */
+    public function current()
+    {
+        return $this->servers[$this->iteratorKey];
+    }
+    /**
+     * Return the key of the current element
+     *
+     * Implement Iterator::key()
+     *
+     * @return int
+     */
+    public function key()
+    {
+        return $this->iteratorKey;
+    }
+    /**
+     * Move forward to next element
+     *
+     * Implement Iterator::next()
+     *
+     * @return void
+     */
+    public function next()
+    {
+        $this->iteratorKey += 1;
+    }
+    /**
+     * Rewind the Iterator to the first element
+     *
+     * Implement Iterator::rewind()
+     *
+     * @return void
+     */
+    public function rewind()
+    {
+        $this->iteratorKey = 0;
+    }
+    /**
+     * Check if there is a current element after calls to rewind() or next()
+     *
+     * Implement Iterator::valid()
+     *
+     * @return bool
+     */
+    public function valid()
+    {
+        $numItems = $this->count();
+        if ($numItems > 0 && $this->iteratorKey < $numItems) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+    /**
+     * Whether the offset exists
+     *
+     * Implement ArrayAccess::offsetExists()
+     *
+     * @param   int     $offset
+     * @return  bool
+     */
+    public function offsetExists($offset)
+    {
+        return ($offset < $this->count());
+    }
+    /**
+     * Return value at given offset
+     *
+     * Implement ArrayAccess::offsetGet()
+     *
+     * @param   int     $offset
+     * @throws  Zend_Service_Rackspace_Servers_Exception
+     * @return  Zend_Service_Rackspace_Servers_Server
+     */
+    public function offsetGet($offset)
+    {
+        if ($this->offsetExists($offset)) {
+            return $this->servers[$offset];
+        } else {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception('Illegal index');
+        }
+    }
+
+    /**
+     * Throws exception because all values are read-only
+     *
+     * Implement ArrayAccess::offsetSet()
+     *
+     * @param   int     $offset
+     * @param   string  $value
+     * @throws  Zend_Service_Rackspace_Servers_Exception
+     */
+    public function offsetSet($offset, $value)
+    {
+        require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+        throw new Zend_Service_Rackspace_Servers_Exception('You are trying to set read-only property');
+    }
+
+    /**
+     * Throws exception because all values are read-only
+     *
+     * Implement ArrayAccess::offsetUnset()
+     *
+     * @param   int     $offset
+     * @throws  Zend_Service_Rackspace_Servers_Exception
+     */
+    public function offsetUnset($offset)
+    {
+        require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+        throw new Zend_Service_Rackspace_Servers_Exception('You are trying to unset read-only property');
+    }
+}

+ 165 - 0
library/Zend/Service/Rackspace/Servers/SharedIpGroup.php

@@ -0,0 +1,165 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Servers
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Service/Rackspace/Servers.php';
+
+class Zend_Service_Rackspace_Servers_SharedIpGroup
+{
+    const ERROR_PARAM_CONSTRUCT  = 'You must pass a Zend_Service_Rackspace_Servers object and an array';
+    const ERROR_PARAM_NO_NAME    = 'You must pass the image\'s name in the array (name)';
+    const ERROR_PARAM_NO_ID      = 'You must pass the image\'s id in the array (id)';
+    const ERROR_PARAM_NO_SERVERS = 'The servers parameter must be an array of Ids';
+    /**
+     * Name of the shared IP group
+     * 
+     * @var string 
+     */
+    protected $name;
+    /**
+     * Id of the shared IP group
+     * 
+     * @var string 
+     */
+    protected $id;
+    /**
+     * Array of servers of the shared IP group
+     * 
+     * @var array 
+     */
+    protected $serversId = array();
+    /**
+     * The service that has created the image object
+     *
+     * @var Zend_Service_Rackspace_Servers
+     */
+    protected $service;
+    /**
+     * Construct
+     * 
+     * @param  Zend_Service_Rackspace_Servers $service
+     * @param  array $data
+     * @return void
+     */
+    public function __construct($service, $data)
+    {
+        if (!($service instanceof Zend_Service_Rackspace_Servers) || !is_array($data)) {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception(self::ERROR_PARAM_CONSTRUCT);
+        }
+        if (!array_key_exists('name', $data)) {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception(self::ERROR_PARAM_NO_NAME);
+        }
+        if (!array_key_exists('id', $data)) {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception(self::ERROR_PARAM_NO_ID);
+        }
+        if (isset($data['servers']) && !is_array($data['servers'])) {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception(self::ERROR_PARAM_NO_SERVERS);
+        } 
+        $this->service= $service;
+        $this->name = $data['name'];
+        $this->id = $data['id'];
+        if (isset($data['servers'])) {
+            $this->serversId= $data['servers'];
+        }    
+    }
+    /**
+     * Get the name of the shared IP group
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+    /**
+     * Get the id of the shared IP group
+     * 
+     * @return string 
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+    /**
+     * Get the server's array of the shared IP group
+     * 
+     * @return string 
+     */
+    public function getServersId()
+    {
+        if (empty($this->serversId)) {
+            $info= $this->service->getSharedIpGroup($this->id);
+            if (($info!==false)) {
+                $info= $info->toArray();
+                if (isset($info['servers'])) {
+                    $this->serversId= $info['servers'];
+                }
+            }    
+        }
+        return $this->serversId;
+    }
+    /**
+     * Get the server 
+     * 
+     * @param integer $id
+     * @return Zend_Service_Rackspace_Servers_Server|boolean
+     */
+    public function getServer($id)
+    {
+        if (empty($this->serversId)) {
+            $this->getServersId();
+        }
+        if (in_array($id,$this->serversId)) {
+            return $this->service->getServer($id);
+        }
+        return false;
+    }
+    /**
+     * Create a server in the shared Ip Group
+     * 
+     * @param  array $data
+     * @param  array $metadata
+     * @param  array $files 
+     * @return Zend_Service_Rackspace_Servers_Server|boolean
+     */
+    public function createServer(array $data, $metadata=array(),$files=array()) 
+    {
+        $data['sharedIpGroupId']= (integer) $this->id;
+        return $this->service->createServer($data,$metadata,$files);
+    }
+    /**
+     * To Array
+     * 
+     * @return array 
+     */
+    public function toArray()
+    {
+        return array (
+            'name'    => $this->name,
+            'id'      => $this->id,
+            'servers' => $this->serversId
+        );
+    }
+}

+ 234 - 0
library/Zend/Service/Rackspace/Servers/SharedIpGroupList.php

@@ -0,0 +1,234 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Servers
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Service/Rackspace/Servers.php';
+require_once 'Zend/Service/Rackspace/Servers/SharedIpGroup.php';
+
+/**
+ * List of shared Ip group of Rackspace
+ *
+ * @uses       ArrayAccess
+ * @uses       Countable
+ * @uses       Iterator
+ * @uses       Zend_Service_Rackspace_Servers
+ * @category   Zend
+ * @package    Zend_Service_Rackspace
+ * @subpackage Servers
+ * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_Rackspace_Servers_SharedIpGroupList implements Countable, Iterator, ArrayAccess
+{
+    /**
+     * @var array of Zend_Service_Rackspace_Servers_SharedIpGroup
+     */
+    protected $shared = array();
+    /**
+     * @var int Iterator key
+     */
+    protected $iteratorKey = 0;
+    /**
+     * @var Zend_Service_Rackspace_Servers
+     */
+    protected $service;
+    /**
+     * Construct
+     *
+     * @param  Zend_Service_Rackspace_Servers $service
+     * @param  array $list
+     * @return void
+     */
+    public function __construct($service,$list = array())
+    {
+        if (!($service instanceof Zend_Service_Rackspace_Servers) || !is_array($list)) {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception("You must pass a Zend_Service_Rackspace_Servers object and an array");
+        }
+        $this->service= $service;
+        $this->constructFromArray($list);
+    }
+    /**
+     * Transforms the array to array of Shared Ip Group
+     *
+     * @param  array $list
+     * @return void
+     */
+    private function constructFromArray(array $list)
+    {
+        foreach ($list as $share) {
+            $this->addSharedIpGroup(new Zend_Service_Rackspace_Servers_SharedIpGroup($this->service,$share));
+        }
+    }
+    /**
+     * Add a shared Ip group
+     *
+     * @param  Zend_Service_Rackspace_Servers_SharedIpGroup $shared
+     * @return Zend_Service_Rackspace_Servers_SharedIpGroupList
+     */
+    protected function addSharedIpGroup (Zend_Service_Rackspace_Servers_SharedIpGroup $share)
+    {
+        $this->shared[] = $share;
+        return $this;
+    }
+    /**
+     * To Array
+     * 
+     * @return array 
+     */
+    public function toArray()
+    {
+        $array= array();
+        foreach ($this->shared as $share) {
+            $array[]= $share->toArray();
+        }
+        return $array;
+    }
+    /**
+     * Return number of shared Ip Groups
+     *
+     * Implement Countable::count()
+     *
+     * @return int
+     */
+    public function count()
+    {
+        return count($this->shared);
+    }
+    /**
+     * Return the current element
+     *
+     * Implement Iterator::current()
+     *
+     * @return Zend_Service_Rackspace_Servers_SharedIpGroup
+     */
+    public function current()
+    {
+        return $this->shared[$this->iteratorKey];
+    }
+    /**
+     * Return the key of the current element
+     *
+     * Implement Iterator::key()
+     *
+     * @return int
+     */
+    public function key()
+    {
+        return $this->iteratorKey;
+    }
+    /**
+     * Move forward to next element
+     *
+     * Implement Iterator::next()
+     *
+     * @return void
+     */
+    public function next()
+    {
+        $this->iteratorKey += 1;
+    }
+    /**
+     * Rewind the Iterator to the first element
+     *
+     * Implement Iterator::rewind()
+     *
+     * @return void
+     */
+    public function rewind()
+    {
+        $this->iteratorKey = 0;
+    }
+    /**
+     * Check if there is a current element after calls to rewind() or next()
+     *
+     * Implement Iterator::valid()
+     *
+     * @return boolean
+     */
+    public function valid()
+    {
+        $numItems = $this->count();
+        if ($numItems > 0 && $this->iteratorKey < $numItems) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+    /**
+     * Whether the offset exists
+     *
+     * Implement ArrayAccess::offsetExists()
+     *
+     * @param   int     $offset
+     * @return  boolean
+     */
+    public function offsetExists($offset)
+    {
+        return ($offset < $this->count());
+    }
+    /**
+     * Return value at given offset
+     *
+     * Implement ArrayAccess::offsetGet()
+     *
+     * @param   int  $offset
+     * @throws  Zend_Service_Rackspace_Servers_Exception
+     * @return  Zend_Service_Rackspace_Servers_SharedIpGroup
+     */
+    public function offsetGet($offset)
+    {
+        if ($this->offsetExists($offset)) {
+            return $this->shared[$offset];
+        } else {
+            require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+            throw new Zend_Service_Rackspace_Servers_Exception('Illegal index');
+        }
+    }
+
+    /**
+     * Throws exception because all values are read-only
+     *
+     * Implement ArrayAccess::offsetSet()
+     *
+     * @param   int     $offset
+     * @param   string  $value
+     * @throws  Zend_Service_Rackspace_Servers_Exception
+     */
+    public function offsetSet($offset, $value)
+    {
+        require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+        throw new Zend_Service_Rackspace_Servers_Exception('You are trying to set read-only property');
+    }
+
+    /**
+     * Throws exception because all values are read-only
+     *
+     * Implement ArrayAccess::offsetUnset()
+     *
+     * @param  int $offset
+     * @throws Zend_Service_Rackspace_Servers_Exception
+     */
+    public function offsetUnset($offset)
+    {
+        require_once 'Zend/Service/Rackspace/Servers/Exception.php';
+        throw new Zend_Service_Rackspace_Servers_Exception('You are trying to unset read-only property');
+    }
+}