PluginProbe
UpdraftPlus: WP Backup & Migration Plugin / 1.16.5
UpdraftPlus: WP Backup & Migration Plugin v1.16.5
1.26.7 1.26.6 1.26.5 1.26.4 1.26.3 1.9.19 1.9.25 1.9.26 1.9.30 1.9.31 1.9.32 1.9.4 1.9.40 1.9.41 1.9.42 1.9.43 1.9.44 1.9.45 1.9.46 1.9.5 1.9.50 1.9.51 1.9.60 1.9.62 1.9.63 All 371 releases
updraftplus / includes / cloudfiles / cloudfiles_http.php

cloudfiles_http.php in UpdraftPlus: WP Backup & Migration Plugin 1.16.5, at includes/cloudfiles/cloudfiles_http.php

1,583 lines 54.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This is an HTTP client class for Cloud Files. It uses PHP's cURL module
4 * to handle the actual HTTP request/response. This is NOT a generic HTTP
5 * client class and is only used to abstract out the HTTP communication for
6 * the PHP Cloud Files API.
7 *
8 * This module was designed to re-use existing HTTP(S) connections between
9 * subsequent operations. For example, performing multiple PUT operations
10 * will re-use the same connection.
11 *
12 * This modules also provides support for streaming content into and out
13 * of Cloud Files. The majority (all?) of the PHP HTTP client modules expect
14 * to read the server's response into a string variable. This will not work
15 * with large files without killing your server. Methods like,
16 * get_object_to_stream() and put_object() take an open filehandle
17 * argument for streaming data out of or into Cloud Files.
18 *
19 * Requres PHP 5.x (for Exceptions and OO syntax)
20 *
21 * See COPYING for license information.
22 *
23 * @author Eric "EJ" Johnson <ej@racklabs.com>
24 * @copyright Copyright (c) 2008, Rackspace US, Inc.
25 * @package php-cloudfiles-http
26 */
27
28 /**
29 */
30 require_once("cloudfiles_exceptions.php");
31
32 @define("PHP_CF_VERSION", "1.7.11");
33 @define("USER_AGENT", sprintf("PHP-CloudFiles/%s", PHP_CF_VERSION));
34 @define("MAX_HEADER_NAME_LEN", 128);
35 @define("MAX_HEADER_VALUE_LEN", 256);
36 @define("ACCOUNT_CONTAINER_COUNT", "X-Account-Container-Count");
37 @define("ACCOUNT_BYTES_USED", "X-Account-Bytes-Used");
38 @define("ACCOUNT_KEY", "X-Account-Meta-Key");
39 @define("ACCOUNT_METADATA_HEADER_PREFIX", "X-Account-Meta-");
40 @define("CONTAINER_OBJ_COUNT", "X-Container-Object-Count");
41 @define("CONTAINER_BYTES_USED", "X-Container-Bytes-Used");
42 @define("CONTAINER_METADATA_HEADER_PREFIX", "X-Container-Meta-");
43 @define("DELETE_AFTER", "X-Delete-After");
44 @define("DELETE_AT", "X-Delete-At");
45 @define("MANIFEST_HEADER", "X-Object-Manifest");
46 @define("METADATA_HEADER_PREFIX", "X-Object-Meta-");
47 @define("CONTENT_HEADER_PREFIX", "Content-");
48 @define("ACCESS_CONTROL_HEADER_PREFIX", "Access-Control-");
49 @define("ORIGIN_HEADER", "Origin");
50 @define("CDN_URI", "X-CDN-URI");
51 @define("CDN_SSL_URI", "X-CDN-SSL-URI");
52 @define("CDN_STREAMING_URI", "X-CDN-Streaming-URI");
53 @define("CDN_ENABLED", "X-CDN-Enabled");
54 @define("CDN_LOG_RETENTION", "X-Log-Retention");
55 @define("CDN_ACL_USER_AGENT", "X-User-Agent-ACL");
56 @define("CDN_ACL_REFERRER", "X-Referrer-ACL");
57 @define("CDN_TTL", "X-TTL");
58 @define("CDNM_URL", "X-CDN-Management-Url");
59 @define("STORAGE_URL", "X-Storage-Url");
60 @define("AUTH_TOKEN", "X-Auth-Token");
61 @define("AUTH_USER_HEADER", "X-Auth-User");
62 @define("AUTH_KEY_HEADER", "X-Auth-Key");
63 @define("AUTH_USER_HEADER_LEGACY", "X-Storage-User");
64 @define("AUTH_KEY_HEADER_LEGACY", "X-Storage-Pass");
65 @define("AUTH_TOKEN_LEGACY", "X-Storage-Token");
66 @define("CDN_EMAIL", "X-Purge-Email");
67 @define("DESTINATION", "Destination");
68 @define("ETAG_HEADER", "ETag");
69 @define("LAST_MODIFIED_HEADER", "Last-Modified");
70 @define("CONTENT_TYPE_HEADER", "Content-Type");
71 @define("CONTENT_LENGTH_HEADER", "Content-Length");
72 @define("USER_AGENT_HEADER", "User-Agent");
73
74 /**
75 * HTTP/cURL wrapper for Cloud Files
76 *
77 * This class should not be used directly. It's only purpose is to abstract
78 * out the HTTP communication from the main API.
79 *
80 * @package php-cloudfiles-http
81 */
82 class UpdraftPlus_CF_Http
83 {
84 private $error_str;
85 private $dbug;
86 private $cabundle_path;
87 private $api_version;
88 # Authentication instance variables
89 #
90 private $storage_url;
91 private $cdnm_url;
92 private $auth_token;
93
94 # Request/response variables
95 #
96 private $response_status;
97 private $response_reason;
98 private $connections;
99
100 # Variables used for content/header callbacks
101 #
102 private $_user_read_progress_callback_func;
103 private $_user_write_progress_callback_func;
104 private $_write_callback_type;
105 private $_text_list;
106 private $_account_metadata;
107 private $_account_container_count;
108 private $_account_bytes_used;
109 private $_account_key;
110 private $_container_metadata;
111 private $_container_object_count;
112 private $_container_bytes_used;
113 private $_obj_delete_after;
114 private $_obj_delete_at;
115 private $_obj_etag;
116 private $_obj_last_modified;
117 private $_obj_content_type;
118 private $_obj_content_length;
119 private $_obj_metadata;
120 private $_obj_headers;
121 private $_obj_manifest;
122 private $_obj_write_resource;
123 private $_obj_write_string;
124 private $_cdn_enabled;
125 private $_cdn_ssl_uri;
126 private $_cdn_streaming_uri;
127 private $_cdn_uri;
128 private $_cdn_ttl;
129 private $_cdn_log_retention;
130 private $_cdn_acl_user_agent;
131 private $_cdn_acl_referrer;
132
133 function __construct($api_version)
134 {
135 $this->dbug = False;
136 $this->cabundle_path = NULL;
137 $this->api_version = $api_version;
138 $this->error_str = NULL;
139
140 $this->storage_url = NULL;
141 $this->cdnm_url = NULL;
142 $this->auth_token = NULL;
143
144 $this->response_status = NULL;
145 $this->response_reason = NULL;
146
147 # Curl connections array - since there is no way to "re-set" the
148 # connection paramaters for a cURL handle, we keep an array of
149 # the unique use-cases and funnel all of those same type
150 # requests through the appropriate curl connection.
151 #
152 $this->connections = array(
153 "GET_CALL" => NULL, # GET objects/containers/lists
154 "PUT_OBJ" => NULL, # PUT object
155 "HEAD" => NULL, # HEAD requests
156 "PUT_CONT" => NULL, # PUT container
157 "DEL_POST" => NULL, # DELETE containers/objects, POST objects
158 "COPY" => null, # COPY objects
159 );
160
161 $this->_user_read_progress_callback_func = NULL;
162 $this->_user_write_progress_callback_func = NULL;
163 $this->_write_callback_type = NULL;
164 $this->_text_list = array();
165 $this->_return_list = NULL;
166 $this->_account_metadata = array();
167 $this->_account_key = NULL;
168 $this->_account_container_count = 0;
169 $this->_account_bytes_used = 0;
170 $this->_container_metadata = array();
171 $this->_container_object_count = 0;
172 $this->_container_bytes_used = 0;
173 $this->_obj_delete_after = NULL;
174 $this->_obj_delete_at = NULL;
175 $this->_obj_write_resource = NULL;
176 $this->_obj_write_string = "";
177 $this->_obj_etag = NULL;
178 $this->_obj_last_modified = NULL;
179 $this->_obj_content_type = NULL;
180 $this->_obj_content_length = NULL;
181 $this->_obj_metadata = array();
182 $this->_obj_manifest = NULL;
183 $this->_obj_headers = NULL;
184 $this->_cdn_enabled = NULL;
185 $this->_cdn_ssl_uri = NULL;
186 $this->_cdn_streaming_uri = NULL;
187 $this->_cdn_uri = NULL;
188 $this->_cdn_ttl = NULL;
189 $this->_cdn_log_retention = NULL;
190 $this->_cdn_acl_user_agent = NULL;
191 $this->_cdn_acl_referrer = NULL;
192
193 # The OS list with a PHP without an updated CA File for CURL to
194 # connect to SSL Websites. It is the first 3 letters of the PHP_OS
195 # variable.
196 $OS_CAFILE_NONUPDATED=array(
197 "win","dar"
198 );
199
200 // We don't want this happening automatically - since the UpdraftPlus default is to use our own certificate already
201 // if (in_array((strtolower (substr(PHP_OS, 0,3))), $OS_CAFILE_NONUPDATED))
202 // $this->ssl_use_cabundle();
203
204 }
205
206 function ssl_use_cabundle($path=NULL)
207 {
208 if ($path) {
209 $this->cabundle_path = $path;
210 } else {
211 $this->cabundle_path = UPDRAFTPLUS_DIR.'/includes/cacert.pem';
212 }
213 if (!file_exists($this->cabundle_path)) {
214 throw new IOException("Could not use CA bundle: "
215 . $this->cabundle_path);
216 }
217 return;
218 }
219
220 # Uses separate cURL connection to authenticate
221 #
222 function authenticate($user, $pass, $acct=NULL, $host=NULL)
223 {
224 $path = array();
225 if (isset($acct)){
226 $headers = array(
227 sprintf("%s: %s", AUTH_USER_HEADER_LEGACY, $user),
228 sprintf("%s: %s", AUTH_KEY_HEADER_LEGACY, $pass),
229 );
230 $path[] = $host;
231 $path[] = rawurlencode(sprintf("v%d",$this->api_version));
232 $path[] = rawurlencode($acct);
233 } else {
234 $headers = array(
235 sprintf("%s: %s", AUTH_USER_HEADER, $user),
236 sprintf("%s: %s", AUTH_KEY_HEADER, $pass),
237 );
238 $path[] = $host;
239 }
240 $path[] = "v1.0";
241 $url = implode("/", $path);
242
243 $curl_ch = curl_init();
244 if (!is_null($this->cabundle_path)) {
245 curl_setopt($curl_ch, CURLOPT_CAINFO, $this->cabundle_path);
246 }
247 if (defined('UPDRAFTPLUS_SSL_DISABLEVERIFY')) {
248 curl_setopt($curl_ch, CURLOPT_SSL_VERIFYPEER, UPDRAFTPLUS_SSL_DISABLEVERIFY);
249 } elseif (UpdraftPlus_Options::get_updraft_option('updraft_ssl_disableverify')) {
250 curl_setopt($curl_ch, CURLOPT_SSL_VERIFYPEER, false);
251 } else {
252 curl_setopt($curl_ch, CURLOPT_SSL_VERIFYPEER, true);
253 }
254
255 curl_setopt($curl_ch, CURLOPT_VERBOSE, $this->dbug);
256 curl_setopt($curl_ch, CURLOPT_FOLLOWLOCATION, 1);
257 curl_setopt($curl_ch, CURLOPT_MAXREDIRS, 4);
258 curl_setopt($curl_ch, CURLOPT_HEADER, 0);
259 curl_setopt($curl_ch, CURLOPT_HTTPHEADER, $headers);
260 curl_setopt($curl_ch, CURLOPT_USERAGENT, USER_AGENT);
261 curl_setopt($curl_ch, CURLOPT_RETURNTRANSFER, TRUE);
262 curl_setopt($curl_ch, CURLOPT_HEADERFUNCTION,array(&$this,'_auth_hdr_cb'));
263 curl_setopt($curl_ch, CURLOPT_CONNECTTIMEOUT, 10);
264 curl_setopt($curl_ch, CURLOPT_URL, $url);
265 curl_exec($curl_ch);
266 curl_close($curl_ch);
267
268 return array($this->response_status, $this->response_reason,
269 $this->storage_url, $this->cdnm_url, $this->auth_token);
270 }
271
272 # (CDN) GET /v1/Account
273 #
274 function list_cdn_containers($enabled_only)
275 {
276 $conn_type = "GET_CALL";
277 $url_path = $this->_make_path("CDN");
278
279 $this->_write_callback_type = "TEXT_LIST";
280 if ($enabled_only)
281 {
282 $return_code = $this->_send_request($conn_type, $url_path .
283 '/?enabled_only=true');
284 }
285 else
286 {
287 $return_code = $this->_send_request($conn_type, $url_path);
288 }
289 if (!$return_code) {
290 $this->error_str .= ": Failed to obtain valid HTTP response.";
291 return array(0,$this->error_str,array());
292 }
293 if ($return_code == 401) {
294 return array($return_code,"Unauthorized",array());
295 }
296 if ($return_code == 404) {
297 return array($return_code,"Account not found.",array());
298 }
299 if ($return_code == 204) {
300 return array($return_code,"Account has no CDN enabled Containers.",
301 array());
302 }
303 if ($return_code == 200) {
304 $this->create_array();
305 return array($return_code,$this->response_reason,$this->_text_list);
306 }
307 $this->error_str = "Unexpected HTTP response: ".$this->response_reason;
308 return array($return_code,$this->error_str,array());
309 }
310
311 # (CDN) DELETE /v1/Account/Container or /v1/Account/Container/Object
312 #
313 function purge_from_cdn($path, $email=null)
314 {
315 if(!$path)
316 throw new SyntaxException("Path not set");
317 $url_path = $this->_make_path("CDN", NULL, $path);
318 if($email)
319 {
320 $hdrs = array(CDN_EMAIL => $email);
321 $return_code = $this->_send_request("DEL_POST",$url_path,$hdrs,"DELETE");
322 }
323 else
324 $return_code = $this->_send_request("DEL_POST",$url_path,null,"DELETE");
325 return $return_code;
326 }
327
328 # (CDN) POST /v1/Account/Container
329 function update_cdn_container($container_name, $ttl=86400, $cdn_log_retention=False,
330 $cdn_acl_user_agent="", $cdn_acl_referrer)
331 {
332 if ($container_name == "")
333 throw new SyntaxException("Container name not set.");
334
335 if ($container_name != "0" and !isset($container_name))
336 throw new SyntaxException("Container name not set.");
337
338 $url_path = $this->_make_path("CDN", $container_name);
339 $hdrs = array(
340 CDN_ENABLED => "True",
341 CDN_TTL => $ttl,
342 CDN_LOG_RETENTION => $cdn_log_retention ? "True" : "False",
343 CDN_ACL_USER_AGENT => $cdn_acl_user_agent,
344 CDN_ACL_REFERRER => $cdn_acl_referrer,
345 );
346 $return_code = $this->_send_request("DEL_POST",$url_path,$hdrs,"POST");
347 if ($return_code == 401) {
348 $this->error_str = "Unauthorized";
349 return array($return_code, $this->error_str, NULL);
350 }
351 if ($return_code == 404) {
352 $this->error_str = "Container not found.";
353 return array($return_code, $this->error_str, NULL);
354 }
355 if ($return_code != 202) {
356 $this->error_str="Unexpected HTTP response: ".$this->response_reason;
357 return array($return_code, $this->error_str, NULL);
358 }
359 return array($return_code, "Accepted", $this->_cdn_uri, $this->_cdn_ssl_uri);
360
361 }
362
363 # (CDN) PUT /v1/Account/Container
364 #
365 function add_cdn_container($container_name, $ttl=86400)
366 {
367 if ($container_name == "")
368 throw new SyntaxException("Container name not set.");
369
370 if ($container_name != "0" and !isset($container_name))
371 throw new SyntaxException("Container name not set.");
372
373 $url_path = $this->_make_path("CDN", $container_name);
374 $hdrs = array(
375 CDN_ENABLED => "True",
376 CDN_TTL => $ttl,
377 );
378 $return_code = $this->_send_request("PUT_CONT", $url_path, $hdrs);
379 if ($return_code == 401) {
380 $this->error_str = "Unauthorized";
381 return array($return_code,$this->response_reason,False);
382 }
383 if (!in_array($return_code, array(201,202))) {
384 $this->error_str="Unexpected HTTP response: ".$this->response_reason;
385 return array($return_code,$this->response_reason,False);
386 }
387 return array($return_code,$this->response_reason,$this->_cdn_uri,
388 $this->_cdn_ssl_uri);
389 }
390
391 # (CDN) POST /v1/Account/Container
392 #
393 function remove_cdn_container($container_name)
394 {
395 if ($container_name == "")
396 throw new SyntaxException("Container name not set.");
397
398 if ($container_name != "0" and !isset($container_name))
399 throw new SyntaxException("Container name not set.");
400
401 $url_path = $this->_make_path("CDN", $container_name);
402 $hdrs = array(CDN_ENABLED => "False");
403 $return_code = $this->_send_request("DEL_POST",$url_path,$hdrs,"POST");
404 if ($return_code == 401) {
405 $this->error_str = "Unauthorized";
406 return array($return_code, $this->error_str);
407 }
408 if ($return_code == 404) {
409 $this->error_str = "Container not found.";
410 return array($return_code, $this->error_str);
411 }
412 if ($return_code != 202) {
413 $this->error_str="Unexpected HTTP response: ".$this->response_reason;
414 return array($return_code, $this->error_str);
415 }
416 return array($return_code, "Accepted");
417 }
418
419 # (CDN) HEAD /v1/Account
420 #
421 function head_cdn_container($container_name)
422 {
423 if ($container_name == "")
424 throw new SyntaxException("Container name not set.");
425
426 if ($container_name != "0" and !isset($container_name))
427 throw new SyntaxException("Container name not set.");
428
429 $conn_type = "HEAD";
430 $url_path = $this->_make_path("CDN", $container_name);
431 $return_code = $this->_send_request($conn_type, $url_path, NULL, "GET", True);
432
433 if (!$return_code) {
434 $this->error_str .= ": Failed to obtain valid HTTP response.";
435 return array(0,$this->error_str,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
436 }
437 if ($return_code == 401) {
438 return array($return_code,"Unauthorized",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
439 }
440 if ($return_code == 404) {
441 return array($return_code,"Account not found.",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
442 }
443 if ($return_code == 204) {
444 return array($return_code,$this->response_reason,
445 $this->_cdn_enabled, $this->_cdn_ssl_uri,
446 $this->_cdn_streaming_uri,
447 $this->_cdn_uri, $this->_cdn_ttl,
448 $this->_cdn_log_retention,
449 $this->_cdn_acl_user_agent,
450 $this->_cdn_acl_referrer
451 );
452 }
453 return array($return_code,$this->response_reason,
454 NULL,NULL,NULL,NULL,
455 $this->_cdn_log_retention,
456 $this->_cdn_acl_user_agent,
457 $this->_cdn_acl_referrer,
458 NULL
459 );
460 }
461
462 # GET /v1/Account
463 #
464 function list_containers($limit=0, $marker=NULL)
465 {
466 $conn_type = "GET_CALL";
467 $url_path = $this->_make_path();
468
469 $limit = intval($limit);
470 $params = array();
471 if ($limit > 0) {
472 $params[] = "limit=$limit";
473 }
474 if ($marker) {
475 $params[] = "marker=".rawurlencode($marker);
476 }
477 if (!empty($params)) {
478 $url_path .= "?" . implode("&", $params);
479 }
480
481 $this->_write_callback_type = "TEXT_LIST";
482 $return_code = $this->_send_request($conn_type, $url_path);
483
484 if (!$return_code) {
485 $this->error_str .= ": Failed to obtain valid HTTP response.";
486 return array(0,$this->error_str,array());
487 }
488 if ($return_code == 204) {
489 return array($return_code, "Account has no containers.", array());
490 }
491 if ($return_code == 404) {
492 $this->error_str = "Invalid account name for authentication token.";
493 return array($return_code,$this->error_str,array());
494 }
495 if ($return_code == 200) {
496 $this->create_array();
497 return array($return_code, $this->response_reason, $this->_text_list);
498 }
499 $this->error_str = "Unexpected HTTP response: ".$this->response_reason;
500 return array($return_code,$this->error_str,array());
501 }
502
503 # GET /v1/Account?format=json
504 #
505 function list_containers_info($limit=0, $marker=NULL)
506 {
507 $conn_type = "GET_CALL";
508 $url_path = $this->_make_path() . "?format=json";
509
510 $limit = intval($limit);
511 $params = array();
512 if ($limit > 0) {
513 $params[] = "limit=$limit";
514 }
515 if ($marker) {
516 $params[] = "marker=".rawurlencode($marker);
517 }
518 if (!empty($params)) {
519 $url_path .= "&" . implode("&", $params);
520 }
521
522 $this->_write_callback_type = "OBJECT_STRING";
523 $return_code = $this->_send_request($conn_type, $url_path);
524
525 if (!$return_code) {
526 $this->error_str .= ": Failed to obtain valid HTTP response.";
527 return array(0,$this->error_str,array());
528 }
529 if ($return_code == 204) {
530 return array($return_code, "Account has no containers.", array());
531 }
532 if ($return_code == 404) {
533 $this->error_str = "Invalid account name for authentication token.";
534 return array($return_code,$this->error_str,array());
535 }
536 if ($return_code == 200) {
537 $json_body = json_decode($this->_obj_write_string, True);
538 return array($return_code, $this->response_reason, $json_body);
539 }
540 $this->error_str = "Unexpected HTTP response: ".$this->response_reason;
541 return array($return_code,$this->error_str,array());
542 }
543
544 # HEAD /v1/Account
545 #
546 function head_account()
547 {
548 $conn_type = "HEAD";
549
550 $url_path = $this->_make_path();
551 $return_code = $this->_send_request($conn_type,$url_path);
552
553 if (!$return_code) {
554 $this->error_str .= ": Failed to obtain valid HTTP response.";
555 return array(0,$this->error_str,0,0, NULL, array());
556 }
557 if ($return_code == 404) {
558 return array($return_code,"Account not found.",0,0, NULL, array());
559 }
560 if ($return_code == 204) {
561 return array($return_code,$this->response_reason,
562 $this->_account_container_count, $this->_account_bytes_used,
563 $this->_account_key, $this->account_metadata);
564 }
565 return array($return_code,$this->response_reason,0,0, NULL, array());
566 }
567
568 # PUT /v1/Account/Container
569 #
570 function create_container($container_name)
571 {
572 if ($container_name == "")
573 throw new SyntaxException("Container name not set.");
574
575 if ($container_name != "0" and !isset($container_name))
576 throw new SyntaxException("Container name not set.");
577
578 $url_path = $this->_make_path("STORAGE", $container_name);
579 $return_code = $this->_send_request("PUT_CONT",$url_path);
580
581 if (!$return_code) {
582 $this->error_str .= ": Failed to obtain valid HTTP response.";
583 return False;
584 }
585 return $return_code;
586 }
587
588 # DELETE /v1/Account/Container
589 #
590 function delete_container($container_name)
591 {
592 if ($container_name == "")
593 throw new SyntaxException("Container name not set.");
594
595 if ($container_name != "0" and !isset($container_name))
596 throw new SyntaxException("Container name not set.");
597
598 $url_path = $this->_make_path("STORAGE", $container_name);
599 $return_code = $this->_send_request("DEL_POST",$url_path,array(),"DELETE");
600
601 switch ($return_code) {
602 case 204:
603 break;
604 case 0:
605 $this->error_str .= ": Failed to obtain valid HTTP response.";;
606 break;
607 case 409:
608 $this->error_str = "Container must be empty prior to removing it.";
609 break;
610 case 404:
611 $this->error_str = "Specified container did not exist to delete.";
612 break;
613 default:
614 $this->error_str = "Unexpected HTTP return code: $return_code.";
615 }
616 return $return_code;
617 }
618
619 # GET /v1/Account/Container
620 #
621 function list_objects($cname,$limit=0,$marker=NULL,$prefix=NULL,$path=NULL)
622 {
623 if (!$cname) {
624 $this->error_str = "Container name not set.";
625 return array(0, $this->error_str, array());
626 }
627
628 $url_path = $this->_make_path("STORAGE", $cname);
629
630 $limit = intval($limit);
631 $params = array();
632 if ($limit > 0) {
633 $params[] = "limit=$limit";
634 }
635 if ($marker) {
636 $params[] = "marker=".rawurlencode($marker);
637 }
638 if ($prefix) {
639 $params[] = "prefix=".rawurlencode($prefix);
640 }
641 if ($path) {
642 $params[] = "path=".rawurlencode($path);
643 }
644 if (!empty($params)) {
645 $url_path .= "?" . implode("&", $params);
646 }
647
648 $conn_type = "GET_CALL";
649 $this->_write_callback_type = "TEXT_LIST";
650 $return_code = $this->_send_request($conn_type,$url_path);
651
652 if (!$return_code) {
653 $this->error_str .= ": Failed to obtain valid HTTP response.";
654 return array(0,$this->error_str,array());
655 }
656 if ($return_code == 204) {
657 $this->error_str = "Container has no Objects.";
658 return array($return_code,$this->error_str,array());
659 }
660 if ($return_code == 404) {
661 $this->error_str = "Container has no Objects.";
662 return array($return_code,$this->error_str,array());
663 }
664 if ($return_code == 200) {
665 $this->create_array();
666 return array($return_code,$this->response_reason, $this->_text_list);
667 }
668 $this->error_str = "Unexpected HTTP response code: $return_code";
669 return array(0,$this->error_str,array());
670 }
671
672 # GET /v1/Account/Container?format=json
673 #
674 function get_objects($cname,$limit=0,$marker=NULL,$prefix=NULL,$path=NULL,$delimiter=NULL)
675 {
676 if (strlen($cname) == 0) {
677 $this->error_str = "Container name not set.";
678 return array(0, $this->error_str, array());
679 }
680 $url_path = $this->_make_path("STORAGE", $cname);
681
682 $limit = intval($limit);
683 $params = array();
684 $params[] = "format=json";
685 if ($limit > 0) {
686 $params[] = "limit=$limit";
687 }
688 if ($marker) {
689 $params[] = "marker=".rawurlencode($marker);
690 }
691 if ($prefix) {
692 $params[] = "prefix=".rawurlencode($prefix);
693 }
694 if ($path) {
695 $params[] = "path=".rawurlencode($path);
696 }
697 if ($delimiter) {
698 $params[] = "delimiter=".rawurlencode($delimiter);
699 }
700 if (!empty($params)) {
701 $url_path .= "?" . implode("&", $params);
702 }
703
704 $conn_type = "GET_CALL";
705 $this->_write_callback_type = "OBJECT_STRING";
706 $return_code = $this->_send_request($conn_type,$url_path);
707
708 if (!$return_code) {
709 $this->error_str .= ": Failed to obtain valid HTTP response.";
710 return array(0,$this->error_str,array());
711 }
712 if ($return_code == 204) {
713 $this->error_str = "Container has no Objects.";
714 return array($return_code,$this->error_str,array());
715 }
716 if ($return_code == 404) {
717 $this->error_str = "Container has no Objects.";
718 return array($return_code,$this->error_str,array());
719 }
720 if ($return_code == 200) {
721 $json_body = json_decode($this->_obj_write_string, True);
722 return array($return_code,$this->response_reason, $json_body);
723 }
724 $this->error_str = "Unexpected HTTP response code: $return_code";
725 return array(0,$this->error_str,array());
726 }
727
728
729 # HEAD /v1/Account/Container
730 #
731 function head_container($container_name)
732 {
733
734 if ($container_name == "") {
735 $this->error_str = "Container name not set.";
736 return False;
737 }
738
739 if ($container_name != "0" and !isset($container_name)) {
740 $this->error_str = "Container name not set.";
741 return False;
742 }
743
744 $conn_type = "HEAD";
745
746 $url_path = $this->_make_path("STORAGE", $container_name);
747 $return_code = $this->_send_request($conn_type,$url_path);
748
749 if (!$return_code) {
750 $this->error_str .= ": Failed to obtain valid HTTP response.";
751 return array(0,$this->error_str,0,0, array());
752 }
753 if ($return_code == 404) {
754 return array($return_code,"Container not found.",0,0, array());
755 }
756 if ($return_code == 204 || $return_code == 200) {
757 return array($return_code,$this->response_reason,
758 $this->_container_object_count, $this->_container_bytes_used,
759 $this->_container_metadata);
760 }
761 return array($return_code,$this->response_reason,0,0, array());
762 }
763
764 # GET /v1/Account/Container/Object
765 #
766 function get_object_to_string(&$obj, $hdrs=array())
767 {
768 if (!is_object($obj) || get_class($obj) != "UpdraftPlus_CF_Object") {
769 throw new SyntaxException(
770 "Method argument is not a valid CF_Object.");
771 }
772
773 $conn_type = "GET_CALL";
774
775 $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name);
776 $this->_write_callback_type = "OBJECT_STRING";
777 $return_code = $this->_send_request($conn_type,$url_path,$hdrs);
778
779 if (!$return_code) {
780 $this->error_str .= ": Failed to obtain valid HTTP response.";
781 return array($return_code0,$this->error_str,NULL);
782 }
783 if ($return_code == 404) {
784 $this->error_str = "Object not found.";
785 return array($return_code0,$this->error_str,NULL);
786 }
787 if (($return_code < 200) || ($return_code > 299
788 && $return_code != 412 && $return_code != 304)) {
789 $this->error_str = "Unexpected HTTP return code: $return_code";
790 return array($return_code,$this->error_str,NULL);
791 }
792 return array($return_code,$this->response_reason, $this->_obj_write_string);
793 }
794
795 # GET /v1/Account/Container/Object
796 #
797 function get_object_to_stream(&$obj, &$resource=NULL, $hdrs=array())
798 {
799 if (!is_object($obj) || get_class($obj) != "UpdraftPlus_CF_Object") {
800 throw new SyntaxException(
801 "Method argument is not a valid CF_Object.");
802 }
803 if (!is_resource($resource)) {
804 throw new SyntaxException(
805 "Resource argument not a valid PHP resource.");
806 }
807
808 $conn_type = "GET_CALL";
809
810 $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name);
811 $this->_obj_write_resource = $resource;
812 $this->_write_callback_type = "OBJECT_STREAM";
813 $return_code = $this->_send_request($conn_type,$url_path,$hdrs);
814
815 if (!$return_code) {
816 $this->error_str .= ": Failed to obtain valid HTTP response.";
817 return array($return_code,$this->error_str);
818 }
819 if ($return_code == 404) {
820 $this->error_str = "Object not found.";
821 return array($return_code,$this->error_str);
822 }
823 if (($return_code < 200) || ($return_code > 299
824 && $return_code != 412 && $return_code != 304)) {
825 $this->error_str = "Unexpected HTTP return code: $return_code";
826 return array($return_code,$this->error_str);
827 }
828 return array($return_code,$this->response_reason);
829 }
830
831 # PUT /v1/Account/Container/Object
832 #
833 function put_object(&$obj, &$fp)
834 {
835 if (!is_object($obj) || get_class($obj) != "UpdraftPlus_CF_Object") {
836 throw new SyntaxException(
837 "Method argument is not a valid CF_Object.");
838 }
839 if (!is_resource($fp)) {
840 throw new SyntaxException(
841 "File pointer argument is not a valid resource.");
842 }
843
844 $conn_type = "PUT_OBJ";
845 $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name);
846 $hdrs = $this->_headers($obj);
847
848 $etag = $obj->getETag();
849 if (isset($etag)) {
850 $hdrs[] = "ETag: " . $etag;
851 }
852 if (!$obj->content_type) {
853 $hdrs[] = "Content-Type: application/octet-stream";
854 } else {
855 $hdrs[] = "Content-Type: " . $obj->content_type;
856 }
857
858 $this->_init($conn_type);
859 curl_setopt($this->connections[$conn_type],
860 CURLOPT_INFILE, $fp);
861 if (!$obj->content_length) {
862 # We don''t know the Content-Length, so assumed "chunked" PUT
863 #
864 curl_setopt($this->connections[$conn_type], CURLOPT_UPLOAD, True);
865 $hdrs[] = 'Transfer-Encoding: chunked';
866 } else {
867 # We know the Content-Length, so use regular transfer
868 #
869 curl_setopt($this->connections[$conn_type],
870 CURLOPT_INFILESIZE, $obj->content_length);
871 }
872 $return_code = $this->_send_request($conn_type,$url_path,$hdrs);
873
874 if (!$return_code) {
875 $this->error_str .= ": Failed to obtain valid HTTP response.";
876 return array(0,$this->error_str,NULL);
877 }
878 if ($return_code == 412) {
879 $this->error_str = "Missing Content-Type header";
880 return array($return_code,$this->error_str,NULL);
881 }
882 if ($return_code == 422) {
883 $this->error_str = "Derived and computed checksums do not match.";
884 return array($return_code,$this->error_str,NULL);
885 }
886 if ($return_code != 201) {
887 $this->error_str = "Unexpected HTTP return code: $return_code";
888 return array($return_code,$this->error_str,NULL);
889 }
890 return array($return_code,$this->response_reason,$this->_obj_etag);
891 }
892 function post_account(&$conn)
893 {
894 if (!is_object($conn) || get_class($conn) != "UpdraftPlus_CF_Connection") {
895 throw new SyntaxException(
896 "Method argument is not a valid CF_Connection object.");
897 }
898 if (!is_array($conn->metadata)) {
899 throw new SyntaxException("Metadata array is empty");
900 }
901 $return_code = $this->_send_request("DEL_POST", $this->_make_path("STORAGE"), $conn->metadata, "POST");
902 switch ($return_code) {
903 case 202:
904 case 201:
905 break;
906 case 0:
907 $this->error_str .= ": Failed to obtain valid HTTP response.";
908 $return_code = 0;
909 break;
910 case 404:
911 $this->error_str = "Account, Container, or Object not found.";
912 break;
913 default:
914 $this->error_str = "Unexpected HTTP return code: $return_code";
915 break;
916 }
917 return $return_code;
918 }
919 function post_container(&$cont)
920 {
921 if (!is_object($cont) || get_class($cont) != "UpdraftPlus_CF_Container") {
922 throw new SyntaxException(
923 "Method argument is not a valid CF_Container object.");
924 }
925 if (!is_array($cont->metadata)) {
926 throw new SyntaxException("Metadata array is empty");
927 }
928 $return_code = $this->_send_request("DEL_POST", $this->_make_path("STORAGE", $cont->name), $cont->metadata, "POST");
929 switch ($return_code) {
930 case 201:
931 case 202:
932 break;
933 case 0:
934 $this->error_str .= ": Failed to obtain valid HTTP response.";
935 $return_code = 0;
936 break;
937 case 404:
938 $this->error_str = "Account, Container, or Object not found.";
939 break;
940 default:
941 $this->error_str = "Unexpected HTTP return code: $return_code";
942 break;
943 }
944 return $return_code;
945 }
946
947 # POST /v1/Account/Container/Object
948 #
949 function update_object(&$obj)
950 {
951 if (!is_object($obj) || get_class($obj) != "UpdraftPlus_CF_Object") {
952 throw new SyntaxException(
953 "Method argument is not a valid CF_Object.");
954 }
955
956 # TODO: The is_array check isn't in sync with the error message
957 if (!$obj->manifest && !(is_array($obj->metadata) || is_array($obj->headers))) {
958 $this->error_str = "Metadata and headers arrays are empty.";
959 return 0;
960 }
961
962 $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name);
963
964 $hdrs = $this->_headers($obj);
965 $return_code = $this->_send_request("DEL_POST",$url_path,$hdrs,"POST");
966 switch ($return_code) {
967 case 202:
968 break;
969 case 0:
970 $this->error_str .= ": Failed to obtain valid HTTP response.";
971 $return_code = 0;
972 break;
973 case 404:
974 $this->error_str = "Account, Container, or Object not found.";
975 break;
976 default:
977 $this->error_str = "Unexpected HTTP return code: $return_code";
978 break;
979 }
980 return $return_code;
981 }
982
983 # HEAD /v1/Account/Container/Object
984 #
985 function head_object(&$obj)
986 {
987 if (!is_object($obj) || get_class($obj) != "UpdraftPlus_CF_Object") {
988 throw new SyntaxException(
989 "Method argument is not a valid CF_Object.");
990 }
991
992 $conn_type = "HEAD";
993
994 $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name);
995 $return_code = $this->_send_request($conn_type,$url_path);
996
997 if (!$return_code) {
998 $this->error_str .= ": Failed to obtain valid HTTP response.";
999 return array(0, $this->error_str." ".$this->response_reason,
1000 NULL, NULL, NULL, NULL, array(), NULL, NULL, NULL, array());
1001 }
1002
1003 if ($return_code == 404) {
1004 return array($return_code, $this->response_reason,
1005 NULL, NULL, NULL, NULL, array(), NULL, NULL, NULL, array());
1006 }
1007 if ($return_code == 204 || $return_code == 200) {
1008 return array($return_code,$this->response_reason,
1009 $this->_obj_etag,
1010 $this->_obj_last_modified,
1011 $this->_obj_content_type,
1012 $this->_obj_content_length,
1013 $this->_obj_metadata,
1014 $this->_obj_manifest,
1015 $this->_obj_delete_at,
1016 $this->_obj_delete_after,
1017 $this->_obj_headers);
1018 }
1019 $this->error_str = "Unexpected HTTP return code: $return_code";
1020 return array($return_code, $this->error_str." ".$this->response_reason,
1021 NULL, NULL, NULL, NULL, array(), NULL, NULL, NULL, array());
1022 }
1023
1024 # COPY /v1/Account/Container/Object
1025 #
1026 function copy_object($src_obj_name, $dest_obj_name, $container_name_source, $container_name_target, $metadata=NULL, $headers=NULL)
1027 {
1028 if (!$src_obj_name) {
1029 $this->error_str = "Object name not set.";
1030 return 0;
1031 }
1032
1033 if ($container_name_source == "") {
1034 $this->error_str = "Container name source not set.";
1035 return 0;
1036 }
1037
1038 if ($container_name_source != "0" and !isset($container_name_source)) {
1039 $this->error_str = "Container name source not set.";
1040 return 0;
1041 }
1042
1043 if ($container_name_target == "") {
1044 $this->error_str = "Container name target not set.";
1045 return 0;
1046 }
1047
1048 if ($container_name_target != "0" and !isset($container_name_target)) {
1049 $this->error_str = "Container name target not set.";
1050 return 0;
1051 }
1052
1053 $conn_type = "COPY";
1054
1055 $url_path = $this->_make_path("STORAGE", $container_name_source, rawurlencode($src_obj_name));
1056 $destination = rawurlencode($container_name_target."/".$dest_obj_name);
1057
1058 $hdrs = self::_process_headers($metadata, $headers);
1059 $hdrs[DESTINATION] = $destination;
1060
1061 $return_code = $this->_send_request($conn_type,$url_path,$hdrs,"COPY");
1062 switch ($return_code) {
1063 case 201:
1064 break;
1065 case 0:
1066 $this->error_str .= ": Failed to obtain valid HTTP response.";
1067 $return_code = 0;
1068 break;
1069 case 404:
1070 $this->error_str = "Specified container/object did not exist.";
1071 break;
1072 default:
1073 $this->error_str = "Unexpected HTTP return code: $return_code.";
1074 }
1075 return $return_code;
1076 }
1077
1078 # DELETE /v1/Account/Container/Object
1079 #
1080 function delete_object($container_name, $object_name)
1081 {
1082 if ($container_name == "") {
1083 $this->error_str = "Container name not set.";
1084 return 0;
1085 }
1086
1087 if ($container_name != "0" and !isset($container_name)) {
1088 $this->error_str = "Container name not set.";
1089 return 0;
1090 }
1091
1092 if (!$object_name) {
1093 $this->error_str = "Object name not set.";
1094 return 0;
1095 }
1096
1097 $url_path = $this->_make_path("STORAGE", $container_name,$object_name);
1098 $return_code = $this->_send_request("DEL_POST",$url_path,NULL,"DELETE");
1099 switch ($return_code) {
1100 case 204:
1101 break;
1102 case 0:
1103 $this->error_str .= ": Failed to obtain valid HTTP response.";
1104 $return_code = 0;
1105 break;
1106 case 404:
1107 $this->error_str = "Specified container did not exist to delete.";
1108 break;
1109 default:
1110 $this->error_str = "Unexpected HTTP return code: $return_code.";
1111 }
1112 return $return_code;
1113 }
1114
1115 function get_error()
1116 {
1117 return $this->error_str;
1118 }
1119
1120 function setDebug($bool)
1121 {
1122 $this->dbug = $bool;
1123 foreach ($this->connections as $k => $v) {
1124 if (!is_null($v)) {
1125 curl_setopt($this->connections[$k], CURLOPT_VERBOSE, $this->dbug);
1126 }
1127 }
1128 }
1129
1130 function getCDNMUrl()
1131 {
1132 return $this->cdnm_url;
1133 }
1134
1135 function getStorageUrl()
1136 {
1137 return $this->storage_url;
1138 }
1139
1140 function getAuthToken()
1141 {
1142 return $this->auth_token;
1143 }
1144
1145 function setCFAuth($cfs_auth, $servicenet=False)
1146 {
1147 if ($servicenet) {
1148 $this->storage_url = "https://snet-" . substr($cfs_auth->storage_url, 8);
1149 } else {
1150 $this->storage_url = $cfs_auth->storage_url;
1151 }
1152 $this->auth_token = $cfs_auth->auth_token;
1153 $this->cdnm_url = $cfs_auth->cdnm_url;
1154 }
1155
1156 function setReadProgressFunc($func_name)
1157 {
1158 $this->_user_read_progress_callback_func = $func_name;
1159 }
1160
1161 function setWriteProgressFunc($func_name)
1162 {
1163 $this->_user_write_progress_callback_func = $func_name;
1164 }
1165 private function _header_cb($ch, $header)
1166 {
1167 $header_len = strlen($header);
1168
1169 if (preg_match("/^(HTTP\/1\.[01]) (\d{3}) (.*)/", $header, $matches)) {
1170 $this->response_status = $matches[2];
1171 $this->response_reason = $matches[3];
1172 return $header_len;
1173 }
1174
1175 if (strpos($header, ":") === False)
1176 return $header_len;
1177 list($name, $value) = explode(":", $header, 2);
1178 $value = trim($value);
1179
1180 switch (strtolower($name)) {
1181 case strtolower(CDN_ENABLED):
1182 $this->_cdn_enabled = strtolower($value) == "true";
1183 break;
1184 case strtolower(CDN_URI):
1185 $this->_cdn_uri = $value;
1186 break;
1187 case strtolower(CDN_SSL_URI):
1188 $this->_cdn_ssl_uri = $value;
1189 break;
1190 case strtolower(CDN_STREAMING_URI):
1191 $this->_cdn_streaming_uri = $value;
1192 break;
1193 case strtolower(CDN_TTL):
1194 $this->_cdn_ttl = $value;
1195 break;
1196 case strtolower(MANIFEST_HEADER):
1197 $this->_obj_manifest = $value;
1198 break;
1199 case strtolower(CDN_LOG_RETENTION):
1200 $this->_cdn_log_retention = strtolower($value) == "true";
1201 break;
1202 case strtolower(CDN_ACL_USER_AGENT):
1203 $this->_cdn_acl_user_agent = $value;
1204 break;
1205 case strtolower(CDN_ACL_REFERRER):
1206 $this->_cdn_acl_referrer = $value;
1207 break;
1208 case strtolower(ACCOUNT_CONTAINER_COUNT):
1209 $this->_account_container_count = (float)$value+0;
1210 break;
1211 case strtolower(ACCOUNT_BYTES_USED):
1212 $this->_account_bytes_used = (float)$value+0;
1213 break;
1214 case strtolower(CONTAINER_OBJ_COUNT):
1215 $this->_container_object_count = (float)$value+0;
1216 break;
1217 case strtolower(CONTAINER_BYTES_USED):
1218 $this->_container_bytes_used = (float)$value+0;
1219 break;
1220 case strtolower(ETAG_HEADER):
1221 $this->_obj_etag = $value;
1222 break;
1223 case strtolower(LAST_MODIFIED_HEADER):
1224 $this->_obj_last_modified = $value;
1225 break;
1226 case strtolower(CONTENT_TYPE_HEADER):
1227 $this->_obj_content_type = $value;
1228 break;
1229 case strtolower(CONTENT_LENGTH_HEADER):
1230 $this->_obj_content_length = (float)$value+0;
1231 break;
1232 case strtolower(ORIGIN_HEADER):
1233 $this->_obj_headers[ORIGIN_HEADER] = $value;
1234 break;
1235 case strtolower(ACCOUNT_KEY):
1236 $this->_account_key = $value;
1237 break;
1238 default:
1239 if (strncasecmp($name, METADATA_HEADER_PREFIX, strlen(METADATA_HEADER_PREFIX)) == 0) {
1240 $name = substr($name, strlen(METADATA_HEADER_PREFIX));
1241 $this->_obj_metadata[$name] = $value;
1242 }
1243 elseif ((strncasecmp($name, CONTENT_HEADER_PREFIX, strlen(CONTENT_HEADER_PREFIX)) == 0) ||
1244 (strncasecmp($name, ACCESS_CONTROL_HEADER_PREFIX, strlen(ACCESS_CONTROL_HEADER_PREFIX)) == 0)) {
1245 $this->_obj_headers[$name] = $value;
1246 }
1247 elseif (strncasecmp($name, ACCOUNT_METADATA_HEADER_PREFIX, strlen(ACCOUNT_METADATA_HEADER_PREFIX)) == 0) {
1248 $this->_account_metadata[$name] = $value;
1249 }
1250 elseif (strncasecmp($name, CONTAINER_METADATA_HEADER_PREFIX, strlen(CONTAINER_METADATA_HEADER_PREFIX)) == 0) {
1251 $this->_container_metadata[$name] = $value;
1252 }
1253 }
1254 return $header_len;
1255 }
1256
1257 private function _read_cb($ch, $fd, $length)
1258 {
1259 $data = fread($fd, $length);
1260 $len = strlen($data);
1261 if (isset($this->_user_write_progress_callback_func)) {
1262 call_user_func($this->_user_write_progress_callback_func, $len);
1263 }
1264 return $data;
1265 }
1266
1267 private function _write_cb($ch, $data)
1268 {
1269 $dlen = strlen($data);
1270 switch ($this->_write_callback_type) {
1271 case "TEXT_LIST":
1272 $this->_return_list = $this->_return_list . $data;
1273 //= explode("\n",$data); # keep tab,space
1274 //his->_text_list[] = rtrim($data,"\n\r\x0B"); # keep tab,space
1275 break;
1276 case "OBJECT_STREAM":
1277 fwrite($this->_obj_write_resource, $data, $dlen);
1278 break;
1279 case "OBJECT_STRING":
1280 $this->_obj_write_string .= $data;
1281 break;
1282 }
1283 if (isset($this->_user_read_progress_callback_func)) {
1284 call_user_func($this->_user_read_progress_callback_func, $dlen);
1285 }
1286 return $dlen;
1287 }
1288
1289 private function _auth_hdr_cb($ch, $header)
1290 {
1291 preg_match("/^HTTP\/1\.[01] (\d{3}) (.*)/", $header, $matches);
1292 if (isset($matches[1])) {
1293 $this->response_status = $matches[1];
1294 }
1295 if (isset($matches[2])) {
1296 $this->response_reason = $matches[2];
1297 }
1298 if (stripos($header, STORAGE_URL) === 0) {
1299 $this->storage_url = trim(substr($header, strlen(STORAGE_URL)+1));
1300 }
1301 if (stripos($header, CDNM_URL) === 0) {
1302 $this->cdnm_url = trim(substr($header, strlen(CDNM_URL)+1));
1303 }
1304 if (stripos($header, AUTH_TOKEN) === 0) {
1305 $this->auth_token = trim(substr($header, strlen(AUTH_TOKEN)+1));
1306 }
1307 if (stripos($header, AUTH_TOKEN_LEGACY) === 0) {
1308 $this->auth_token = trim(substr($header,strlen(AUTH_TOKEN_LEGACY)+1));
1309 }
1310 return strlen($header);
1311 }
1312
1313 private function _make_headers($hdrs=NULL)
1314 {
1315 $new_headers = array();
1316 $has_stoken = False;
1317 $has_uagent = False;
1318 if (is_array($hdrs)) {
1319 foreach ($hdrs as $h => $v) {
1320 if (is_int($h)) {
1321 list($h, $v) = explode(":", $v, 2);
1322 }
1323
1324 if (strncasecmp($h, AUTH_TOKEN, strlen(AUTH_TOKEN)) === 0) {
1325 $has_stoken = True;
1326 }
1327 if (strncasecmp($h, USER_AGENT_HEADER, strlen(USER_AGENT_HEADER)) === 0) {
1328 $has_uagent = True;
1329 }
1330 $new_headers[] = $h . ": " . trim($v);
1331 }
1332 }
1333 if (!$has_stoken) {
1334 $new_headers[] = AUTH_TOKEN . ": " . $this->auth_token;
1335 }
1336 if (!$has_uagent) {
1337 $new_headers[] = USER_AGENT_HEADER . ": " . USER_AGENT;
1338 }
1339 return $new_headers;
1340 }
1341
1342 private function _init($conn_type, $force_new=False)
1343 {
1344 if (!array_key_exists($conn_type, $this->connections)) {
1345 $this->error_str = "Invalid CURL_XXX connection type";
1346 return False;
1347 }
1348
1349 if (is_null($this->connections[$conn_type]) || $force_new) {
1350 $ch = curl_init();
1351 } else {
1352 return;
1353 }
1354
1355 if ($this->dbug) { curl_setopt($ch, CURLOPT_VERBOSE, 1); }
1356
1357 if (!is_null($this->cabundle_path)) {
1358 curl_setopt($ch, CURLOPT_CAINFO, $this->cabundle_path);
1359 }
1360 if (UpdraftPlus_Options::get_updraft_option('updraft_ssl_disableverify')) {
1361 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
1362 } else {
1363 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
1364 }
1365 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
1366 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
1367 curl_setopt($ch, CURLOPT_MAXREDIRS, 4);
1368 curl_setopt($ch, CURLOPT_HEADER, 0);
1369 curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$this, '_header_cb'));
1370
1371 if ($conn_type == "GET_CALL") {
1372 curl_setopt($ch, CURLOPT_WRITEFUNCTION, array(&$this, '_write_cb'));
1373 }
1374
1375 if ($conn_type == "PUT_OBJ") {
1376 curl_setopt($ch, CURLOPT_PUT, 1);
1377 curl_setopt($ch, CURLOPT_READFUNCTION, array(&$this, '_read_cb'));
1378 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1379 }
1380 if ($conn_type == "HEAD") {
1381 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "HEAD");
1382 curl_setopt($ch, CURLOPT_NOBODY, 1);
1383 }
1384 if ($conn_type == "PUT_CONT") {
1385 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
1386 curl_setopt($ch, CURLOPT_INFILESIZE, 0);
1387 curl_setopt($ch, CURLOPT_NOBODY, 1);
1388 }
1389 if ($conn_type == "DEL_POST") {
1390 curl_setopt($ch, CURLOPT_NOBODY, 1);
1391 }
1392 if ($conn_type == "COPY") {
1393 curl_setopt($ch, CURLOPT_NOBODY, 1);
1394 }
1395 $this->connections[$conn_type] = $ch;
1396 return;
1397 }
1398
1399 private function _reset_callback_vars()
1400 {
1401 $this->_text_list = array();
1402 $this->_return_list = NULL;
1403 $this->_account_metadata = array();
1404 $this->_account_key = NULL;
1405 $this->_account_container_count = 0;
1406 $this->_account_bytes_used = 0;
1407 $this->_container_metadata = array();
1408 $this->_container_object_count = 0;
1409 $this->_container_bytes_used = 0;
1410 $this->_obj_delete_at = NULL;
1411 $this->_obj_delete_after = NULL;
1412 $this->_obj_etag = NULL;
1413 $this->_obj_last_modified = NULL;
1414 $this->_obj_content_type = NULL;
1415 $this->_obj_content_length = NULL;
1416 $this->_obj_metadata = array();
1417 $this->_obj_manifest = NULL;
1418 $this->_obj_headers = NULL;
1419 $this->_obj_write_string = "";
1420 $this->_cdn_streaming_uri = NULL;
1421 $this->_cdn_enabled = NULL;
1422 $this->_cdn_ssl_uri = NULL;
1423 $this->_cdn_uri = NULL;
1424 $this->_cdn_ttl = NULL;
1425 $this->response_status = 0;
1426 $this->response_reason = "";
1427 }
1428
1429 private function _make_path($t="STORAGE",$c=NULL,$o=NULL)
1430 {
1431 $path = array();
1432 switch ($t) {
1433 case "STORAGE":
1434 $path[] = $this->storage_url; break;
1435 case "CDN":
1436 $path[] = $this->cdnm_url; break;
1437 }
1438 if ($c != "") {
1439 $path[] = rawurlencode($c);
1440 }
1441 if ($o) {
1442 # mimic Python''s urllib.quote() feature of a "safe" '/' character
1443 #
1444 $path[] = str_replace("%2F","/",rawurlencode($o));
1445 }
1446 return implode("/",$path);
1447 }
1448
1449 private function _headers(&$obj)
1450 {
1451 $hdrs = self::_process_headers($obj->metadata, $obj->headers);
1452 if ($obj->manifest)
1453 $hdrs[MANIFEST_HEADER] = $obj->manifest;
1454
1455 return $hdrs;
1456 }
1457
1458 private function _process_headers($metadata=null, $headers=null)
1459 {
1460 $rules = array(
1461 array(
1462 'prefix' => METADATA_HEADER_PREFIX,
1463 ),
1464 array(
1465 'prefix' => '',
1466 'filter' => array( # key order is important, first match decides
1467 CONTENT_TYPE_HEADER => false,
1468 CONTENT_LENGTH_HEADER => false,
1469 CONTENT_HEADER_PREFIX => true,
1470 ACCESS_CONTROL_HEADER_PREFIX => true,
1471 ORIGIN_HEADER => true,
1472 ),
1473 ),
1474 );
1475
1476 $hdrs = array();
1477 $argc = func_num_args();
1478 $argv = func_get_args();
1479 for ($argi = 0; $argi < $argc; $argi++) {
1480 if(!is_array($argv[$argi])) continue;
1481
1482 $rule = $rules[$argi];
1483 foreach ($argv[$argi] as $k => $v) {
1484 $k = trim($k);
1485 $v = trim($v);
1486 if (strpos($k, ":") !== False) throw new SyntaxException(
1487 "Header names cannot contain a ':' character.");
1488
1489 if (array_key_exists('filter', $rule)) {
1490 $result = null;
1491 foreach ($rule['filter'] as $p => $f) {
1492 if (strncasecmp($k, $p, strlen($p)) == 0) {
1493 $result = $f;
1494 break;
1495 }
1496 }
1497 if (!$result) throw new SyntaxException(sprintf(
1498 "Header name %s is not allowed", $k));
1499 }
1500
1501 $k = $rule['prefix'] . $k;
1502 if (strlen($k) > MAX_HEADER_NAME_LEN || strlen($v) > MAX_HEADER_VALUE_LEN)
1503 throw new SyntaxException(sprintf(
1504 "Header %s exceeds maximum length: %d/%d",
1505 $k, strlen($k), strlen($v)));
1506
1507 $hdrs[$k] = $v;
1508 }
1509 }
1510
1511 return $hdrs;
1512 }
1513
1514 private function _send_request($conn_type, $url_path, $hdrs=NULL, $method="GET", $force_new=False)
1515 {
1516 $this->_init($conn_type, $force_new);
1517 $this->_reset_callback_vars();
1518 $headers = $this->_make_headers($hdrs);
1519
1520 if (gettype($this->connections[$conn_type]) == "unknown type")
1521 throw new ConnectionNotOpenException (
1522 "Connection is not open."
1523 );
1524
1525 switch ($method) {
1526 case "COPY":
1527 curl_setopt($this->connections[$conn_type],
1528 CURLOPT_CUSTOMREQUEST, "COPY");
1529 break;
1530 case "DELETE":
1531 curl_setopt($this->connections[$conn_type],
1532 CURLOPT_CUSTOMREQUEST, "DELETE");
1533 break;
1534 case "POST":
1535 curl_setopt($this->connections[$conn_type],
1536 CURLOPT_CUSTOMREQUEST, "POST");
1537 default:
1538 break;
1539 }
1540
1541 curl_setopt($this->connections[$conn_type],
1542 CURLOPT_HTTPHEADER, $headers);
1543
1544 curl_setopt($this->connections[$conn_type],
1545 CURLOPT_URL, $url_path);
1546
1547 if (!curl_exec($this->connections[$conn_type]) && curl_errno($this->connections[$conn_type]) !== 0) {
1548 $this->error_str = "(curl error: "
1549 . curl_errno($this->connections[$conn_type]) . ") ";
1550 $this->error_str .= curl_error($this->connections[$conn_type]);
1551 return False;
1552 }
1553 return curl_getinfo($this->connections[$conn_type], CURLINFO_HTTP_CODE);
1554 }
1555
1556 function close()
1557 {
1558 foreach ($this->connections as $cnx) {
1559 if (isset($cnx)) {
1560 curl_close($cnx);
1561 $this->connections[$cnx] = NULL;
1562 }
1563 }
1564 }
1565 private function create_array()
1566 {
1567 $this->_text_list = explode("\n",rtrim($this->_return_list,"\n\x0B"));
1568 return True;
1569 }
1570
1571 }
1572
1573 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
1574
1575 /*
1576 * Local variables:
1577 * tab-width: 4
1578 * c-basic-offset: 4
1579 * c-hanging-comment-ender-p: nil
1580 * End:
1581 */
1582 ?>
1583