forked from wbobeirne/Phlickr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Request.php
364 lines (337 loc) · 10.4 KB
/
Request.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
<?php
/**
* @version $Id$
* @author Andrew Morton <[email protected]>
* @license http://opensource.org/licenses/lgpl-license.php
* GNU Lesser General Public License, Version 2.1
* @package Phlickr
*/
/**
* Phlickr_Api includes the core classes.
*/
require_once dirname(__FILE__) . '/Api.php';
/**
* The Phlickr_Request executes a Flickr API method and returns a
* Phlickr_Response object with the results.
*
* Sample usage:
* <code>
* <?php
* include_once '/Api.php';
* $api = new Phlickr_Api(FLICKR_API_KEY, FLICKR_API_SECRET, FLICKR_TOKEN);
*
* // create a request to search for photos tagged with person and happy
* // from all users.
* $request = $api->createRequest(
* 'flickr.photos.search',
* array(
* 'tags' => 'person,happy',
* 'tag_mode' => 'all',
* 'user_id' => ''
* )
* );
*
* // use the photo list and photo list iterator to display the titles and urls
* // of each of the photos.
* $photolist = new Phlickr_PhotoList($request);
* $iterator = new Phlickr_PhotoListIterator($photolist);
* foreach ($iterator as $photos) {
* foreach ($photos as $photo) {
* print "Photo: {$photo->getTitle()}\n";
* print "\t{$photo->buildImgUrl()}\n";
* }
* }
* ?>
* </code>
*
* This class is responsible for:
* - Assembling the information needed to build a REST URL.
* - Submitting an HTTP POST request.
* - Creating a Phlickr_Response from the results of an HTTP request.
* - Providing callers with the details of the HTTP request for debugging
* purposes.
*
* @package Phlickr
* @author Andrew Morton <[email protected]>
* @since 0.1.0
*/
class Phlickr_Request {
/**
* Number of seconds to wait while connecting to the server.
*/
const TIMEOUT_CONNECTION = 30;
/**
* Total number of seconds to wait for a request.
*/
const TIMEOUT_TOTAL = 120;
/**
* Phlickr_API object
*
* @var object
*/
private $_api = null;
/**
* Name of the method.
*
* @var string
*/
private $_method = null;
/**
* Parameters used in the last request.
*
* @var array
*/
private $_params = array();
/**
* Should an exception be thrown when an API call fails?
*
* @var boolean
*/
private $_throwOnFail = true;
/**
* Constructor.
*
* See the {@link http://flickr.com/services/api/ Flickr API} for a complete
* list of methods and parameters.
*
* @param object Phlickr_API $api
* @param string $method The name of the method.
* @param array $params Associative array of parameter name/value pairs.
*/
public function __construct(Phlickr_Api $api, $method, $params = array())
{
$this->_api = $api;
$this->_method = (string) $method;
if (!is_null($params)) {
$this->_params = $params;
}
}
public function __toString()
{
return $this->buildUrl();
}
/**
* Submit a POST request with to the specified URL with given parameters.
*
* @param string $url
* @param array $params An optional array of parameter name/value
* pairs to include in the POST.
* @param integer $timeout The total number of seconds, including the
* wait for the initial connection, wait for a request to complete.
* @return string
* @throws Phlickr_ConnectionException
* @uses TIMEOUT_CONNECTION to determine how long to wait for a
* for a connection.
* @uses TIMEOUT_TOTAL to determine how long to wait for a request
* to complete.
* @uses set_time_limit() to ensure that PHP's script timer is five
* seconds longer than the sum of $timeout and TIMEOUT_CONNECTION.
*/
static function submitHttpPost($url, $postParams = null, $timeout = self::TIMEOUT_TOTAL)
{
$ch = curl_init();
// set up the request
curl_setopt($ch, CURLOPT_URL, $url);
// make sure we submit this as a post
curl_setopt($ch, CURLOPT_POST, true);
if (isset($postParams)) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $postParams);
}else{
curl_setopt($ch, CURLOPT_POSTFIELDS, "");
}
// make sure problems are caught
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
// return the output
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// set the timeouts
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::TIMEOUT_CONNECTION);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
$min_time = self::TIMEOUT_CONNECTION + $timeout + 5;
$max_execution_time = ini_get('max_execution_time');
// Adjust time limit only if it's too low.
if ($max_execution_time > 0 && $max_execution_time < $min_time) {
// set the PHP script's timeout to be greater than CURL's
set_time_limit($min_time);
}
// remove the Expect: 100-continue header
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
$result = curl_exec($ch);
// check for errors
if (0 == curl_errno($ch)) {
curl_close($ch);
return $result;
}
else {
$ex = new Phlickr_ConnectionException(
'Request failed. ' . curl_error($ch), curl_errno($ch), $url);
curl_close($ch);
throw $ex;
}
}
/**
* Create a signed signature of the parameters.
*
* Return a parameter string that can be tacked onto the end of a URL.
* Items will be sorted and an api_sig element will be on the end.
*
* @param string $secret
* @param array $params
* @return string
* @since 0.2.3
* @link http://flickr.com/services/api/auth.spec.html
*/
static function signParams($secret, $params)
{
$signing = '';
$values = array();
ksort($params);
foreach($params as $key => $value) {
$signing .= $key . $value;
$values[] = $key . '=' . urlencode($value);
}
$values[] = 'api_sig=' . md5($secret . $signing);
return implode('&', $values);
}
static function signPost($secret, $params)
{
$signing = '';
$values = array();
ksort($params);
foreach($params as $key => $value) {
$signing .= $key . $value;
}
return array('api_sig' => md5($secret . $signing));
}
/**
* Return a reference to this Request's Phlickr_Api.
*
* @return object Phlickr_Api
* @see __construct()
*/
public function getApi()
{
return $this->_api;
}
/**
* Return the name of the method
*
* @return string
* @see __construct()
*/
public function getMethod()
{
return $this->_method;
}
/**
* Return the array of parameters.
*
* @return array
* @see setParams()
*/
public function &getParams()
{
return $this->_params;
}
/**
* Assign parameters to the request.
*
* @param array $params Associative array of parameter name/value pairs
* @return void
* @see __construct, getParams()
*/
public function setParams($params)
{
if (is_null($params)) {
$this->_params = array();
} else {
$this->_params = $params;
}
}
/**
* Return true if an exception will be thrown if the API returns a fail
* for the request.
*
* @return boolean
* @see setExceptionThrownOnFailure()
*/
public function isExceptionThrownOnFailure()
{
return $this->_throwOnFail;
}
/**
* Set an exception will be thrown if the API returns a fail for the
* request.
*
* @param boolean $throwOnFail
* @return void
* @see isExceptionThrownOnFailure()
*/
public function setExceptionThrownOnFailure($throwOnFail)
{
$this->_throwOnFail = (boolean) $throwOnFail;
}
/**
* Build a signed URL for this Request.
*
* The Api will provide the key and secret and token values.
*
* @return string
* @link http://flickr.com/services/api/auth.spec.html
* @see buildUrl, Phlickr_Api::getKey(), Phlickr_Api::getSecret()
* @uses signParams() to create a signed URL.
*/
public function buildUrl($isPost = false)
{
$api = $this->getApi();
// merge the api's parameters with the user's. the order of array_merge
// parameters is designed so that user values will overwrite api values
// if there are duplicates.
$params = array_merge(
$api->getParamsForRequest(),
$this->getParams()
);
$params['method'] = $this->getMethod();
if ($isPost) {
$params = array_merge($params, $this->signPost($api->getSecret(), $params));
$this->setParams($params);
return $api->getEndpointUrl();
}
else {
return $api->getEndpointUrl() . '?'
. self::signParams($api->getSecret(), $params);
}
}
/**
* Execute a Flickr API method.
*
* All requests are cached but cached data is only used when the caller
* specifically allows it. This allows the unittests to load a cache full
* of expected responses and avoid a network connection.
*
* @param boolean $allowCached If a cached result exists, should it be returned?
* @return object Flicrk_Response
* @throws Phlickr_XmlParseException, Phlickr_ConnectionException
* @uses submitHttpPost() to submit the request.
* @uses Phlickr_Cache to load and cached requests.
* @uses Phlickr_Response to return results.
*/
public function execute($allowCached = false, $isPost = false)
{
$url = $this->buildUrl($isPost);
$cache =& $this->getApi()->getCache();
if ($allowCached && $cache->has($url)) {
$result = $cache->get($url);
} else {
if ($isPost) {
$params = $this->getParams();
$result = self::submitHttpPost($url, $params);
}
else {
$result = self::submitHttpPost($url);
}
$cache->set($url, $result);
}
return new Phlickr_Response($result, $this->_throwOnFail);
}
}