|
1 <?php |
|
2 /** |
|
3 * Zend Framework |
|
4 * |
|
5 * LICENSE |
|
6 * |
|
7 * This source file is subject to the new BSD license that is bundled |
|
8 * with this package in the file LICENSE.txt. |
|
9 * It is also available through the world-wide-web at this URL: |
|
10 * http://framework.zend.com/license/new-bsd |
|
11 * If you did not receive a copy of the license and are unable to |
|
12 * obtain it through the world-wide-web, please send an email |
|
13 * to license@zend.com so we can send you a copy immediately. |
|
14 * |
|
15 * @category Zend |
|
16 * @package Zend_Service_Amazon |
|
17 * @subpackage Ec2 |
|
18 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
19 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
20 * @version $Id: Abstract.php 20096 2010-01-06 02:05:09Z bkarwin $ |
|
21 */ |
|
22 |
|
23 /** |
|
24 * @see Zend_Service_Amazon_Abstract |
|
25 */ |
|
26 require_once 'Zend/Service/Amazon/Abstract.php'; |
|
27 |
|
28 /** |
|
29 * @see Zend_Service_Amazon_Ec2_Response |
|
30 */ |
|
31 require_once 'Zend/Service/Amazon/Ec2/Response.php'; |
|
32 |
|
33 /** |
|
34 * @see Zend_Service_Amazon_Ec2_Exception |
|
35 */ |
|
36 require_once 'Zend/Service/Amazon/Ec2/Exception.php'; |
|
37 |
|
38 /** |
|
39 * Provides the basic functionality to send a request to the Amazon Ec2 Query API |
|
40 * |
|
41 * @category Zend |
|
42 * @package Zend_Service_Amazon |
|
43 * @subpackage Ec2 |
|
44 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
45 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
46 */ |
|
47 abstract class Zend_Service_Amazon_Ec2_Abstract extends Zend_Service_Amazon_Abstract |
|
48 { |
|
49 /** |
|
50 * The HTTP query server |
|
51 */ |
|
52 protected $_ec2Endpoint = 'ec2.amazonaws.com'; |
|
53 |
|
54 /** |
|
55 * The API version to use |
|
56 */ |
|
57 protected $_ec2ApiVersion = '2009-04-04'; |
|
58 |
|
59 /** |
|
60 * Signature Version |
|
61 */ |
|
62 protected $_ec2SignatureVersion = '2'; |
|
63 |
|
64 /** |
|
65 * Signature Encoding Method |
|
66 */ |
|
67 protected $_ec2SignatureMethod = 'HmacSHA256'; |
|
68 |
|
69 /** |
|
70 * Period after which HTTP request will timeout in seconds |
|
71 */ |
|
72 protected $_httpTimeout = 10; |
|
73 |
|
74 /** |
|
75 * @var string Amazon Region |
|
76 */ |
|
77 protected static $_defaultRegion = null; |
|
78 |
|
79 /** |
|
80 * @var string Amazon Region |
|
81 */ |
|
82 protected $_region; |
|
83 |
|
84 /** |
|
85 * An array that contains all the valid Amazon Ec2 Regions. |
|
86 * |
|
87 * @var array |
|
88 */ |
|
89 protected static $_validEc2Regions = array('eu-west-1', 'us-east-1'); |
|
90 |
|
91 /** |
|
92 * Create Amazon client. |
|
93 * |
|
94 * @param string $access_key Override the default Access Key |
|
95 * @param string $secret_key Override the default Secret Key |
|
96 * @param string $region Sets the AWS Region |
|
97 * @return void |
|
98 */ |
|
99 public function __construct($accessKey=null, $secretKey=null, $region=null) |
|
100 { |
|
101 if(!$region) { |
|
102 $region = self::$_defaultRegion; |
|
103 } else { |
|
104 // make rue the region is valid |
|
105 if(!empty($region) && !in_array(strtolower($region), self::$_validEc2Regions, true)) { |
|
106 require_once 'Zend/Service/Amazon/Exception.php'; |
|
107 throw new Zend_Service_Amazon_Exception('Invalid Amazon Ec2 Region'); |
|
108 } |
|
109 } |
|
110 |
|
111 $this->_region = $region; |
|
112 |
|
113 parent::__construct($accessKey, $secretKey); |
|
114 } |
|
115 |
|
116 /** |
|
117 * Set which region you are working in. It will append the |
|
118 * end point automaticly |
|
119 * |
|
120 * @param string $region |
|
121 */ |
|
122 public static function setRegion($region) |
|
123 { |
|
124 if(in_array(strtolower($region), self::$_validEc2Regions, true)) { |
|
125 self::$_defaultRegion = $region; |
|
126 } else { |
|
127 require_once 'Zend/Service/Amazon/Exception.php'; |
|
128 throw new Zend_Service_Amazon_Exception('Invalid Amazon Ec2 Region'); |
|
129 } |
|
130 } |
|
131 |
|
132 /** |
|
133 * Method to fetch the AWS Region |
|
134 * |
|
135 * @return string |
|
136 */ |
|
137 protected function _getRegion() |
|
138 { |
|
139 return (!empty($this->_region)) ? $this->_region . '.' : ''; |
|
140 } |
|
141 |
|
142 /** |
|
143 * Sends a HTTP request to the queue service using Zend_Http_Client |
|
144 * |
|
145 * @param array $params List of parameters to send with the request |
|
146 * @return Zend_Service_Amazon_Ec2_Response |
|
147 * @throws Zend_Service_Amazon_Ec2_Exception |
|
148 */ |
|
149 protected function sendRequest(array $params = array()) |
|
150 { |
|
151 $url = 'https://' . $this->_getRegion() . $this->_ec2Endpoint . '/'; |
|
152 |
|
153 $params = $this->addRequiredParameters($params); |
|
154 |
|
155 try { |
|
156 /* @var $request Zend_Http_Client */ |
|
157 $request = self::getHttpClient(); |
|
158 $request->resetParameters(); |
|
159 |
|
160 $request->setConfig(array( |
|
161 'timeout' => $this->_httpTimeout |
|
162 )); |
|
163 |
|
164 $request->setUri($url); |
|
165 $request->setMethod(Zend_Http_Client::POST); |
|
166 $request->setParameterPost($params); |
|
167 |
|
168 $httpResponse = $request->request(); |
|
169 |
|
170 |
|
171 } catch (Zend_Http_Client_Exception $zhce) { |
|
172 $message = 'Error in request to AWS service: ' . $zhce->getMessage(); |
|
173 throw new Zend_Service_Amazon_Ec2_Exception($message, $zhce->getCode(), $zhce); |
|
174 } |
|
175 $response = new Zend_Service_Amazon_Ec2_Response($httpResponse); |
|
176 $this->checkForErrors($response); |
|
177 |
|
178 return $response; |
|
179 } |
|
180 |
|
181 /** |
|
182 * Adds required authentication and version parameters to an array of |
|
183 * parameters |
|
184 * |
|
185 * The required parameters are: |
|
186 * - AWSAccessKey |
|
187 * - SignatureVersion |
|
188 * - Timestamp |
|
189 * - Version and |
|
190 * - Signature |
|
191 * |
|
192 * If a required parameter is already set in the <tt>$parameters</tt> array, |
|
193 * it is overwritten. |
|
194 * |
|
195 * @param array $parameters the array to which to add the required |
|
196 * parameters. |
|
197 * |
|
198 * @return array |
|
199 */ |
|
200 protected function addRequiredParameters(array $parameters) |
|
201 { |
|
202 $parameters['AWSAccessKeyId'] = $this->_getAccessKey(); |
|
203 $parameters['SignatureVersion'] = $this->_ec2SignatureVersion; |
|
204 $parameters['Timestamp'] = gmdate('Y-m-d\TH:i:s\Z'); |
|
205 $parameters['Version'] = $this->_ec2ApiVersion; |
|
206 $parameters['SignatureMethod'] = $this->_ec2SignatureMethod; |
|
207 $parameters['Signature'] = $this->signParameters($parameters); |
|
208 |
|
209 return $parameters; |
|
210 } |
|
211 |
|
212 /** |
|
213 * Computes the RFC 2104-compliant HMAC signature for request parameters |
|
214 * |
|
215 * This implements the Amazon Web Services signature, as per the following |
|
216 * specification: |
|
217 * |
|
218 * 1. Sort all request parameters (including <tt>SignatureVersion</tt> and |
|
219 * excluding <tt>Signature</tt>, the value of which is being created), |
|
220 * ignoring case. |
|
221 * |
|
222 * 2. Iterate over the sorted list and append the parameter name (in its |
|
223 * original case) and then its value. Do not URL-encode the parameter |
|
224 * values before constructing this string. Do not use any separator |
|
225 * characters when appending strings. |
|
226 * |
|
227 * @param array $parameters the parameters for which to get the signature. |
|
228 * @param string $secretKey the secret key to use to sign the parameters. |
|
229 * |
|
230 * @return string the signed data. |
|
231 */ |
|
232 protected function signParameters(array $paramaters) |
|
233 { |
|
234 $data = "POST\n"; |
|
235 $data .= $this->_getRegion() . $this->_ec2Endpoint . "\n"; |
|
236 $data .= "/\n"; |
|
237 |
|
238 uksort($paramaters, 'strcmp'); |
|
239 unset($paramaters['Signature']); |
|
240 |
|
241 $arrData = array(); |
|
242 foreach($paramaters as $key => $value) { |
|
243 $arrData[] = $key . '=' . str_replace("%7E", "~", rawurlencode($value)); |
|
244 } |
|
245 |
|
246 $data .= implode('&', $arrData); |
|
247 |
|
248 require_once 'Zend/Crypt/Hmac.php'; |
|
249 $hmac = Zend_Crypt_Hmac::compute($this->_getSecretKey(), 'SHA256', $data, Zend_Crypt_Hmac::BINARY); |
|
250 |
|
251 return base64_encode($hmac); |
|
252 } |
|
253 |
|
254 /** |
|
255 * Checks for errors responses from Amazon |
|
256 * |
|
257 * @param Zend_Service_Amazon_Ec2_Response $response the response object to |
|
258 * check. |
|
259 * |
|
260 * @return void |
|
261 * |
|
262 * @throws Zend_Service_Amazon_Ec2_Exception if one or more errors are |
|
263 * returned from Amazon. |
|
264 */ |
|
265 private function checkForErrors(Zend_Service_Amazon_Ec2_Response $response) |
|
266 { |
|
267 $xpath = new DOMXPath($response->getDocument()); |
|
268 $list = $xpath->query('//Error'); |
|
269 if ($list->length > 0) { |
|
270 $node = $list->item(0); |
|
271 $code = $xpath->evaluate('string(Code/text())', $node); |
|
272 $message = $xpath->evaluate('string(Message/text())', $node); |
|
273 throw new Zend_Service_Amazon_Ec2_Exception($message, 0, $code); |
|
274 } |
|
275 |
|
276 } |
|
277 } |