Index: trunk/extensions/SwiftMedia/copyover |
— | — | @@ -1,8 +1,6 @@ |
2 | 2 | #!/bin/sh |
3 | 3 | |
4 | 4 | scp rnelson@ersch.wikimedia.org:/var/www/extensions/SwiftMedia/{SwiftMedia.body.php,SwiftMedia.i18n.php,SwiftMedia.php,TODO} . |
5 | | -scp -r rnelson@ersch.wikimedia.org:/usr/share/php-cloudfiles . |
6 | | -rm php-cloudfiles/*~ |
7 | 5 | scp rnelson@alsted.wikimedia.org:/etc/swift/proxy-server.conf proxy-server.sample |
8 | 6 | scp rnelson@alsted.wikimedia.org:/usr/local/lib/python2.6/dist-packages/wmf/{client.py,__init__.py,rewrite.py} wmf/ |
9 | 7 | scp rnelson@alsted.wikimedia.org:test_rewrite.py . |
Index: trunk/extensions/SwiftMedia/wmf/rewrite.py |
— | — | @@ -11,10 +11,6 @@ |
12 | 12 | import wmf.client |
13 | 13 | import time |
14 | 14 | |
15 | | -# the auth system turns our login and key into an account / token pair. |
16 | | -# the account remains valid forever, but the token times out. |
17 | | -account = 'AUTH_dea4a45c-a80b-43b5-8e8b-e452f0dc778f' |
18 | | - |
19 | 15 | # Copy2 is hairy. If we were only opening a URL, and returning it, we could |
20 | 16 | # just return the open file handle, and webob would take care of reading from |
21 | 17 | # the socket and returning the data to the client machine. If we were only |
— | — | @@ -33,12 +29,17 @@ |
34 | 30 | """ |
35 | 31 | token = None |
36 | 32 | |
37 | | - def __init__(self, conn, app, url, container, obj, authurl, login, key, content_type=None, modified=None): |
| 33 | + def __init__(self, conn, app, url, container, obj, authurl, login, key, |
| 34 | + content_type=None, modified=None): |
38 | 35 | self.app = app |
39 | 36 | self.conn = conn |
40 | 37 | if self.token is None: |
41 | 38 | (account, self.token) = wmf.client.get_auth(authurl, login, key) |
42 | 39 | if modified is not None: |
| 40 | + # The issue here is that we need to keep the timestamp between the |
| 41 | + # thumb server and us. The Migration-Timestamp header was in 1.2, |
| 42 | + # but was deprecated. They likely have a different solution for |
| 43 | + # setting the timestamp on an uploaded file. |
43 | 44 | h = {'!Migration-Timestamp!': '%s' % modified} |
44 | 45 | else: |
45 | 46 | h = {} |
— | — | @@ -46,9 +47,11 @@ |
47 | 48 | container, obj, content_type=content_type, headers=h) |
48 | 49 | |
49 | 50 | def __iter__(self): |
| 51 | + # We're an iterator; we get passed back to wsgi as a consumer. |
50 | 52 | return self |
51 | 53 | |
52 | 54 | def next(self): |
| 55 | + # We read from the thumb server, write out to Swift, and return it. |
53 | 56 | data = self.conn.read(4096) |
54 | 57 | if not data: |
55 | 58 | # if we get a 401 error, it's okay, but we should re-auth. |
— | — | @@ -57,7 +60,8 @@ |
58 | 61 | except wmf.client.ClientException, err: |
59 | 62 | self.app.logger.warn("PUT Status: %d" % err.http_status) |
60 | 63 | if err.http_status == 401: |
61 | | - # not worth retrying the write. |
| 64 | + # not worth retrying the write. Thumb will get saved |
| 65 | + # the next time. |
62 | 66 | self.token = None |
63 | 67 | else: |
64 | 68 | raise |
— | — | @@ -66,6 +70,10 @@ |
67 | 71 | return data |
68 | 72 | |
69 | 73 | class ObjectController(object): |
| 74 | + """ |
| 75 | + We're an object controller that doesn't actually do anything, but we |
| 76 | + will need these arguments later |
| 77 | + """ |
70 | 78 | |
71 | 79 | def __init__(self): |
72 | 80 | self.response_args = [] |
— | — | @@ -78,7 +86,7 @@ |
79 | 87 | """ |
80 | 88 | Rewrite Media Store URLs so that swift knows how to deal. |
81 | 89 | |
82 | | - Mostly it's a question of inserting the AUTH_ string, and escaping the %2F's in the container section. |
| 90 | + Mostly it's a question of inserting the AUTH_ string, and changing / to - in the container section. |
83 | 91 | """ |
84 | 92 | |
85 | 93 | def __init__(self, app, conf): |
— | — | @@ -92,16 +100,22 @@ |
93 | 101 | self.user_agent = conf['user_agent'].strip() |
94 | 102 | |
95 | 103 | def handle404(self, reqorig, url, container, obj): |
96 | | - """ return a webob.Response which reads the request, but from the thumb host. |
97 | 104 | """ |
| 105 | + Return a webob.Response which fetches the thumbnail from the thumb |
| 106 | + host, potentially writes it out to Swift so we don't 404 next time, |
| 107 | + and returns it. Note also that the thumb host might write it out |
| 108 | + to Swift so we don't have to. |
| 109 | + """ |
98 | 110 | # go to the thumb media store for unknown files |
99 | 111 | reqorig.host = self.thumbhost |
100 | | - # upload doesn't like our User-agent, otherwise we could call it using urllib2.url() |
| 112 | + # upload doesn't like our User-agent, otherwise we could call it |
| 113 | + # using urllib2.url() |
101 | 114 | opener = urllib2.build_opener() |
102 | 115 | opener.addheaders = [('User-agent', self.user_agent)] |
103 | | - # At least in theory, we shouldn't be handing out links to files that we don't have |
104 | | - # (or in the case of thumbs, can't generate). However, someone may have a formerly |
105 | | - # valid link to a file, so we should do them the favor of giving them a 404. |
| 116 | + # At least in theory, we shouldn't be handing out links to originals |
| 117 | + # that we don't have (or in the case of thumbs, can't generate). |
| 118 | + # However, someone may have a formerly valid link to a file, so we |
| 119 | + # should do them the favor of giving them a 404. |
106 | 120 | try: |
107 | 121 | upcopy = opener.open(reqorig.url) |
108 | 122 | except urllib2.HTTPError,status: |
— | — | @@ -127,7 +141,7 @@ |
128 | 142 | return resp |
129 | 143 | |
130 | 144 | def __call__(self, env, start_response): |
131 | | - #try: |
| 145 | + #try: commented-out while debugging so you can see where stuff happened. |
132 | 146 | req = webob.Request(env) |
133 | 147 | # PUT requests never need rewriting. |
134 | 148 | if req.method == 'PUT': |
— | — | @@ -146,14 +160,14 @@ |
147 | 161 | match = re.match(r'/(.*?)/(.*?)/(.*)', req.path) |
148 | 162 | if match: |
149 | 163 | # Our target URL is as follows: |
150 | | - # https://alsted.wikimedia.org:8080/v1/AUTH_6790933748e741268babd69804c6298b/wikipedia%252Fen/2/25/Machinesmith.png |
| 164 | + # https://alsted.wikimedia.org:8080/v1/AUTH_6790933748e741268babd69804c6298b/wikipedia-en/2/25/Machinesmith.png |
151 | 165 | |
152 | 166 | # quote slashes in the container name |
153 | | - container = "%s%%2F%s" % (match.group(1), match.group(2)) #02 |
| 167 | + container = "%s-%s" % (match.group(1), match.group(2)) #02 |
154 | 168 | obj = match.group(3) |
155 | 169 | # include the thumb in the container. |
156 | 170 | if obj.startswith("thumb/"): #03 |
157 | | - container += "%2Fthumb" |
| 171 | + container += "-thumb" |
158 | 172 | obj = obj[len("thumb/"):] |
159 | 173 | |
160 | 174 | if not obj: |
Index: trunk/extensions/SwiftMedia/SwiftMedia.body.php |
— | — | @@ -28,29 +28,13 @@ |
29 | 29 | * @private |
30 | 30 | */ |
31 | 31 | var |
32 | | - $conn; # our connection to the Swift proxy. |
33 | | - # $fileExists, # does the file file exist on disk? (loadFromXxx) |
34 | | - # $historyLine, # Number of line to return by nextHistoryLine() (constructor) |
35 | | - # $historyRes, # result of the query for the file's history (nextHistoryLine) |
36 | | - # $width, # \ |
37 | | - # $height, # | |
38 | | - # $bits, # --- returned by getimagesize (loadFromXxx) |
39 | | - # $attr, # / |
40 | | - # $media_type, # MEDIATYPE_xxx (bitmap, drawing, audio...) |
41 | | - # $mime, # MIME type, determined by MimeMagic::guessMimeType |
42 | | - # $major_mime, # Major mime type |
43 | | - # $minor_mime, # Minor mime type |
44 | | - # $size, # Size in bytes (loadFromXxx) |
45 | | - # $metadata, # Handler-specific metadata |
46 | | - # $timestamp, # Upload timestamp |
47 | | - # $sha1, # SHA-1 base 36 content hash |
48 | | - # $user, $user_text, # User, who uploaded the file |
49 | | - # $description, # Description of current revision of the file |
50 | | - # $dataLoaded, # Whether or not all this has been loaded from the database (loadFromXxx) |
51 | | - # $upgraded, # Whether the row was upgraded on load |
52 | | - # $locked, # True if the image row is locked |
53 | | - # $missing, # True if file is not present in file system. Not to be cached in memcached |
54 | | - # $deleted; # Bitfield akin to rev_deleted |
| 32 | + $conn, # our connection to the Swift proxy. |
| 33 | + $fileExists, # does the file file exist on disk? (loadFromXxx) |
| 34 | + $dataLoaded, # Whether or not all this has been loaded from the database (loadFromXxx) |
| 35 | + $swiftuser, |
| 36 | + $swiftkey, |
| 37 | + $authurl, |
| 38 | + $container; |
55 | 39 | /**#@-*/ |
56 | 40 | |
57 | 41 | /** |
— | — | @@ -185,7 +169,7 @@ |
186 | 170 | |
187 | 171 | // see if the file exists, and if it exists, is not too old. |
188 | 172 | $conn = $this->repo->connect(); |
189 | | - $container = $this->repo->get_container( $conn, $this->repo->container . '%2Fthumb' ); |
| 173 | + $container = $this->repo->get_container( $conn, $this->repo->container . '-thumb' ); |
190 | 174 | try { |
191 | 175 | $pic = $container->get_object( $this->getRel() . "/$thumbName" ); |
192 | 176 | } catch ( NoSuchObjectException $e ) { |
— | — | @@ -216,7 +200,7 @@ |
217 | 201 | // what if they didn't actually write out a thumbnail? Check the file size. |
218 | 202 | if ( $thumb && file_exists( $thumbPath ) && filesize( $thumbPath ) ) { |
219 | 203 | // Store the thumbnail into Swift, but in the thumb version of the container. |
220 | | - wfDebug( __METHOD__ . 'Creating thumb ' . $this->getRel() . "/$thumbName\n" ); |
| 204 | + wfDebug( __METHOD__ . ': creating thumb ' . $this->getRel() . "/$thumbName\n" ); |
221 | 205 | $this->repo->write_swift_object( $thumbPath, $container, $this->getRel() . "/$thumbName" ); |
222 | 206 | // php-cloudfiles throws exceptions, so failure never gets here. |
223 | 207 | } |
— | — | @@ -264,7 +248,7 @@ |
265 | 249 | $prefix = $this->getRel(); |
266 | 250 | } |
267 | 251 | $conn = $this->repo->connect(); |
268 | | - $container = $this->repo->get_container( $conn, $this->repo->container . '%2Fthumb' ); |
| 252 | + $container = $this->repo->get_container( $conn, $this->repo->container . '-thumb' ); |
269 | 253 | $files = $container->list_objects( 0, NULL, $prefix ); |
270 | 254 | array_unshift( $files, 'unused' ); # return an unused $dir. |
271 | 255 | return $files; |
— | — | @@ -272,14 +256,14 @@ |
273 | 257 | |
274 | 258 | /** |
275 | 259 | * Delete cached transformed files |
276 | | - * @param $dir string If needed for this repo, the directory prefix. |
| 260 | + * @param $dir string Should always be the 'unused' we specified earlier. |
277 | 261 | * @param $files array of strings listing the thumbs to be deleted. |
278 | 262 | */ |
279 | 263 | function purgeThumbList( $dir, $files ) { |
280 | 264 | global $wgExcludeFromThumbnailPurge; |
281 | 265 | |
282 | 266 | $conn = $this->repo->connect(); |
283 | | - $container = $this->repo->get_container( $conn, $this->repo->container . '%2Fthumb' ); |
| 267 | + $container = $this->repo->get_container( $conn, $this->repo->container . '-thumb' ); |
284 | 268 | foreach ( $files as $file ) { |
285 | 269 | // Only remove files not in the $wgExcludeFromThumbnailPurge configuration variable |
286 | 270 | $ext = pathinfo( $file, PATHINFO_EXTENSION ); |
— | — | @@ -544,7 +528,7 @@ |
545 | 529 | function append( $srcPath, $toAppendPath, $flags = 0 ) { |
546 | 530 | // Count the number of files whose names start with $toAppendPath |
547 | 531 | $conn = $this->connect(); |
548 | | - $container = $this->repo->get_container( $conn, $this->repo->container . "%2Ftemp" ); |
| 532 | + $container = $this->repo->get_container( $conn, $this->repo->container . "-temp" ); |
549 | 533 | $nextone = count( $container->list_objects( 0, NULL, $srcPath ) ); |
550 | 534 | |
551 | 535 | // Do the append to the next name |
— | — | @@ -562,7 +546,7 @@ |
563 | 547 | */ |
564 | 548 | function appendFinish( $toAppendPath ) { |
565 | 549 | $conn = $this->connect(); |
566 | | - $container = $this->repo->get_container( $conn, $this->repo->container . '%2Ftemp' ); |
| 550 | + $container = $this->repo->get_container( $conn, $this->repo->container . '-temp' ); |
567 | 551 | $parts = $container->list_objects( 0, NULL, $toAppendPath); |
568 | 552 | // list_objects() returns a sorted list. |
569 | 553 | |
— | — | @@ -671,8 +655,6 @@ |
672 | 656 | throw new MWException( "Missing Content-Type: $e" ); |
673 | 657 | } catch ( MisMatchedChecksumException $e ) { |
674 | 658 | throw new MWException( __METHOD__ . "should not happen: '$e'" ); |
675 | | - # } catch (InvalidResponseException $e ) { |
676 | | - # throw new MWException( __METHOD__ . "unexpected response '$e'" ); |
677 | 659 | } |
678 | 660 | |
679 | 661 | try { |
— | — | @@ -681,16 +663,20 @@ |
682 | 664 | throw new MWException( 'The object we just created does not exist: ' . $dstContainer->name . "/$dstRel: $e" ); |
683 | 665 | } |
684 | 666 | |
| 667 | + try { |
| 668 | + $srcObj = $srcContainer->get_object( $srcRel ); |
| 669 | + } catch ( NoSuchObjectException $e ) { |
| 670 | + throw new MWException( 'Source file does not exist: ' . $srcContainer->name . "/$srcRel: $e" ); |
| 671 | + } |
| 672 | + |
685 | 673 | wfDebug( __METHOD__ . ' copying to ' . $dstContainer->name . "/$dstRel from " . $srcContainer->name . "/$srcRel\n" ); |
686 | 674 | |
687 | 675 | try { |
688 | | - $obj->copy( $srcContainer->name . "/$srcRel" ); |
| 676 | + $dstContainer->copy_object_from($srcObj,$srcContainer,$dstRel); |
689 | 677 | } catch ( SyntaxException $e ) { |
690 | 678 | throw new MWException( 'Source file does not exist: ' . $srcContainer->name . "/$srcRel: $e" ); |
691 | 679 | } catch ( MisMatchedChecksumException $e ) { |
692 | 680 | throw new MWException( "Checksums do not match: $e" ); |
693 | | - # } catch (InvalidResponseException $e ) { |
694 | | - # throw new MWException( __METHOD__ . "unexpected response '$e'" ); |
695 | 681 | } |
696 | 682 | } |
697 | 683 | |
— | — | @@ -875,11 +861,11 @@ |
876 | 862 | case 'public': |
877 | 863 | return $this->container; |
878 | 864 | case 'temp': |
879 | | - return $this->container . '%2Ftemp'; |
| 865 | + return $this->container . '-temp'; |
880 | 866 | case 'deleted': |
881 | | - return $this->container . '%2Fdeleted'; |
| 867 | + return $this->container . '-deleted'; |
882 | 868 | case 'thumb': |
883 | | - return $this->container . '%2Fthumb'; |
| 869 | + return $this->container . '-thumb'; |
884 | 870 | default: |
885 | 871 | return false; |
886 | 872 | } |
Index: trunk/extensions/SwiftMedia/php-cloudfiles/cloudfiles.php |
— | — | @@ -1,2352 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * This is the PHP Cloud Files API. |
5 | | - * |
6 | | - * <code> |
7 | | - * # Authenticate to Cloud Files. The default is to automatically try |
8 | | - * # to re-authenticate if an authentication token expires. |
9 | | - * # |
10 | | - * # NOTE: Some versions of cURL include an outdated certificate authority (CA) |
11 | | - * # file. This API ships with a newer version obtained directly from |
12 | | - * # cURL's web site (http://curl.haxx.se). To use the newer CA bundle, |
13 | | - * # call the CF_Authentication instance's 'ssl_use_cabundle()' method. |
14 | | - * # |
15 | | - * $auth = new CF_Authentication($username, $api_key); |
16 | | - * # $auth->ssl_use_cabundle(); # bypass cURL's old CA bundle |
17 | | - * $auth->authenticate(); |
18 | | - * |
19 | | - * # Establish a connection to the storage system |
20 | | - * # |
21 | | - * # NOTE: Some versions of cURL include an outdated certificate authority (CA) |
22 | | - * # file. This API ships with a newer version obtained directly from |
23 | | - * # cURL's web site (http://curl.haxx.se). To use the newer CA bundle, |
24 | | - * # call the CF_Connection instance's 'ssl_use_cabundle()' method. |
25 | | - * # |
26 | | - * $conn = new CF_Connection($auth); |
27 | | - * # $conn->ssl_use_cabundle(); # bypass cURL's old CA bundle |
28 | | - * |
29 | | - * # Create a remote Container and storage Object |
30 | | - * # |
31 | | - * $images = $conn->create_container("photos"); |
32 | | - * $bday = $images->create_object("first_birthday.jpg"); |
33 | | - * |
34 | | - * # Upload content from a local file by streaming it. Note that we use |
35 | | - * # a "float" for the file size to overcome PHP's 32-bit integer limit for |
36 | | - * # very large files. |
37 | | - * # |
38 | | - * $fname = "/home/user/photos/birthdays/birthday1.jpg"; # filename to upload |
39 | | - * $size = (float) sprintf("%u", filesize($fname)); |
40 | | - * $fp = open($fname, "r"); |
41 | | - * $bday->write($fp, $size); |
42 | | - * |
43 | | - * # Or... use a convenience function instead |
44 | | - * # |
45 | | - * $bday->load_from_filename("/home/user/photos/birthdays/birthday1.jpg"); |
46 | | - * |
47 | | - * # Now, publish the "photos" container to serve the images by CDN. |
48 | | - * # Use the "$uri" value to put in your web pages or send the link in an |
49 | | - * # email message, etc. |
50 | | - * # |
51 | | - * $uri = $images->make_public(); |
52 | | - * |
53 | | - * # Or... print out the Object's public URI |
54 | | - * # |
55 | | - * print $bday->public_uri(); |
56 | | - * </code> |
57 | | - * |
58 | | - * See the included tests directory for additional sample code. |
59 | | - * |
60 | | - * Requres PHP 5.x (for Exceptions and OO syntax) and PHP's cURL module. |
61 | | - * |
62 | | - * It uses the supporting "cloudfiles_http.php" module for HTTP(s) support and |
63 | | - * allows for connection re-use and streaming of content into/out of Cloud Files |
64 | | - * via PHP's cURL module. |
65 | | - * |
66 | | - * See COPYING for license information. |
67 | | - * |
68 | | - * @author Eric "EJ" Johnson <ej@racklabs.com> |
69 | | - * @copyright Copyright (c) 2008, Rackspace US, Inc. |
70 | | - * @package php-cloudfiles |
71 | | - */ |
72 | | - |
73 | | -/** |
74 | | - */ |
75 | | -require_once("cloudfiles_exceptions.php"); |
76 | | -require("cloudfiles_http.php"); |
77 | | -define("DEFAULT_CF_API_VERSION", 1); |
78 | | -define("MAX_CONTAINER_NAME_LEN", 256); |
79 | | -define("MAX_OBJECT_NAME_LEN", 1024); |
80 | | -define("MAX_OBJECT_SIZE", 5*1024*1024*1024+1); |
81 | | -define("US_AUTHURL", "https://auth.api.rackspacecloud.com"); |
82 | | -define("UK_AUTHURL", "https://lon.auth.api.rackspacecloud.com"); |
83 | | -/** |
84 | | - * Class for handling Cloud Files Authentication, call it's {@link authenticate()} |
85 | | - * method to obtain authorized service urls and an authentication token. |
86 | | - * |
87 | | - * Example: |
88 | | - * <code> |
89 | | - * # Create the authentication instance |
90 | | - * # |
91 | | - * $auth = new CF_Authentication("username", "api_key"); |
92 | | - * |
93 | | - * # NOTE: For UK Customers please specify your AuthURL Manually |
94 | | - * # There is a Predfined constant to use EX: |
95 | | - * # |
96 | | - * # $auth = new CF_Authentication("username, "api_key", NULL, UK_AUTHURL); |
97 | | - * # Using the UK_AUTHURL keyword will force the api to use the UK AuthUrl. |
98 | | - * # rather then the US one. The NULL Is passed for legacy purposes and must |
99 | | - * # be passed to function correctly. |
100 | | - * |
101 | | - * # NOTE: Some versions of cURL include an outdated certificate authority (CA) |
102 | | - * # file. This API ships with a newer version obtained directly from |
103 | | - * # cURL's web site (http://curl.haxx.se). To use the newer CA bundle, |
104 | | - * # call the CF_Authentication instance's 'ssl_use_cabundle()' method. |
105 | | - * # |
106 | | - * # $auth->ssl_use_cabundle(); # bypass cURL's old CA bundle |
107 | | - * |
108 | | - * # Perform authentication request |
109 | | - * # |
110 | | - * $auth->authenticate(); |
111 | | - * </code> |
112 | | - * |
113 | | - * @package php-cloudfiles |
114 | | - */ |
115 | | -class CF_Authentication |
116 | | -{ |
117 | | - public $dbug; |
118 | | - public $username; |
119 | | - public $api_key; |
120 | | - public $auth_host; |
121 | | - public $account; |
122 | | - |
123 | | - /** |
124 | | - * Instance variables that are set after successful authentication |
125 | | - */ |
126 | | - public $storage_url; |
127 | | - public $cdnm_url; |
128 | | - public $auth_token; |
129 | | - |
130 | | - /** |
131 | | - * Class constructor (PHP 5 syntax) |
132 | | - * |
133 | | - * @param string $username Mosso username |
134 | | - * @param string $api_key Mosso API Access Key |
135 | | - * @param string $account <i>Account name</i> |
136 | | - * @param string $auth_host <i>Authentication service URI</i> |
137 | | - */ |
138 | | - function __construct($username=NULL, $api_key=NULL, $account=NULL, $auth_host=US_AUTHURL) |
139 | | - { |
140 | | - |
141 | | - $this->dbug = False; |
142 | | - $this->username = $username; |
143 | | - $this->api_key = $api_key; |
144 | | - $this->account_name = $account; |
145 | | - $this->auth_host = $auth_host; |
146 | | - |
147 | | - $this->storage_url = NULL; |
148 | | - $this->cdnm_url = NULL; |
149 | | - $this->auth_token = NULL; |
150 | | - |
151 | | - $this->cfs_http = new CF_Http(DEFAULT_CF_API_VERSION); |
152 | | - } |
153 | | - |
154 | | - /** |
155 | | - * Use the Certificate Authority bundle included with this API |
156 | | - * |
157 | | - * Most versions of PHP with cURL support include an outdated Certificate |
158 | | - * Authority (CA) bundle (the file that lists all valid certificate |
159 | | - * signing authorities). The SSL certificates used by the Cloud Files |
160 | | - * storage system are perfectly valid but have been created/signed by |
161 | | - * a CA not listed in these outdated cURL distributions. |
162 | | - * |
163 | | - * As a work-around, we've included an updated CA bundle obtained |
164 | | - * directly from cURL's web site (http://curl.haxx.se). You can direct |
165 | | - * the API to use this CA bundle by calling this method prior to making |
166 | | - * any remote calls. The best place to use this method is right after |
167 | | - * the CF_Authentication instance has been instantiated. |
168 | | - * |
169 | | - * You can specify your own CA bundle by passing in the full pathname |
170 | | - * to the bundle. You can use the included CA bundle by leaving the |
171 | | - * argument blank. |
172 | | - * |
173 | | - * @param string $path Specify path to CA bundle (default to included) |
174 | | - */ |
175 | | - function ssl_use_cabundle($path=NULL) |
176 | | - { |
177 | | - $this->cfs_http->ssl_use_cabundle($path); |
178 | | - } |
179 | | - |
180 | | - /** |
181 | | - * Attempt to validate Username/API Access Key |
182 | | - * |
183 | | - * Attempts to validate credentials with the authentication service. It |
184 | | - * either returns <kbd>True</kbd> or throws an Exception. Accepts a single |
185 | | - * (optional) argument for the storage system API version. |
186 | | - * |
187 | | - * Example: |
188 | | - * <code> |
189 | | - * # Create the authentication instance |
190 | | - * # |
191 | | - * $auth = new CF_Authentication("username", "api_key"); |
192 | | - * |
193 | | - * # Perform authentication request |
194 | | - * # |
195 | | - * $auth->authenticate(); |
196 | | - * </code> |
197 | | - * |
198 | | - * @param string $version API version for Auth service (optional) |
199 | | - * @return boolean <kbd>True</kbd> if successfully authenticated |
200 | | - * @throws AuthenticationException invalid credentials |
201 | | - * @throws InvalidResponseException invalid response |
202 | | - */ |
203 | | - function authenticate($version=DEFAULT_CF_API_VERSION) |
204 | | - { |
205 | | - list($status,$reason,$surl,$curl,$atoken) = |
206 | | - $this->cfs_http->authenticate($this->username, $this->api_key, |
207 | | - $this->account_name, $this->auth_host); |
208 | | - |
209 | | - if ($status == 401) { |
210 | | - throw new AuthenticationException("Invalid username or access key."); |
211 | | - } |
212 | | - if ($status != 204 && $status != 200) { |
213 | | - throw new InvalidResponseException( |
214 | | - "Unexpected response (".$status."): ".$reason); |
215 | | - } |
216 | | - |
217 | | - if (!($surl || $curl) || !$atoken) { |
218 | | - throw new InvalidResponseException( |
219 | | - "Expected headers missing from auth service."); |
220 | | - } |
221 | | - $this->storage_url = $surl; |
222 | | - $this->cdnm_url = $curl; |
223 | | - $this->auth_token = $atoken; |
224 | | - return True; |
225 | | - } |
226 | | - /** |
227 | | - * Use Cached Token and Storage URL's rather then grabbing from the Auth System |
228 | | - * |
229 | | - * Example: |
230 | | - * <code> |
231 | | - * #Create an Auth instance |
232 | | - * $auth = new CF_Authentication(); |
233 | | - * #Pass Cached URL's and Token as Args |
234 | | - * $auth->load_cached_credentials("auth_token", "storage_url", "cdn_management_url"); |
235 | | - * </code> |
236 | | - * |
237 | | - * @param string $auth_token A Cloud Files Auth Token (Required) |
238 | | - * @param string $storage_url The Cloud Files Storage URL (Required) |
239 | | - * @param string $cdnm_url CDN Management URL (Required) |
240 | | - * @return boolean <kbd>True</kbd> if successful |
241 | | - * @throws SyntaxException If any of the Required Arguments are missing |
242 | | - */ |
243 | | - function load_cached_credentials($auth_token, $storage_url, $cdnm_url) |
244 | | - { |
245 | | - if(!$storage_url || !$cdnm_url) |
246 | | - { |
247 | | - throw new SyntaxException("Missing Required Interface URL's!"); |
248 | | - return False; |
249 | | - } |
250 | | - if(!$auth_token) |
251 | | - { |
252 | | - throw new SyntaxException("Missing Auth Token!"); |
253 | | - return False; |
254 | | - } |
255 | | - |
256 | | - $this->storage_url = $storage_url; |
257 | | - $this->cdnm_url = $cdnm_url; |
258 | | - $this->auth_token = $auth_token; |
259 | | - return True; |
260 | | - } |
261 | | - /** |
262 | | - * Grab Cloud Files info to be Cached for later use with the load_cached_credentials method. |
263 | | - * |
264 | | - * Example: |
265 | | - * <code> |
266 | | - * #Create an Auth instance |
267 | | - * $auth = new CF_Authentication("UserName","API_Key"); |
268 | | - * $auth->authenticate(); |
269 | | - * $array = $auth->export_credentials(); |
270 | | - * </code> |
271 | | - * |
272 | | - * @return array of url's and an auth token. |
273 | | - */ |
274 | | - function export_credentials() |
275 | | - { |
276 | | - $arr = array(); |
277 | | - $arr['storage_url'] = $this->storage_url; |
278 | | - $arr['cdnm_url'] = $this->cdnm_url; |
279 | | - $arr['auth_token'] = $this->auth_token; |
280 | | - |
281 | | - return $arr; |
282 | | - } |
283 | | - |
284 | | - |
285 | | - /** |
286 | | - * Make sure the CF_Authentication instance has authenticated. |
287 | | - * |
288 | | - * Ensures that the instance variables necessary to communicate with |
289 | | - * Cloud Files have been set from a previous authenticate() call. |
290 | | - * |
291 | | - * @return boolean <kbd>True</kbd> if successfully authenticated |
292 | | - */ |
293 | | - function authenticated() |
294 | | - { |
295 | | - if (!($this->storage_url || $this->cdnm_url) || !$this->auth_token) { |
296 | | - return False; |
297 | | - } |
298 | | - return True; |
299 | | - } |
300 | | - |
301 | | - /** |
302 | | - * Toggle debugging - set cURL verbose flag |
303 | | - */ |
304 | | - function setDebug($bool) |
305 | | - { |
306 | | - $this->dbug = $bool; |
307 | | - $this->cfs_http->setDebug($bool); |
308 | | - } |
309 | | -} |
310 | | - |
311 | | -/** |
312 | | - * Class for establishing connections to the Cloud Files storage system. |
313 | | - * Connection instances are used to communicate with the storage system at |
314 | | - * the account level; listing and deleting Containers and returning Container |
315 | | - * instances. |
316 | | - * |
317 | | - * Example: |
318 | | - * <code> |
319 | | - * # Create the authentication instance |
320 | | - * # |
321 | | - * $auth = new CF_Authentication("username", "api_key"); |
322 | | - * |
323 | | - * # Perform authentication request |
324 | | - * # |
325 | | - * $auth->authenticate(); |
326 | | - * |
327 | | - * # Create a connection to the storage/cdn system(s) and pass in the |
328 | | - * # validated CF_Authentication instance. |
329 | | - * # |
330 | | - * $conn = new CF_Connection($auth); |
331 | | - * |
332 | | - * # NOTE: Some versions of cURL include an outdated certificate authority (CA) |
333 | | - * # file. This API ships with a newer version obtained directly from |
334 | | - * # cURL's web site (http://curl.haxx.se). To use the newer CA bundle, |
335 | | - * # call the CF_Authentication instance's 'ssl_use_cabundle()' method. |
336 | | - * # |
337 | | - * # $conn->ssl_use_cabundle(); # bypass cURL's old CA bundle |
338 | | - * </code> |
339 | | - * |
340 | | - * @package php-cloudfiles |
341 | | - */ |
342 | | -class CF_Connection |
343 | | -{ |
344 | | - public $dbug; |
345 | | - public $cfs_http; |
346 | | - public $cfs_auth; |
347 | | - |
348 | | - /** |
349 | | - * Pass in a previously authenticated CF_Authentication instance. |
350 | | - * |
351 | | - * Example: |
352 | | - * <code> |
353 | | - * # Create the authentication instance |
354 | | - * # |
355 | | - * $auth = new CF_Authentication("username", "api_key"); |
356 | | - * |
357 | | - * # Perform authentication request |
358 | | - * # |
359 | | - * $auth->authenticate(); |
360 | | - * |
361 | | - * # Create a connection to the storage/cdn system(s) and pass in the |
362 | | - * # validated CF_Authentication instance. |
363 | | - * # |
364 | | - * $conn = new CF_Connection($auth); |
365 | | - * |
366 | | - * # If you are connecting via Rackspace servers and have access |
367 | | - * # to the servicenet network you can set the $servicenet to True |
368 | | - * # like this. |
369 | | - * |
370 | | - * $conn = new CF_Connection($auth, $servicenet=True); |
371 | | - * |
372 | | - * </code> |
373 | | - * |
374 | | - * If the environement variable RACKSPACE_SERVICENET is defined it will |
375 | | - * force to connect via the servicenet. |
376 | | - * |
377 | | - * @param obj $cfs_auth previously authenticated CF_Authentication instance |
378 | | - * @param boolean $servicenet enable/disable access via Rackspace servicenet. |
379 | | - * @throws AuthenticationException not authenticated |
380 | | - */ |
381 | | - function __construct($cfs_auth, $servicenet=False) |
382 | | - { |
383 | | - if (isset($_ENV['RACKSPACE_SERVICENET'])) |
384 | | - $servicenet=True; |
385 | | - $this->cfs_http = new CF_Http(DEFAULT_CF_API_VERSION); |
386 | | - $this->cfs_auth = $cfs_auth; |
387 | | - if (!$this->cfs_auth->authenticated()) { |
388 | | - $e = "Need to pass in a previously authenticated "; |
389 | | - $e .= "CF_Authentication instance."; |
390 | | - throw new AuthenticationException($e); |
391 | | - } |
392 | | - $this->cfs_http->setCFAuth($this->cfs_auth, $servicenet=$servicenet); |
393 | | - $this->dbug = False; |
394 | | - } |
395 | | - |
396 | | - /** |
397 | | - * Toggle debugging of instance and back-end HTTP module |
398 | | - * |
399 | | - * @param boolean $bool enable/disable cURL debugging |
400 | | - */ |
401 | | - function setDebug($bool) |
402 | | - { |
403 | | - $this->dbug = (boolean) $bool; |
404 | | - $this->cfs_http->setDebug($this->dbug); |
405 | | - } |
406 | | - |
407 | | - /** |
408 | | - * Close a connection |
409 | | - * |
410 | | - * Example: |
411 | | - * <code> |
412 | | - * |
413 | | - * $conn->close(); |
414 | | - * |
415 | | - * </code> |
416 | | - * |
417 | | - * Will close all current cUrl active connections. |
418 | | - * |
419 | | - */ |
420 | | - public function close() |
421 | | - { |
422 | | - $this->cfs_http->close(); |
423 | | - } |
424 | | - |
425 | | - /** |
426 | | - * Cloud Files account information |
427 | | - * |
428 | | - * Return an array of two floats (since PHP only supports 32-bit integers); |
429 | | - * number of containers on the account and total bytes used for the account. |
430 | | - * |
431 | | - * Example: |
432 | | - * <code> |
433 | | - * # ... authentication code excluded (see previous examples) ... |
434 | | - * # |
435 | | - * $conn = new CF_Authentication($auth); |
436 | | - * |
437 | | - * list($quantity, $bytes) = $conn->get_info(); |
438 | | - * print "Number of containers: " . $quantity . "\n"; |
439 | | - * print "Bytes stored in container: " . $bytes . "\n"; |
440 | | - * </code> |
441 | | - * |
442 | | - * @return array (number of containers, total bytes stored) |
443 | | - * @throws InvalidResponseException unexpected response |
444 | | - */ |
445 | | - function get_info() |
446 | | - { |
447 | | - list($status, $reason, $container_count, $total_bytes) = |
448 | | - $this->cfs_http->head_account(); |
449 | | - #if ($status == 401 && $this->_re_auth()) { |
450 | | - # return $this->get_info(); |
451 | | - #} |
452 | | - if ($status < 200 || $status > 299) { |
453 | | - throw new InvalidResponseException( |
454 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
455 | | - } |
456 | | - return array($container_count, $total_bytes); |
457 | | - } |
458 | | - |
459 | | - /** |
460 | | - * Create a Container |
461 | | - * |
462 | | - * Given a Container name, return a Container instance, creating a new |
463 | | - * remote Container if it does not exit. |
464 | | - * |
465 | | - * Example: |
466 | | - * <code> |
467 | | - * # ... authentication code excluded (see previous examples) ... |
468 | | - * # |
469 | | - * $conn = new CF_Authentication($auth); |
470 | | - * |
471 | | - * $images = $conn->create_container("my photos"); |
472 | | - * </code> |
473 | | - * |
474 | | - * @param string $container_name container name |
475 | | - * @return CF_Container |
476 | | - * @throws SyntaxException invalid name |
477 | | - * @throws InvalidResponseException unexpected response |
478 | | - */ |
479 | | - function create_container($container_name=NULL) |
480 | | - { |
481 | | - if ($container_name != "0" and !isset($container_name)) |
482 | | - throw new SyntaxException("Container name not set."); |
483 | | - |
484 | | - if (!isset($container_name) or $container_name == "") |
485 | | - throw new SyntaxException("Container name not set."); |
486 | | - |
487 | | - if (strpos($container_name, "/") !== False) { |
488 | | - $r = "Container name '".$container_name; |
489 | | - $r .= "' cannot contain a '/' character."; |
490 | | - throw new SyntaxException($r); |
491 | | - } |
492 | | - if (strlen($container_name) > MAX_CONTAINER_NAME_LEN) { |
493 | | - throw new SyntaxException(sprintf( |
494 | | - "Container name exeeds %d bytes.", |
495 | | - MAX_CONTAINER_NAME_LEN)); |
496 | | - } |
497 | | - |
498 | | - $return_code = $this->cfs_http->create_container($container_name); |
499 | | - if (!$return_code) { |
500 | | - throw new InvalidResponseException("Invalid response (" |
501 | | - . $return_code. "): " . $this->cfs_http->get_error()); |
502 | | - } |
503 | | - #if ($status == 401 && $this->_re_auth()) { |
504 | | - # return $this->create_container($container_name); |
505 | | - #} |
506 | | - if ($return_code != 201 && $return_code != 202) { |
507 | | - throw new InvalidResponseException( |
508 | | - "Invalid response (".$return_code."): " |
509 | | - . $this->cfs_http->get_error()); |
510 | | - } |
511 | | - return new CF_Container($this->cfs_auth, $this->cfs_http, $container_name); |
512 | | - } |
513 | | - |
514 | | - /** |
515 | | - * Delete a Container |
516 | | - * |
517 | | - * Given either a Container instance or name, remove the remote Container. |
518 | | - * The Container must be empty prior to removing it. |
519 | | - * |
520 | | - * Example: |
521 | | - * <code> |
522 | | - * # ... authentication code excluded (see previous examples) ... |
523 | | - * # |
524 | | - * $conn = new CF_Authentication($auth); |
525 | | - * |
526 | | - * $conn->delete_container("my photos"); |
527 | | - * </code> |
528 | | - * |
529 | | - * @param string|obj $container container name or instance |
530 | | - * @return boolean <kbd>True</kbd> if successfully deleted |
531 | | - * @throws SyntaxException missing proper argument |
532 | | - * @throws InvalidResponseException invalid response |
533 | | - * @throws NonEmptyContainerException container not empty |
534 | | - * @throws NoSuchContainerException remote container does not exist |
535 | | - */ |
536 | | - function delete_container($container=NULL) |
537 | | - { |
538 | | - $container_name = NULL; |
539 | | - |
540 | | - if (is_object($container)) { |
541 | | - if (get_class($container) == "CF_Container") { |
542 | | - $container_name = $container->name; |
543 | | - } |
544 | | - } |
545 | | - if (is_string($container)) { |
546 | | - $container_name = $container; |
547 | | - } |
548 | | - |
549 | | - if ($container_name != "0" and !isset($container_name)) |
550 | | - throw new SyntaxException("Must specify container object or name."); |
551 | | - |
552 | | - $return_code = $this->cfs_http->delete_container($container_name); |
553 | | - |
554 | | - if (!$return_code) { |
555 | | - throw new InvalidResponseException("Failed to obtain http response"); |
556 | | - } |
557 | | - #if ($status == 401 && $this->_re_auth()) { |
558 | | - # return $this->delete_container($container); |
559 | | - #} |
560 | | - if ($return_code == 409) { |
561 | | - throw new NonEmptyContainerException( |
562 | | - "Container must be empty prior to removing it."); |
563 | | - } |
564 | | - if ($return_code == 404) { |
565 | | - throw new NoSuchContainerException( |
566 | | - "Specified container did not exist to delete."); |
567 | | - } |
568 | | - if ($return_code != 204) { |
569 | | - throw new InvalidResponseException( |
570 | | - "Invalid response (".$return_code."): " |
571 | | - . $this->cfs_http->get_error()); |
572 | | - } |
573 | | - return True; |
574 | | - } |
575 | | - |
576 | | - /** |
577 | | - * Return a Container instance |
578 | | - * |
579 | | - * For the given name, return a Container instance if the remote Container |
580 | | - * exists, otherwise throw a Not Found exception. |
581 | | - * |
582 | | - * Example: |
583 | | - * <code> |
584 | | - * # ... authentication code excluded (see previous examples) ... |
585 | | - * # |
586 | | - * $conn = new CF_Authentication($auth); |
587 | | - * |
588 | | - * $images = $conn->get_container("my photos"); |
589 | | - * print "Number of Objects: " . $images->count . "\n"; |
590 | | - * print "Bytes stored in container: " . $images->bytes . "\n"; |
591 | | - * </code> |
592 | | - * |
593 | | - * @param string $container_name name of the remote Container |
594 | | - * @return container CF_Container instance |
595 | | - * @throws NoSuchContainerException thrown if no remote Container |
596 | | - * @throws InvalidResponseException unexpected response |
597 | | - */ |
598 | | - function get_container($container_name=NULL) |
599 | | - { |
600 | | - list($status, $reason, $count, $bytes) = |
601 | | - $this->cfs_http->head_container($container_name); |
602 | | - #if ($status == 401 && $this->_re_auth()) { |
603 | | - # return $this->get_container($container_name); |
604 | | - #} |
605 | | - if ($status == 404) { |
606 | | - throw new NoSuchContainerException("Container not found."); |
607 | | - } |
608 | | - if ($status < 200 || $status > 299) { |
609 | | - throw new InvalidResponseException( |
610 | | - "Invalid response: ".$this->cfs_http->get_error()); |
611 | | - } |
612 | | - return new CF_Container($this->cfs_auth, $this->cfs_http, |
613 | | - $container_name, $count, $bytes); |
614 | | - } |
615 | | - |
616 | | - /** |
617 | | - * Return array of Container instances |
618 | | - * |
619 | | - * Return an array of CF_Container instances on the account. The instances |
620 | | - * will be fully populated with Container attributes (bytes stored and |
621 | | - * Object count) |
622 | | - * |
623 | | - * Example: |
624 | | - * <code> |
625 | | - * # ... authentication code excluded (see previous examples) ... |
626 | | - * # |
627 | | - * $conn = new CF_Authentication($auth); |
628 | | - * |
629 | | - * $clist = $conn->get_containers(); |
630 | | - * foreach ($clist as $cont) { |
631 | | - * print "Container name: " . $cont->name . "\n"; |
632 | | - * print "Number of Objects: " . $cont->count . "\n"; |
633 | | - * print "Bytes stored in container: " . $cont->bytes . "\n"; |
634 | | - * } |
635 | | - * </code> |
636 | | - * |
637 | | - * @return array An array of CF_Container instances |
638 | | - * @throws InvalidResponseException unexpected response |
639 | | - */ |
640 | | - function get_containers($limit=0, $marker=NULL) |
641 | | - { |
642 | | - list($status, $reason, $container_info) = |
643 | | - $this->cfs_http->list_containers_info($limit, $marker); |
644 | | - #if ($status == 401 && $this->_re_auth()) { |
645 | | - # return $this->get_containers(); |
646 | | - #} |
647 | | - if ($status < 200 || $status > 299) { |
648 | | - throw new InvalidResponseException( |
649 | | - "Invalid response: ".$this->cfs_http->get_error()); |
650 | | - } |
651 | | - $containers = array(); |
652 | | - foreach ($container_info as $name => $info) { |
653 | | - $containers[] = new CF_Container($this->cfs_auth, $this->cfs_http, |
654 | | - $info['name'], $info["count"], $info["bytes"], False); |
655 | | - } |
656 | | - return $containers; |
657 | | - } |
658 | | - |
659 | | - /** |
660 | | - * Return list of remote Containers |
661 | | - * |
662 | | - * Return an array of strings containing the names of all remote Containers. |
663 | | - * |
664 | | - * Example: |
665 | | - * <code> |
666 | | - * # ... authentication code excluded (see previous examples) ... |
667 | | - * # |
668 | | - * $conn = new CF_Authentication($auth); |
669 | | - * |
670 | | - * $container_list = $conn->list_containers(); |
671 | | - * print_r($container_list); |
672 | | - * Array |
673 | | - * ( |
674 | | - * [0] => "my photos", |
675 | | - * [1] => "my docs" |
676 | | - * ) |
677 | | - * </code> |
678 | | - * |
679 | | - * @param integer $limit restrict results to $limit Containers |
680 | | - * @param string $marker return results greater than $marker |
681 | | - * @return array list of remote Containers |
682 | | - * @throws InvalidResponseException unexpected response |
683 | | - */ |
684 | | - function list_containers($limit=0, $marker=NULL) |
685 | | - { |
686 | | - list($status, $reason, $containers) = |
687 | | - $this->cfs_http->list_containers($limit, $marker); |
688 | | - #if ($status == 401 && $this->_re_auth()) { |
689 | | - # return $this->list_containers($limit, $marker); |
690 | | - #} |
691 | | - if ($status < 200 || $status > 299) { |
692 | | - throw new InvalidResponseException( |
693 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
694 | | - } |
695 | | - return $containers; |
696 | | - } |
697 | | - |
698 | | - /** |
699 | | - * Return array of information about remote Containers |
700 | | - * |
701 | | - * Return a nested array structure of Container info. |
702 | | - * |
703 | | - * Example: |
704 | | - * <code> |
705 | | - * # ... authentication code excluded (see previous examples) ... |
706 | | - * # |
707 | | - * |
708 | | - * $container_info = $conn->list_containers_info(); |
709 | | - * print_r($container_info); |
710 | | - * Array |
711 | | - * ( |
712 | | - * ["my photos"] => |
713 | | - * Array |
714 | | - * ( |
715 | | - * ["bytes"] => 78, |
716 | | - * ["count"] => 2 |
717 | | - * ) |
718 | | - * ["docs"] => |
719 | | - * Array |
720 | | - * ( |
721 | | - * ["bytes"] => 37323, |
722 | | - * ["count"] => 12 |
723 | | - * ) |
724 | | - * ) |
725 | | - * </code> |
726 | | - * |
727 | | - * @param integer $limit restrict results to $limit Containers |
728 | | - * @param string $marker return results greater than $marker |
729 | | - * @return array nested array structure of Container info |
730 | | - * @throws InvalidResponseException unexpected response |
731 | | - */ |
732 | | - function list_containers_info($limit=0, $marker=NULL) |
733 | | - { |
734 | | - list($status, $reason, $container_info) = |
735 | | - $this->cfs_http->list_containers_info($limit, $marker); |
736 | | - #if ($status == 401 && $this->_re_auth()) { |
737 | | - # return $this->list_containers_info($limit, $marker); |
738 | | - #} |
739 | | - if ($status < 200 || $status > 299) { |
740 | | - throw new InvalidResponseException( |
741 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
742 | | - } |
743 | | - return $container_info; |
744 | | - } |
745 | | - |
746 | | - /** |
747 | | - * Return list of Containers that have been published to the CDN. |
748 | | - * |
749 | | - * Return an array of strings containing the names of published Containers. |
750 | | - * Note that this function returns the list of any Container that has |
751 | | - * ever been CDN-enabled regardless of it's existence in the storage |
752 | | - * system. |
753 | | - * |
754 | | - * Example: |
755 | | - * <code> |
756 | | - * # ... authentication code excluded (see previous examples) ... |
757 | | - * # |
758 | | - * $conn = new CF_Authentication($auth); |
759 | | - * |
760 | | - * $public_containers = $conn->list_public_containers(); |
761 | | - * print_r($public_containers); |
762 | | - * Array |
763 | | - * ( |
764 | | - * [0] => "images", |
765 | | - * [1] => "css", |
766 | | - * [2] => "javascript" |
767 | | - * ) |
768 | | - * </code> |
769 | | - * |
770 | | - * @param bool $enabled_only Will list all containers ever CDN enabled if * set to false or only currently enabled CDN containers if set to true. * Defaults to false. |
771 | | - * @return array list of published Container names |
772 | | - * @throws InvalidResponseException unexpected response |
773 | | - */ |
774 | | - function list_public_containers($enabled_only=False) |
775 | | - { |
776 | | - list($status, $reason, $containers) = |
777 | | - $this->cfs_http->list_cdn_containers($enabled_only); |
778 | | - #if ($status == 401 && $this->_re_auth()) { |
779 | | - # return $this->list_public_containers(); |
780 | | - #} |
781 | | - if ($status < 200 || $status > 299) { |
782 | | - throw new InvalidResponseException( |
783 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
784 | | - } |
785 | | - return $containers; |
786 | | - } |
787 | | - |
788 | | - /** |
789 | | - * Set a user-supplied callback function to report download progress |
790 | | - * |
791 | | - * The callback function is used to report incremental progress of a data |
792 | | - * download functions (e.g. $container->list_objects(), $obj->read(), etc). |
793 | | - * The specified function will be periodically called with the number of |
794 | | - * bytes transferred until the entire download is complete. This callback |
795 | | - * function can be useful for implementing "progress bars" for large |
796 | | - * downloads. |
797 | | - * |
798 | | - * The specified callback function should take a single integer parameter. |
799 | | - * |
800 | | - * <code> |
801 | | - * function read_callback($bytes_transferred) { |
802 | | - * print ">> downloaded " . $bytes_transferred . " bytes.\n"; |
803 | | - * # ... do other things ... |
804 | | - * return; |
805 | | - * } |
806 | | - * |
807 | | - * $conn = new CF_Connection($auth_obj); |
808 | | - * $conn->set_read_progress_function("read_callback"); |
809 | | - * print_r($conn->list_containers()); |
810 | | - * |
811 | | - * # output would look like this: |
812 | | - * # |
813 | | - * >> downloaded 10 bytes. |
814 | | - * >> downloaded 11 bytes. |
815 | | - * Array |
816 | | - * ( |
817 | | - * [0] => fuzzy.txt |
818 | | - * [1] => space name |
819 | | - * ) |
820 | | - * </code> |
821 | | - * |
822 | | - * @param string $func_name the name of the user callback function |
823 | | - */ |
824 | | - function set_read_progress_function($func_name) |
825 | | - { |
826 | | - $this->cfs_http->setReadProgressFunc($func_name); |
827 | | - } |
828 | | - |
829 | | - /** |
830 | | - * Set a user-supplied callback function to report upload progress |
831 | | - * |
832 | | - * The callback function is used to report incremental progress of a data |
833 | | - * upload functions (e.g. $obj->write() call). The specified function will |
834 | | - * be periodically called with the number of bytes transferred until the |
835 | | - * entire upload is complete. This callback function can be useful |
836 | | - * for implementing "progress bars" for large uploads/downloads. |
837 | | - * |
838 | | - * The specified callback function should take a single integer parameter. |
839 | | - * |
840 | | - * <code> |
841 | | - * function write_callback($bytes_transferred) { |
842 | | - * print ">> uploaded " . $bytes_transferred . " bytes.\n"; |
843 | | - * # ... do other things ... |
844 | | - * return; |
845 | | - * } |
846 | | - * |
847 | | - * $conn = new CF_Connection($auth_obj); |
848 | | - * $conn->set_write_progress_function("write_callback"); |
849 | | - * $container = $conn->create_container("stuff"); |
850 | | - * $obj = $container->create_object("foo"); |
851 | | - * $obj->write("The callback function will be called during upload."); |
852 | | - * |
853 | | - * # output would look like this: |
854 | | - * # >> uploaded 51 bytes. |
855 | | - * # |
856 | | - * </code> |
857 | | - * |
858 | | - * @param string $func_name the name of the user callback function |
859 | | - */ |
860 | | - function set_write_progress_function($func_name) |
861 | | - { |
862 | | - $this->cfs_http->setWriteProgressFunc($func_name); |
863 | | - } |
864 | | - |
865 | | - /** |
866 | | - * Use the Certificate Authority bundle included with this API |
867 | | - * |
868 | | - * Most versions of PHP with cURL support include an outdated Certificate |
869 | | - * Authority (CA) bundle (the file that lists all valid certificate |
870 | | - * signing authorities). The SSL certificates used by the Cloud Files |
871 | | - * storage system are perfectly valid but have been created/signed by |
872 | | - * a CA not listed in these outdated cURL distributions. |
873 | | - * |
874 | | - * As a work-around, we've included an updated CA bundle obtained |
875 | | - * directly from cURL's web site (http://curl.haxx.se). You can direct |
876 | | - * the API to use this CA bundle by calling this method prior to making |
877 | | - * any remote calls. The best place to use this method is right after |
878 | | - * the CF_Authentication instance has been instantiated. |
879 | | - * |
880 | | - * You can specify your own CA bundle by passing in the full pathname |
881 | | - * to the bundle. You can use the included CA bundle by leaving the |
882 | | - * argument blank. |
883 | | - * |
884 | | - * @param string $path Specify path to CA bundle (default to included) |
885 | | - */ |
886 | | - function ssl_use_cabundle($path=NULL) |
887 | | - { |
888 | | - $this->cfs_http->ssl_use_cabundle($path); |
889 | | - } |
890 | | - |
891 | | - #private function _re_auth() |
892 | | - #{ |
893 | | - # $new_auth = new CF_Authentication( |
894 | | - # $this->cfs_auth->username, |
895 | | - # $this->cfs_auth->api_key, |
896 | | - # $this->cfs_auth->auth_host, |
897 | | - # $this->cfs_auth->account); |
898 | | - # $new_auth->authenticate(); |
899 | | - # $this->cfs_auth = $new_auth; |
900 | | - # $this->cfs_http->setCFAuth($this->cfs_auth); |
901 | | - # return True; |
902 | | - #} |
903 | | -} |
904 | | - |
905 | | -/** |
906 | | - * Container operations |
907 | | - * |
908 | | - * Containers are storage compartments where you put your data (objects). |
909 | | - * A container is similar to a directory or folder on a conventional filesystem |
910 | | - * with the exception that they exist in a flat namespace, you can not create |
911 | | - * containers inside of containers. |
912 | | - * |
913 | | - * You also have the option of marking a Container as "public" so that the |
914 | | - * Objects stored in the Container are publicly available via the CDN. |
915 | | - * |
916 | | - * @package php-cloudfiles |
917 | | - */ |
918 | | -class CF_Container |
919 | | -{ |
920 | | - public $cfs_auth; |
921 | | - public $cfs_http; |
922 | | - public $name; |
923 | | - public $object_count; |
924 | | - public $bytes_used; |
925 | | - |
926 | | - public $cdn_enabled; |
927 | | - public $cdn_ssl_uri; |
928 | | - public $cdn_uri; |
929 | | - public $cdn_ttl; |
930 | | - public $cdn_log_retention; |
931 | | - public $cdn_acl_user_agent; |
932 | | - public $cdn_acl_referrer; |
933 | | - |
934 | | - /** |
935 | | - * Class constructor |
936 | | - * |
937 | | - * Constructor for Container |
938 | | - * |
939 | | - * @param obj $cfs_auth CF_Authentication instance |
940 | | - * @param obj $cfs_http HTTP connection manager |
941 | | - * @param string $name name of Container |
942 | | - * @param int $count number of Objects stored in this Container |
943 | | - * @param int $bytes number of bytes stored in this Container |
944 | | - * @throws SyntaxException invalid Container name |
945 | | - */ |
946 | | - function __construct(&$cfs_auth, &$cfs_http, $name, $count=0, |
947 | | - $bytes=0, $docdn=True) |
948 | | - { |
949 | | - if (strlen($name) > MAX_CONTAINER_NAME_LEN) { |
950 | | - throw new SyntaxException("Container name exceeds " |
951 | | - . "maximum allowed length."); |
952 | | - } |
953 | | - if (strpos($name, "/") !== False) { |
954 | | - throw new SyntaxException( |
955 | | - "Container names cannot contain a '/' character."); |
956 | | - } |
957 | | - $this->cfs_auth = $cfs_auth; |
958 | | - $this->cfs_http = $cfs_http; |
959 | | - $this->name = $name; |
960 | | - $this->object_count = $count; |
961 | | - $this->bytes_used = $bytes; |
962 | | - $this->cdn_enabled = NULL; |
963 | | - $this->cdn_uri = NULL; |
964 | | - $this->cdn_ssl_uri = NULL; |
965 | | - $this->cdn_ttl = NULL; |
966 | | - $this->cdn_log_retention = NULL; |
967 | | - $this->cdn_acl_user_agent = NULL; |
968 | | - $this->cdn_acl_referrer = NULL; |
969 | | - if ($this->cfs_http->getCDNMUrl() != NULL && $docdn) { |
970 | | - $this->_cdn_initialize(); |
971 | | - } |
972 | | - } |
973 | | - |
974 | | - /** |
975 | | - * String representation of Container |
976 | | - * |
977 | | - * Pretty print the Container instance. |
978 | | - * |
979 | | - * @return string Container details |
980 | | - */ |
981 | | - function __toString() |
982 | | - { |
983 | | - $me = sprintf("name: %s, count: %.0f, bytes: %.0f", |
984 | | - $this->name, $this->object_count, $this->bytes_used); |
985 | | - if ($this->cfs_http->getCDNMUrl() != NULL) { |
986 | | - $me .= sprintf(", cdn: %s, cdn uri: %s, cdn ttl: %.0f, logs retention: %s", |
987 | | - $this->is_public() ? "Yes" : "No", |
988 | | - $this->cdn_uri, $this->cdn_ttl, |
989 | | - $this->cdn_log_retention ? "Yes" : "No" |
990 | | - ); |
991 | | - |
992 | | - if ($this->cdn_acl_user_agent != NULL) { |
993 | | - $me .= ", cdn acl user agent: " . $this->cdn_acl_user_agent; |
994 | | - } |
995 | | - |
996 | | - if ($this->cdn_acl_referrer != NULL) { |
997 | | - $me .= ", cdn acl referrer: " . $this->cdn_acl_referrer; |
998 | | - } |
999 | | - |
1000 | | - |
1001 | | - } |
1002 | | - return $me; |
1003 | | - } |
1004 | | - |
1005 | | - /** |
1006 | | - * Enable Container content to be served via CDN or modify CDN attributes |
1007 | | - * |
1008 | | - * Either enable this Container's content to be served via CDN or |
1009 | | - * adjust its CDN attributes. This Container will always return the |
1010 | | - * same CDN-enabled URI each time it is toggled public/private/public. |
1011 | | - * |
1012 | | - * Example: |
1013 | | - * <code> |
1014 | | - * # ... authentication code excluded (see previous examples) ... |
1015 | | - * # |
1016 | | - * $conn = new CF_Authentication($auth); |
1017 | | - * |
1018 | | - * $public_container = $conn->create_container("public"); |
1019 | | - * |
1020 | | - * # CDN-enable the container and set it's TTL for a month |
1021 | | - * # |
1022 | | - * $public_container->make_public(86400/2); # 12 hours (86400 seconds/day) |
1023 | | - * </code> |
1024 | | - * |
1025 | | - * @param int $ttl the time in seconds content will be cached in the CDN |
1026 | | - * @returns string the CDN enabled Container's URI |
1027 | | - * @throws CDNNotEnabledException CDN functionality not returned during auth |
1028 | | - * @throws AuthenticationException if auth token is not valid/expired |
1029 | | - * @throws InvalidResponseException unexpected response |
1030 | | - */ |
1031 | | - function make_public($ttl=86400) |
1032 | | - { |
1033 | | - if ($this->cfs_http->getCDNMUrl() == NULL) { |
1034 | | - throw new CDNNotEnabledException( |
1035 | | - "Authentication response did not indicate CDN availability"); |
1036 | | - } |
1037 | | - if ($this->cdn_uri != NULL) { |
1038 | | - # previously published, assume we're setting new attributes |
1039 | | - list($status, $reason, $cdn_uri, $cdn_ssl_uri) = |
1040 | | - $this->cfs_http->update_cdn_container($this->name,$ttl, |
1041 | | - $this->cdn_log_retention, |
1042 | | - $this->cdn_acl_user_agent, |
1043 | | - $this->cdn_acl_referrer); |
1044 | | - #if ($status == 401 && $this->_re_auth()) { |
1045 | | - # return $this->make_public($ttl); |
1046 | | - #} |
1047 | | - if ($status == 404) { |
1048 | | - # this instance _thinks_ the container was published, but the |
1049 | | - # cdn management system thinks otherwise - try again with a PUT |
1050 | | - list($status, $reason, $cdn_uri, $cdn_ssl_uri) = |
1051 | | - $this->cfs_http->add_cdn_container($this->name,$ttl); |
1052 | | - |
1053 | | - } |
1054 | | - } else { |
1055 | | - # publish it for first time |
1056 | | - list($status, $reason, $cdn_uri, $cdn_ssl_uri) = |
1057 | | - $this->cfs_http->add_cdn_container($this->name,$ttl); |
1058 | | - } |
1059 | | - #if ($status == 401 && $this->_re_auth()) { |
1060 | | - # return $this->make_public($ttl); |
1061 | | - #} |
1062 | | - if (!in_array($status, array(201,202))) { |
1063 | | - throw new InvalidResponseException( |
1064 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
1065 | | - } |
1066 | | - $this->cdn_enabled = True; |
1067 | | - $this->cdn_ttl = $ttl; |
1068 | | - $this->cdn_ssl_uri = $cdn_ssl_uri; |
1069 | | - $this->cdn_uri = $cdn_uri; |
1070 | | - $this->cdn_log_retention = False; |
1071 | | - $this->cdn_acl_user_agent = ""; |
1072 | | - $this->cdn_acl_referrer = ""; |
1073 | | - return $this->cdn_uri; |
1074 | | - } |
1075 | | - /** |
1076 | | - * Purge Containers objects from CDN Cache. |
1077 | | - * Example: |
1078 | | - * <code> |
1079 | | - * # ... authentication code excluded (see previous examples) ... |
1080 | | - * # |
1081 | | - * $conn = new CF_Authentication($auth); |
1082 | | - * $container = $conn->get_container("cdn_enabled"); |
1083 | | - * $container->purge_from_cdn("user@domain.com"); |
1084 | | - * # or |
1085 | | - * $container->purge_from_cdn(); |
1086 | | - * # or |
1087 | | - * $container->purge_from_cdn("user1@domain.com,user2@domain.com"); |
1088 | | - * @returns boolean True if successful |
1089 | | - * @throws CDNNotEnabledException if CDN Is not enabled on this connection |
1090 | | - * @throws InvalidResponseException if the response expected is not returned |
1091 | | - */ |
1092 | | - function purge_from_cdn($email=null) |
1093 | | - { |
1094 | | - if (!$this->cfs_http->getCDNMUrl()) |
1095 | | - { |
1096 | | - throw new CDNNotEnabledException( |
1097 | | - "Authentication response did not indicate CDN availability"); |
1098 | | - } |
1099 | | - $status = $this->cfs_http->purge_from_cdn($this->name, $email); |
1100 | | - if ($status < 199 or $status > 299) { |
1101 | | - throw new InvalidResponseException( |
1102 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
1103 | | - } |
1104 | | - return True; |
1105 | | - } |
1106 | | - /** |
1107 | | - * Enable ACL restriction by User Agent for this container. |
1108 | | - * |
1109 | | - * Example: |
1110 | | - * <code> |
1111 | | - * # ... authentication code excluded (see previous examples) ... |
1112 | | - * # |
1113 | | - * $conn = new CF_Authentication($auth); |
1114 | | - * |
1115 | | - * $public_container = $conn->get_container("public"); |
1116 | | - * |
1117 | | - * # Enable ACL by Referrer |
1118 | | - * $public_container->acl_referrer("Mozilla"); |
1119 | | - * </code> |
1120 | | - * |
1121 | | - * @returns boolean True if successful |
1122 | | - * @throws CDNNotEnabledException CDN functionality not returned during auth |
1123 | | - * @throws AuthenticationException if auth token is not valid/expired |
1124 | | - * @throws InvalidResponseException unexpected response |
1125 | | - */ |
1126 | | - function acl_user_agent($cdn_acl_user_agent="") { |
1127 | | - if ($this->cfs_http->getCDNMUrl() == NULL) { |
1128 | | - throw new CDNNotEnabledException( |
1129 | | - "Authentication response did not indicate CDN availability"); |
1130 | | - } |
1131 | | - list($status,$reason) = |
1132 | | - $this->cfs_http->update_cdn_container($this->name, |
1133 | | - $this->cdn_ttl, |
1134 | | - $this->cdn_log_retention, |
1135 | | - $cdn_acl_user_agent, |
1136 | | - $this->cdn_acl_referrer |
1137 | | - ); |
1138 | | - if (!in_array($status, array(202,404))) { |
1139 | | - throw new InvalidResponseException( |
1140 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
1141 | | - } |
1142 | | - $this->cdn_acl_user_agent = $cdn_acl_user_agent; |
1143 | | - return True; |
1144 | | - } |
1145 | | - |
1146 | | - /** |
1147 | | - * Enable ACL restriction by referer for this container. |
1148 | | - * |
1149 | | - * Example: |
1150 | | - * <code> |
1151 | | - * # ... authentication code excluded (see previous examples) ... |
1152 | | - * # |
1153 | | - * $conn = new CF_Authentication($auth); |
1154 | | - * |
1155 | | - * $public_container = $conn->get_container("public"); |
1156 | | - * |
1157 | | - * # Enable Referrer |
1158 | | - * $public_container->acl_referrer("http://www.example.com/gallery.php"); |
1159 | | - * </code> |
1160 | | - * |
1161 | | - * @returns boolean True if successful |
1162 | | - * @throws CDNNotEnabledException CDN functionality not returned during auth |
1163 | | - * @throws AuthenticationException if auth token is not valid/expired |
1164 | | - * @throws InvalidResponseException unexpected response |
1165 | | - */ |
1166 | | - function acl_referrer($cdn_acl_referrer="") { |
1167 | | - if ($this->cfs_http->getCDNMUrl() == NULL) { |
1168 | | - throw new CDNNotEnabledException( |
1169 | | - "Authentication response did not indicate CDN availability"); |
1170 | | - } |
1171 | | - list($status,$reason) = |
1172 | | - $this->cfs_http->update_cdn_container($this->name, |
1173 | | - $this->cdn_ttl, |
1174 | | - $this->cdn_log_retention, |
1175 | | - $this->cdn_acl_user_agent, |
1176 | | - $cdn_acl_referrer |
1177 | | - ); |
1178 | | - if (!in_array($status, array(202,404))) { |
1179 | | - throw new InvalidResponseException( |
1180 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
1181 | | - } |
1182 | | - $this->cdn_acl_referrer = $cdn_acl_referrer; |
1183 | | - return True; |
1184 | | - } |
1185 | | - |
1186 | | - /** |
1187 | | - * Enable log retention for this CDN container. |
1188 | | - * |
1189 | | - * Enable CDN log retention on the container. If enabled logs will |
1190 | | - * be periodically (at unpredictable intervals) compressed and |
1191 | | - * uploaded to a ".CDN_ACCESS_LOGS" container in the form of |
1192 | | - * "container_name.YYYYMMDDHH-XXXX.gz". Requires CDN be enabled on |
1193 | | - * the account. |
1194 | | - * |
1195 | | - * Example: |
1196 | | - * <code> |
1197 | | - * # ... authentication code excluded (see previous examples) ... |
1198 | | - * # |
1199 | | - * $conn = new CF_Authentication($auth); |
1200 | | - * |
1201 | | - * $public_container = $conn->get_container("public"); |
1202 | | - * |
1203 | | - * # Enable logs retention. |
1204 | | - * $public_container->log_retention(True); |
1205 | | - * </code> |
1206 | | - * |
1207 | | - * @returns boolean True if successful |
1208 | | - * @throws CDNNotEnabledException CDN functionality not returned during auth |
1209 | | - * @throws AuthenticationException if auth token is not valid/expired |
1210 | | - * @throws InvalidResponseException unexpected response |
1211 | | - */ |
1212 | | - function log_retention($cdn_log_retention=False) { |
1213 | | - if ($this->cfs_http->getCDNMUrl() == NULL) { |
1214 | | - throw new CDNNotEnabledException( |
1215 | | - "Authentication response did not indicate CDN availability"); |
1216 | | - } |
1217 | | - list($status,$reason) = |
1218 | | - $this->cfs_http->update_cdn_container($this->name, |
1219 | | - $this->cdn_ttl, |
1220 | | - $cdn_log_retention, |
1221 | | - $this->cdn_acl_user_agent, |
1222 | | - $this->cdn_acl_referrer |
1223 | | - ); |
1224 | | - if (!in_array($status, array(202,404))) { |
1225 | | - throw new InvalidResponseException( |
1226 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
1227 | | - } |
1228 | | - $this->cdn_log_retention = $cdn_log_retention; |
1229 | | - return True; |
1230 | | - } |
1231 | | - |
1232 | | - /** |
1233 | | - * Disable the CDN sharing for this container |
1234 | | - * |
1235 | | - * Use this method to disallow distribution into the CDN of this Container's |
1236 | | - * content. |
1237 | | - * |
1238 | | - * NOTE: Any content already cached in the CDN will continue to be served |
1239 | | - * from its cache until the TTL expiration transpires. The default |
1240 | | - * TTL is typically one day, so "privatizing" the Container will take |
1241 | | - * up to 24 hours before the content is purged from the CDN cache. |
1242 | | - * |
1243 | | - * Example: |
1244 | | - * <code> |
1245 | | - * # ... authentication code excluded (see previous examples) ... |
1246 | | - * # |
1247 | | - * $conn = new CF_Authentication($auth); |
1248 | | - * |
1249 | | - * $public_container = $conn->get_container("public"); |
1250 | | - * |
1251 | | - * # Disable CDN accessability |
1252 | | - * # ... still cached up to a month based on previous example |
1253 | | - * # |
1254 | | - * $public_container->make_private(); |
1255 | | - * </code> |
1256 | | - * |
1257 | | - * @returns boolean True if successful |
1258 | | - * @throws CDNNotEnabledException CDN functionality not returned during auth |
1259 | | - * @throws AuthenticationException if auth token is not valid/expired |
1260 | | - * @throws InvalidResponseException unexpected response |
1261 | | - */ |
1262 | | - function make_private() |
1263 | | - { |
1264 | | - if ($this->cfs_http->getCDNMUrl() == NULL) { |
1265 | | - throw new CDNNotEnabledException( |
1266 | | - "Authentication response did not indicate CDN availability"); |
1267 | | - } |
1268 | | - list($status,$reason) = $this->cfs_http->remove_cdn_container($this->name); |
1269 | | - #if ($status == 401 && $this->_re_auth()) { |
1270 | | - # return $this->make_private(); |
1271 | | - #} |
1272 | | - if (!in_array($status, array(202,404))) { |
1273 | | - throw new InvalidResponseException( |
1274 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
1275 | | - } |
1276 | | - $this->cdn_enabled = False; |
1277 | | - $this->cdn_ttl = NULL; |
1278 | | - $this->cdn_uri = NULL; |
1279 | | - $this->cdn_ssl_uri = NULL; |
1280 | | - $this->cdn_log_retention = NULL; |
1281 | | - $this->cdn_acl_user_agent = NULL; |
1282 | | - $this->cdn_acl_referrer = NULL; |
1283 | | - return True; |
1284 | | - } |
1285 | | - |
1286 | | - /** |
1287 | | - * Check if this Container is being publicly served via CDN |
1288 | | - * |
1289 | | - * Use this method to determine if the Container's content is currently |
1290 | | - * available through the CDN. |
1291 | | - * |
1292 | | - * Example: |
1293 | | - * <code> |
1294 | | - * # ... authentication code excluded (see previous examples) ... |
1295 | | - * # |
1296 | | - * $conn = new CF_Authentication($auth); |
1297 | | - * |
1298 | | - * $public_container = $conn->get_container("public"); |
1299 | | - * |
1300 | | - * # Display CDN accessability |
1301 | | - * # |
1302 | | - * $public_container->is_public() ? print "Yes" : print "No"; |
1303 | | - * </code> |
1304 | | - * |
1305 | | - * @returns boolean True if enabled, False otherwise |
1306 | | - */ |
1307 | | - function is_public() |
1308 | | - { |
1309 | | - return $this->cdn_enabled == True ? True : False; |
1310 | | - } |
1311 | | - |
1312 | | - /** |
1313 | | - * Create a new remote storage Object |
1314 | | - * |
1315 | | - * Return a new Object instance. If the remote storage Object exists, |
1316 | | - * the instance's attributes are populated. |
1317 | | - * |
1318 | | - * Example: |
1319 | | - * <code> |
1320 | | - * # ... authentication code excluded (see previous examples) ... |
1321 | | - * # |
1322 | | - * $conn = new CF_Authentication($auth); |
1323 | | - * |
1324 | | - * $public_container = $conn->get_container("public"); |
1325 | | - * |
1326 | | - * # This creates a local instance of a storage object but only creates |
1327 | | - * # it in the storage system when the object's write() method is called. |
1328 | | - * # |
1329 | | - * $pic = $public_container->create_object("baby.jpg"); |
1330 | | - * </code> |
1331 | | - * |
1332 | | - * @param string $obj_name name of storage Object |
1333 | | - * @return obj CF_Object instance |
1334 | | - */ |
1335 | | - function create_object($obj_name=NULL) |
1336 | | - { |
1337 | | - return new CF_Object($this, $obj_name); |
1338 | | - } |
1339 | | - |
1340 | | - /** |
1341 | | - * Return an Object instance for the remote storage Object |
1342 | | - * |
1343 | | - * Given a name, return a Object instance representing the |
1344 | | - * remote storage object. |
1345 | | - * |
1346 | | - * Example: |
1347 | | - * <code> |
1348 | | - * # ... authentication code excluded (see previous examples) ... |
1349 | | - * # |
1350 | | - * $conn = new CF_Authentication($auth); |
1351 | | - * |
1352 | | - * $public_container = $conn->get_container("public"); |
1353 | | - * |
1354 | | - * # This call only fetches header information and not the content of |
1355 | | - * # the storage object. Use the Object's read() or stream() methods |
1356 | | - * # to obtain the object's data. |
1357 | | - * # |
1358 | | - * $pic = $public_container->get_object("baby.jpg"); |
1359 | | - * </code> |
1360 | | - * |
1361 | | - * @param string $obj_name name of storage Object |
1362 | | - * @return obj CF_Object instance |
1363 | | - */ |
1364 | | - function get_object($obj_name=NULL) |
1365 | | - { |
1366 | | - return new CF_Object($this, $obj_name, True); |
1367 | | - } |
1368 | | - |
1369 | | - /** |
1370 | | - * Return a list of Objects |
1371 | | - * |
1372 | | - * Return an array of strings listing the Object names in this Container. |
1373 | | - * |
1374 | | - * Example: |
1375 | | - * <code> |
1376 | | - * # ... authentication code excluded (see previous examples) ... |
1377 | | - * # |
1378 | | - * $images = $conn->get_container("my photos"); |
1379 | | - * |
1380 | | - * # Grab the list of all storage objects |
1381 | | - * # |
1382 | | - * $all_objects = $images->list_objects(); |
1383 | | - * |
1384 | | - * # Grab subsets of all storage objects |
1385 | | - * # |
1386 | | - * $first_ten = $images->list_objects(10); |
1387 | | - * |
1388 | | - * # Note the use of the previous result's last object name being |
1389 | | - * # used as the 'marker' parameter to fetch the next 10 objects |
1390 | | - * # |
1391 | | - * $next_ten = $images->list_objects(10, $first_ten[count($first_ten)-1]); |
1392 | | - * |
1393 | | - * # Grab images starting with "birthday_party" and default limit/marker |
1394 | | - * # to match all photos with that prefix |
1395 | | - * # |
1396 | | - * $prefixed = $images->list_objects(0, NULL, "birthday"); |
1397 | | - * |
1398 | | - * # Assuming you have created the appropriate directory marker Objects, |
1399 | | - * # you can traverse your pseudo-hierarchical containers |
1400 | | - * # with the "path" argument. |
1401 | | - * # |
1402 | | - * $animals = $images->list_objects(0,NULL,NULL,"pictures/animals"); |
1403 | | - * $dogs = $images->list_objects(0,NULL,NULL,"pictures/animals/dogs"); |
1404 | | - * </code> |
1405 | | - * |
1406 | | - * @param int $limit <i>optional</i> only return $limit names |
1407 | | - * @param int $marker <i>optional</i> subset of names starting at $marker |
1408 | | - * @param string $prefix <i>optional</i> Objects whose names begin with $prefix |
1409 | | - * @param string $path <i>optional</i> only return results under "pathname" |
1410 | | - * @return array array of strings |
1411 | | - * @throws InvalidResponseException unexpected response |
1412 | | - */ |
1413 | | - function list_objects($limit=0, $marker=NULL, $prefix=NULL, $path=NULL) |
1414 | | - { |
1415 | | - list($status, $reason, $obj_list) = |
1416 | | - $this->cfs_http->list_objects($this->name, $limit, |
1417 | | - $marker, $prefix, $path); |
1418 | | - #if ($status == 401 && $this->_re_auth()) { |
1419 | | - # return $this->list_objects($limit, $marker, $prefix, $path); |
1420 | | - #} |
1421 | | - if ($status < 200 || $status > 299) { |
1422 | | - throw new InvalidResponseException( |
1423 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
1424 | | - } |
1425 | | - return $obj_list; |
1426 | | - } |
1427 | | - |
1428 | | - /** |
1429 | | - * Return an array of Objects |
1430 | | - * |
1431 | | - * Return an array of Object instances in this Container. |
1432 | | - * |
1433 | | - * Example: |
1434 | | - * <code> |
1435 | | - * # ... authentication code excluded (see previous examples) ... |
1436 | | - * # |
1437 | | - * $images = $conn->get_container("my photos"); |
1438 | | - * |
1439 | | - * # Grab the list of all storage objects |
1440 | | - * # |
1441 | | - * $all_objects = $images->get_objects(); |
1442 | | - * |
1443 | | - * # Grab subsets of all storage objects |
1444 | | - * # |
1445 | | - * $first_ten = $images->get_objects(10); |
1446 | | - * |
1447 | | - * # Note the use of the previous result's last object name being |
1448 | | - * # used as the 'marker' parameter to fetch the next 10 objects |
1449 | | - * # |
1450 | | - * $next_ten = $images->list_objects(10, $first_ten[count($first_ten)-1]); |
1451 | | - * |
1452 | | - * # Grab images starting with "birthday_party" and default limit/marker |
1453 | | - * # to match all photos with that prefix |
1454 | | - * # |
1455 | | - * $prefixed = $images->get_objects(0, NULL, "birthday"); |
1456 | | - * |
1457 | | - * # Assuming you have created the appropriate directory marker Objects, |
1458 | | - * # you can traverse your pseudo-hierarchical containers |
1459 | | - * # with the "path" argument. |
1460 | | - * # |
1461 | | - * $animals = $images->get_objects(0,NULL,NULL,"pictures/animals"); |
1462 | | - * $dogs = $images->get_objects(0,NULL,NULL,"pictures/animals/dogs"); |
1463 | | - * </code> |
1464 | | - * |
1465 | | - * @param int $limit <i>optional</i> only return $limit names |
1466 | | - * @param int $marker <i>optional</i> subset of names starting at $marker |
1467 | | - * @param string $prefix <i>optional</i> Objects whose names begin with $prefix |
1468 | | - * @param string $path <i>optional</i> only return results under "pathname" |
1469 | | - * @return array array of strings |
1470 | | - * @throws InvalidResponseException unexpected response |
1471 | | - */ |
1472 | | - function get_objects($limit=0, $marker=NULL, $prefix=NULL, $path=NULL) |
1473 | | - { |
1474 | | - list($status, $reason, $obj_array) = |
1475 | | - $this->cfs_http->get_objects($this->name, $limit, |
1476 | | - $marker, $prefix, $path); |
1477 | | - #if ($status == 401 && $this->_re_auth()) { |
1478 | | - # return $this->get_objects($limit, $marker, $prefix, $path); |
1479 | | - #} |
1480 | | - if ($status < 200 || $status > 299) { |
1481 | | - throw new InvalidResponseException( |
1482 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
1483 | | - } |
1484 | | - $objects = array(); |
1485 | | - foreach ($obj_array as $obj) { |
1486 | | - $tmp = new CF_Object($this, $obj["name"], False, False); |
1487 | | - $tmp->content_type = $obj["content_type"]; |
1488 | | - $tmp->content_length = (float) $obj["bytes"]; |
1489 | | - $tmp->set_etag($obj["hash"]); |
1490 | | - $tmp->last_modified = $obj["last_modified"]; |
1491 | | - $objects[] = $tmp; |
1492 | | - } |
1493 | | - return $objects; |
1494 | | - } |
1495 | | - |
1496 | | - /** |
1497 | | - * Delete a remote storage Object |
1498 | | - * |
1499 | | - * Given an Object instance or name, permanently remove the remote Object |
1500 | | - * and all associated metadata. |
1501 | | - * |
1502 | | - * Example: |
1503 | | - * <code> |
1504 | | - * # ... authentication code excluded (see previous examples) ... |
1505 | | - * # |
1506 | | - * $conn = new CF_Authentication($auth); |
1507 | | - * |
1508 | | - * $images = $conn->get_container("my photos"); |
1509 | | - * |
1510 | | - * # Delete specific object |
1511 | | - * # |
1512 | | - * $images->delete_object("disco_dancing.jpg"); |
1513 | | - * </code> |
1514 | | - * |
1515 | | - * @param obj $obj name or instance of Object to delete |
1516 | | - * @return boolean <kbd>True</kbd> if successfully removed |
1517 | | - * @throws SyntaxException invalid Object name |
1518 | | - * @throws NoSuchObjectException remote Object does not exist |
1519 | | - * @throws InvalidResponseException unexpected response |
1520 | | - */ |
1521 | | - function delete_object($obj) |
1522 | | - { |
1523 | | - $obj_name = NULL; |
1524 | | - if (is_object($obj)) { |
1525 | | - if (get_class($obj) == "CF_Object") { |
1526 | | - $obj_name = $obj->name; |
1527 | | - } |
1528 | | - } |
1529 | | - if (is_string($obj)) { |
1530 | | - $obj_name = $obj; |
1531 | | - } |
1532 | | - if (!$obj_name) { |
1533 | | - throw new SyntaxException("Object name not set."); |
1534 | | - } |
1535 | | - $status = $this->cfs_http->delete_object($this->name, $obj_name); |
1536 | | - #if ($status == 401 && $this->_re_auth()) { |
1537 | | - # return $this->delete_object($obj); |
1538 | | - #} |
1539 | | - if ($status == 404) { |
1540 | | - $m = "Specified object '".$this->name."/".$obj_name; |
1541 | | - $m.= "' did not exist to delete."; |
1542 | | - throw new NoSuchObjectException($m); |
1543 | | - } |
1544 | | - if ($status != 204) { |
1545 | | - throw new InvalidResponseException( |
1546 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
1547 | | - } |
1548 | | - return True; |
1549 | | - } |
1550 | | - |
1551 | | - /** |
1552 | | - * Helper function to create "path" elements for a given Object name |
1553 | | - * |
1554 | | - * Given an Object whos name contains '/' path separators, this function |
1555 | | - * will create the "directory marker" Objects of one byte with the |
1556 | | - * Content-Type of "application/folder". |
1557 | | - * |
1558 | | - * It assumes the last element of the full path is the "real" Object |
1559 | | - * and does NOT create a remote storage Object for that last element. |
1560 | | - */ |
1561 | | - function create_paths($path_name) |
1562 | | - { |
1563 | | - if ($path_name[0] == '/') { |
1564 | | - $path_name = mb_substr($path_name, 0, 1); |
1565 | | - } |
1566 | | - $elements = explode('/', $path_name, -1); |
1567 | | - $build_path = ""; |
1568 | | - foreach ($elements as $idx => $val) { |
1569 | | - if (!$build_path) { |
1570 | | - $build_path = $val; |
1571 | | - } else { |
1572 | | - $build_path .= "/" . $val; |
1573 | | - } |
1574 | | - $obj = new CF_Object($this, $build_path); |
1575 | | - $obj->content_type = "application/directory"; |
1576 | | - $obj->write(".", 1); |
1577 | | - } |
1578 | | - } |
1579 | | - |
1580 | | - /** |
1581 | | - * Internal method to grab CDN/Container info if appropriate to do so |
1582 | | - * |
1583 | | - * @throws InvalidResponseException unexpected response |
1584 | | - */ |
1585 | | - private function _cdn_initialize() |
1586 | | - { |
1587 | | - list($status, $reason, $cdn_enabled, $cdn_ssl_uri, $cdn_uri, $cdn_ttl, |
1588 | | - $cdn_log_retention, $cdn_acl_user_agent, $cdn_acl_referrer) = |
1589 | | - $this->cfs_http->head_cdn_container($this->name); |
1590 | | - #if ($status == 401 && $this->_re_auth()) { |
1591 | | - # return $this->_cdn_initialize(); |
1592 | | - #} |
1593 | | - if (!in_array($status, array(204,404))) { |
1594 | | - throw new InvalidResponseException( |
1595 | | - "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
1596 | | - } |
1597 | | - $this->cdn_enabled = $cdn_enabled; |
1598 | | - $this->cdn_ssl_uri = $cdn_ssl_uri; |
1599 | | - $this->cdn_uri = $cdn_uri; |
1600 | | - $this->cdn_ttl = $cdn_ttl; |
1601 | | - $this->cdn_log_retention = $cdn_log_retention; |
1602 | | - $this->cdn_acl_user_agent = $cdn_acl_user_agent; |
1603 | | - $this->cdn_acl_referrer = $cdn_acl_referrer; |
1604 | | - } |
1605 | | - |
1606 | | - #private function _re_auth() |
1607 | | - #{ |
1608 | | - # $new_auth = new CF_Authentication( |
1609 | | - # $this->cfs_auth->username, |
1610 | | - # $this->cfs_auth->api_key, |
1611 | | - # $this->cfs_auth->auth_host, |
1612 | | - # $this->cfs_auth->account); |
1613 | | - # $new_auth->authenticate(); |
1614 | | - # $this->cfs_auth = $new_auth; |
1615 | | - # $this->cfs_http->setCFAuth($this->cfs_auth); |
1616 | | - # return True; |
1617 | | - #} |
1618 | | -} |
1619 | | - |
1620 | | - |
1621 | | -/** |
1622 | | - * Object operations |
1623 | | - * |
1624 | | - * An Object is analogous to a file on a conventional filesystem. You can |
1625 | | - * read data from, or write data to your Objects. You can also associate |
1626 | | - * arbitrary metadata with them. |
1627 | | - * |
1628 | | - * @package php-cloudfiles |
1629 | | - */ |
1630 | | -class CF_Object |
1631 | | -{ |
1632 | | - public $container; |
1633 | | - public $name; |
1634 | | - public $last_modified; |
1635 | | - public $content_type; |
1636 | | - public $content_length; |
1637 | | - public $metadata; |
1638 | | - public $manifest; |
1639 | | - private $etag; |
1640 | | - |
1641 | | - /** |
1642 | | - * Class constructor |
1643 | | - * |
1644 | | - * @param obj $container CF_Container instance |
1645 | | - * @param string $name name of Object |
1646 | | - * @param boolean $force_exists if set, throw an error if Object doesn't exist |
1647 | | - */ |
1648 | | - function __construct(&$container, $name, $force_exists=False, $dohead=True) |
1649 | | - { |
1650 | | - if ($name[0] == "/") { |
1651 | | - $r = "Object name '".$name; |
1652 | | - $r .= "' cannot contain begin with a '/' character."; |
1653 | | - throw new SyntaxException($r); |
1654 | | - } |
1655 | | - if (strlen($name) > MAX_OBJECT_NAME_LEN) { |
1656 | | - throw new SyntaxException("Object name exceeds " |
1657 | | - . "maximum allowed length."); |
1658 | | - } |
1659 | | - $this->container = $container; |
1660 | | - $this->name = $name; |
1661 | | - $this->etag = NULL; |
1662 | | - $this->_etag_override = False; |
1663 | | - $this->last_modified = NULL; |
1664 | | - $this->content_type = NULL; |
1665 | | - $this->content_length = 0; |
1666 | | - $this->metadata = array(); |
1667 | | - $this->manifest = NULL; |
1668 | | - if ($dohead) { |
1669 | | - if (!$this->_initialize() && $force_exists) { |
1670 | | - throw new NoSuchObjectException("No such object '".$name."'"); |
1671 | | - } |
1672 | | - } |
1673 | | - } |
1674 | | - |
1675 | | - /** |
1676 | | - * String representation of Object |
1677 | | - * |
1678 | | - * Pretty print the Object's location and name |
1679 | | - * |
1680 | | - * @return string Object information |
1681 | | - */ |
1682 | | - function __toString() |
1683 | | - { |
1684 | | - return $this->container->name . "/" . $this->name; |
1685 | | - } |
1686 | | - |
1687 | | - /** |
1688 | | - * Internal check to get the proper mimetype. |
1689 | | - * |
1690 | | - * This function would go over the available PHP methods to get |
1691 | | - * the MIME type. |
1692 | | - * |
1693 | | - * By default it will try to use the PHP fileinfo library which is |
1694 | | - * available from PHP 5.3 or as an PECL extension |
1695 | | - * (http://pecl.php.net/package/Fileinfo). |
1696 | | - * |
1697 | | - * It will get the magic file by default from the system wide file |
1698 | | - * which is usually available in /usr/share/magic on Unix or try |
1699 | | - * to use the file specified in the source directory of the API |
1700 | | - * (share directory). |
1701 | | - * |
1702 | | - * if fileinfo is not available it will try to use the internal |
1703 | | - * mime_content_type function. |
1704 | | - * |
1705 | | - * @param string $handle name of file or buffer to guess the type from |
1706 | | - * @return boolean <kbd>True</kbd> if successful |
1707 | | - * @throws BadContentTypeException |
1708 | | - */ |
1709 | | - function _guess_content_type($handle) { |
1710 | | - if ($this->content_type) |
1711 | | - return; |
1712 | | - |
1713 | | - if (function_exists("finfo_open")) { |
1714 | | - $local_magic = dirname(__FILE__) . "/share/magic"; |
1715 | | - $finfo = @finfo_open(FILEINFO_MIME, $local_magic); |
1716 | | - |
1717 | | - if (!$finfo) |
1718 | | - $finfo = @finfo_open(FILEINFO_MIME); |
1719 | | - |
1720 | | - if ($finfo) { |
1721 | | - |
1722 | | - if (is_file((string)$handle)) |
1723 | | - $ct = @finfo_file($finfo, $handle); |
1724 | | - else |
1725 | | - $ct = @finfo_buffer($finfo, $handle); |
1726 | | - |
1727 | | - /* PHP 5.3 fileinfo display extra information like |
1728 | | - charset so we remove everything after the ; since |
1729 | | - we are not into that stuff */ |
1730 | | - if ($ct) { |
1731 | | - $extra_content_type_info = strpos($ct, "; "); |
1732 | | - if ($extra_content_type_info) |
1733 | | - $ct = substr($ct, 0, $extra_content_type_info); |
1734 | | - } |
1735 | | - |
1736 | | - if ($ct && $ct != 'application/octet-stream') |
1737 | | - $this->content_type = $ct; |
1738 | | - |
1739 | | - @finfo_close($finfo); |
1740 | | - } |
1741 | | - } |
1742 | | - |
1743 | | - if (!$this->content_type && (string)is_file($handle) && function_exists("mime_content_type")) { |
1744 | | - $this->content_type = @mime_content_type($handle); |
1745 | | - } |
1746 | | - |
1747 | | - if (!$this->content_type) { |
1748 | | - throw new BadContentTypeException("Required Content-Type not set"); |
1749 | | - } |
1750 | | - return True; |
1751 | | - } |
1752 | | - |
1753 | | - /** |
1754 | | - * String representation of the Object's public URI |
1755 | | - * |
1756 | | - * A string representing the Object's public URI assuming that it's |
1757 | | - * parent Container is CDN-enabled. |
1758 | | - * |
1759 | | - * Example: |
1760 | | - * <code> |
1761 | | - * # ... authentication/connection/container code excluded |
1762 | | - * # ... see previous examples |
1763 | | - * |
1764 | | - * # Print out the Object's CDN URI (if it has one) in an HTML img-tag |
1765 | | - * # |
1766 | | - * print "<img src='$pic->public_uri()' />\n"; |
1767 | | - * </code> |
1768 | | - * |
1769 | | - * @return string Object's public URI or NULL |
1770 | | - */ |
1771 | | - function public_uri() |
1772 | | - { |
1773 | | - if ($this->container->cdn_enabled) { |
1774 | | - return $this->container->cdn_uri . "/" . $this->name; |
1775 | | - } |
1776 | | - return NULL; |
1777 | | - } |
1778 | | - |
1779 | | - /** |
1780 | | - * String representation of the Object's public SSL URI |
1781 | | - * |
1782 | | - * A string representing the Object's public SSL URI assuming that it's |
1783 | | - * parent Container is CDN-enabled. |
1784 | | - * |
1785 | | - * Example: |
1786 | | - * <code> |
1787 | | - * # ... authentication/connection/container code excluded |
1788 | | - * # ... see previous examples |
1789 | | - * |
1790 | | - * # Print out the Object's CDN SSL URI (if it has one) in an HTML img-tag |
1791 | | - * # |
1792 | | - * print "<img src='$pic->public_ssl_uri()' />\n"; |
1793 | | - * </code> |
1794 | | - * |
1795 | | - * @return string Object's public SSL URI or NULL |
1796 | | - */ |
1797 | | - function public_ssl_uri() |
1798 | | - { |
1799 | | - if ($this->container->cdn_enabled) { |
1800 | | - return $this->container->cdn_ssl_uri . "/" . $this->name; |
1801 | | - } |
1802 | | - return NULL; |
1803 | | - } |
1804 | | - |
1805 | | - /** |
1806 | | - * Read the remote Object's data |
1807 | | - * |
1808 | | - * Returns the Object's data. This is useful for smaller Objects such |
1809 | | - * as images or office documents. Object's with larger content should use |
1810 | | - * the stream() method below. |
1811 | | - * |
1812 | | - * Pass in $hdrs array to set specific custom HTTP headers such as |
1813 | | - * If-Match, If-None-Match, If-Modified-Since, Range, etc. |
1814 | | - * |
1815 | | - * Example: |
1816 | | - * <code> |
1817 | | - * # ... authentication/connection/container code excluded |
1818 | | - * # ... see previous examples |
1819 | | - * |
1820 | | - * $my_docs = $conn->get_container("documents"); |
1821 | | - * $doc = $my_docs->get_object("README"); |
1822 | | - * $data = $doc->read(); # read image content into a string variable |
1823 | | - * print $data; |
1824 | | - * |
1825 | | - * # Or see stream() below for a different example. |
1826 | | - * # |
1827 | | - * </code> |
1828 | | - * |
1829 | | - * @param array $hdrs user-defined headers (Range, If-Match, etc.) |
1830 | | - * @return string Object's data |
1831 | | - * @throws InvalidResponseException unexpected response |
1832 | | - */ |
1833 | | - function read($hdrs=array()) |
1834 | | - { |
1835 | | - list($status, $reason, $data) = |
1836 | | - $this->container->cfs_http->get_object_to_string($this, $hdrs); |
1837 | | - #if ($status == 401 && $this->_re_auth()) { |
1838 | | - # return $this->read($hdrs); |
1839 | | - #} |
1840 | | - if (($status < 200) || ($status > 299 |
1841 | | - && $status != 412 && $status != 304)) { |
1842 | | - throw new InvalidResponseException("Invalid response (".$status."): " |
1843 | | - . $this->container->cfs_http->get_error()); |
1844 | | - } |
1845 | | - return $data; |
1846 | | - } |
1847 | | - |
1848 | | - /** |
1849 | | - * Streaming read of Object's data |
1850 | | - * |
1851 | | - * Given an open PHP resource (see PHP's fopen() method), fetch the Object's |
1852 | | - * data and write it to the open resource handle. This is useful for |
1853 | | - * streaming an Object's content to the browser (videos, images) or for |
1854 | | - * fetching content to a local file. |
1855 | | - * |
1856 | | - * Pass in $hdrs array to set specific custom HTTP headers such as |
1857 | | - * If-Match, If-None-Match, If-Modified-Since, Range, etc. |
1858 | | - * |
1859 | | - * Example: |
1860 | | - * <code> |
1861 | | - * # ... authentication/connection/container code excluded |
1862 | | - * # ... see previous examples |
1863 | | - * |
1864 | | - * # Assuming this is a web script to display the README to the |
1865 | | - * # user's browser: |
1866 | | - * # |
1867 | | - * <?php |
1868 | | - * // grab README from storage system |
1869 | | - * // |
1870 | | - * $my_docs = $conn->get_container("documents"); |
1871 | | - * $doc = $my_docs->get_object("README"); |
1872 | | - * |
1873 | | - * // Hand it back to user's browser with appropriate content-type |
1874 | | - * // |
1875 | | - * header("Content-Type: " . $doc->content_type); |
1876 | | - * $output = fopen("php://output", "w"); |
1877 | | - * $doc->stream($output); # stream object content to PHP's output buffer |
1878 | | - * fclose($output); |
1879 | | - * ?> |
1880 | | - * |
1881 | | - * # See read() above for a more simple example. |
1882 | | - * # |
1883 | | - * </code> |
1884 | | - * |
1885 | | - * @param resource $fp open resource for writing data to |
1886 | | - * @param array $hdrs user-defined headers (Range, If-Match, etc.) |
1887 | | - * @return string Object's data |
1888 | | - * @throws InvalidResponseException unexpected response |
1889 | | - */ |
1890 | | - function stream(&$fp, $hdrs=array()) |
1891 | | - { |
1892 | | - list($status, $reason) = |
1893 | | - $this->container->cfs_http->get_object_to_stream($this,$fp,$hdrs); |
1894 | | - #if ($status == 401 && $this->_re_auth()) { |
1895 | | - # return $this->stream($fp, $hdrs); |
1896 | | - #} |
1897 | | - if (($status < 200) || ($status > 299 |
1898 | | - && $status != 412 && $status != 304)) { |
1899 | | - throw new InvalidResponseException("Invalid response (".$status."): " |
1900 | | - .$reason); |
1901 | | - } |
1902 | | - return True; |
1903 | | - } |
1904 | | - |
1905 | | - /** |
1906 | | - * Store new Object metadata |
1907 | | - * |
1908 | | - * Write's an Object's metadata to the remote Object. This will overwrite |
1909 | | - * an prior Object metadata. |
1910 | | - * |
1911 | | - * Example: |
1912 | | - * <code> |
1913 | | - * # ... authentication/connection/container code excluded |
1914 | | - * # ... see previous examples |
1915 | | - * |
1916 | | - * $my_docs = $conn->get_container("documents"); |
1917 | | - * $doc = $my_docs->get_object("README"); |
1918 | | - * |
1919 | | - * # Define new metadata for the object |
1920 | | - * # |
1921 | | - * $doc->metadata = array( |
1922 | | - * "Author" => "EJ", |
1923 | | - * "Subject" => "How to use the PHP tests", |
1924 | | - * "Version" => "1.2.2" |
1925 | | - * ); |
1926 | | - * |
1927 | | - * # Push the new metadata up to the storage system |
1928 | | - * # |
1929 | | - * $doc->sync_metadata(); |
1930 | | - * </code> |
1931 | | - * |
1932 | | - * @return boolean <kbd>True</kbd> if successful, <kbd>False</kbd> otherwise |
1933 | | - * @throws InvalidResponseException unexpected response |
1934 | | - */ |
1935 | | - function sync_metadata() |
1936 | | - { |
1937 | | - if (!empty($this->metadata) || $this->manifest) { |
1938 | | - $status = $this->container->cfs_http->update_object($this); |
1939 | | - #if ($status == 401 && $this->_re_auth()) { |
1940 | | - # return $this->sync_metadata(); |
1941 | | - #} |
1942 | | - if ($status != 202) { |
1943 | | - throw new InvalidResponseException("Invalid response (" |
1944 | | - .$status."): ".$this->container->cfs_http->get_error()); |
1945 | | - } |
1946 | | - return True; |
1947 | | - } |
1948 | | - return False; |
1949 | | - } |
1950 | | - /** |
1951 | | - * Store new Object manifest |
1952 | | - * |
1953 | | - * Write's an Object's manifest to the remote Object. This will overwrite |
1954 | | - * an prior Object manifest. |
1955 | | - * |
1956 | | - * Example: |
1957 | | - * <code> |
1958 | | - * # ... authentication/connection/container code excluded |
1959 | | - * # ... see previous examples |
1960 | | - * |
1961 | | - * $my_docs = $conn->get_container("documents"); |
1962 | | - * $doc = $my_docs->get_object("README"); |
1963 | | - * |
1964 | | - * # Define new manifest for the object |
1965 | | - * # |
1966 | | - * $doc->manifest = "container/prefix"; |
1967 | | - * |
1968 | | - * # Push the new manifest up to the storage system |
1969 | | - * # |
1970 | | - * $doc->sync_manifest(); |
1971 | | - * </code> |
1972 | | - * |
1973 | | - * @return boolean <kbd>True</kbd> if successful, <kbd>False</kbd> otherwise |
1974 | | - * @throws InvalidResponseException unexpected response |
1975 | | - */ |
1976 | | - |
1977 | | - function sync_manifest() |
1978 | | - { |
1979 | | - return $this->sync_metadata(); |
1980 | | - } |
1981 | | - /** |
1982 | | - * Upload Object's data to Cloud Files |
1983 | | - * |
1984 | | - * Write data to the remote Object. The $data argument can either be a |
1985 | | - * PHP resource open for reading (see PHP's fopen() method) or an in-memory |
1986 | | - * variable. If passing in a PHP resource, you must also include the $bytes |
1987 | | - * parameter. |
1988 | | - * |
1989 | | - * Example: |
1990 | | - * <code> |
1991 | | - * # ... authentication/connection/container code excluded |
1992 | | - * # ... see previous examples |
1993 | | - * |
1994 | | - * $my_docs = $conn->get_container("documents"); |
1995 | | - * $doc = $my_docs->get_object("README"); |
1996 | | - * |
1997 | | - * # Upload placeholder text in my README |
1998 | | - * # |
1999 | | - * $doc->write("This is just placeholder text for now..."); |
2000 | | - * </code> |
2001 | | - * |
2002 | | - * @param string|resource $data string or open resource |
2003 | | - * @param float $bytes amount of data to upload (required for resources) |
2004 | | - * @param boolean $verify generate, send, and compare MD5 checksums |
2005 | | - * @return boolean <kbd>True</kbd> when data uploaded successfully |
2006 | | - * @throws SyntaxException missing required parameters |
2007 | | - * @throws BadContentTypeException if no Content-Type was/could be set |
2008 | | - * @throws MisMatchedChecksumException $verify is set and checksums unequal |
2009 | | - * @throws InvalidResponseException unexpected response |
2010 | | - */ |
2011 | | - function write($data=NULL, $bytes=0, $verify=True) |
2012 | | - { |
2013 | | - if (!$data && !is_string($data)) { |
2014 | | - throw new SyntaxException("Missing data source."); |
2015 | | - } |
2016 | | - if ($bytes > MAX_OBJECT_SIZE) { |
2017 | | - throw new SyntaxException("Bytes exceeds maximum object size."); |
2018 | | - } |
2019 | | - if ($verify) { |
2020 | | - if (!$this->_etag_override) { |
2021 | | - $this->etag = $this->compute_md5sum($data); |
2022 | | - } |
2023 | | - } else { |
2024 | | - $this->etag = NULL; |
2025 | | - } |
2026 | | - |
2027 | | - $close_fh = False; |
2028 | | - if (!is_resource($data)) { |
2029 | | - # A hack to treat string data as a file handle. php://memory feels |
2030 | | - # like a better option, but it seems to break on Windows so use |
2031 | | - # a temporary file instead. |
2032 | | - # |
2033 | | - $fp = fopen("php://temp", "wb+"); |
2034 | | - #$fp = fopen("php://memory", "wb+"); |
2035 | | - fwrite($fp, $data, strlen($data)); |
2036 | | - rewind($fp); |
2037 | | - $close_fh = True; |
2038 | | - $this->content_length = (float) strlen($data); |
2039 | | - if ($this->content_length > MAX_OBJECT_SIZE) { |
2040 | | - throw new SyntaxException("Data exceeds maximum object size"); |
2041 | | - } |
2042 | | - $ct_data = substr($data, 0, 64); |
2043 | | - } else { |
2044 | | - $this->content_length = $bytes; |
2045 | | - $fp = $data; |
2046 | | - $ct_data = fread($data, 64); |
2047 | | - rewind($data); |
2048 | | - } |
2049 | | - |
2050 | | - $this->_guess_content_type($ct_data); |
2051 | | - |
2052 | | - list($status, $reason, $etag) = |
2053 | | - $this->container->cfs_http->put_object($this, $fp); |
2054 | | - #if ($status == 401 && $this->_re_auth()) { |
2055 | | - # return $this->write($data, $bytes, $verify); |
2056 | | - #} |
2057 | | - if ($status == 412) { |
2058 | | - if ($close_fh) { fclose($fp); } |
2059 | | - throw new SyntaxException("Missing Content-Type header"); |
2060 | | - } |
2061 | | - if ($status == 422) { |
2062 | | - if ($close_fh) { fclose($fp); } |
2063 | | - throw new MisMatchedChecksumException( |
2064 | | - "Supplied and computed checksums do not match."); |
2065 | | - } |
2066 | | - if ($status != 201) { |
2067 | | - if ($close_fh) { fclose($fp); } |
2068 | | - throw new InvalidResponseException("Invalid response (".$status."): " |
2069 | | - . $this->container->cfs_http->get_error()); |
2070 | | - } |
2071 | | - if (!$verify) { |
2072 | | - $this->etag = $etag; |
2073 | | - } |
2074 | | - if ($close_fh) { fclose($fp); } |
2075 | | - return True; |
2076 | | - } |
2077 | | - |
2078 | | - /** |
2079 | | - * Copy one Object to another Object to Cloud Files |
2080 | | - * |
2081 | | - * Example: |
2082 | | - * <code> |
2083 | | - * # ... authentication/connection/container code excluded |
2084 | | - * # ... see previous examples |
2085 | | - * |
2086 | | - * $my_docs = $conn->get_container("documents"); |
2087 | | - * $doc = $my_docs->get_object("README"); |
2088 | | - * |
2089 | | - * # Copy README.txt on top of this object (which you must have |
2090 | | - * already written something to). |
2091 | | - * # |
2092 | | - * $doc->copy("/documents/README.txt"); |
2093 | | - * </code> |
2094 | | - * |
2095 | | - * @param string $source Name of existing object |
2096 | | - * @return boolean <kbd>True</kbd> when data uploaded successfully |
2097 | | - * @throws SyntaxException missing required parameters |
2098 | | - * @throws BadContentTypeException if no Content-Type was/could be set |
2099 | | - * @throws MisMatchedChecksumException $verify is set and checksums unequal |
2100 | | - * @throws InvalidResponseException unexpected response |
2101 | | - */ |
2102 | | - function copy($source) |
2103 | | - { |
2104 | | - if (!$source && !is_string($source)) { |
2105 | | - throw new SyntaxException("Missing data source."); |
2106 | | - } |
2107 | | - list($status, $reason, $etag) = |
2108 | | - $this->container->cfs_http->put_object($this, $source); |
2109 | | - #if ($status == 401 && $this->_re_auth()) { |
2110 | | - # return $this->copy($data, $source); |
2111 | | - #} |
2112 | | - if ($status == 412) { |
2113 | | - throw new SyntaxException("Missing Content-Type header"); |
2114 | | - } |
2115 | | - if ($status == 422) { |
2116 | | - throw new MisMatchedChecksumException( |
2117 | | - "Supplied and computed checksums do not match."); |
2118 | | - } |
2119 | | - if ($status != 201) { |
2120 | | - throw new InvalidResponseException("Invalid response (".$status."): " |
2121 | | - . $this->container->cfs_http->get_error()); |
2122 | | - } |
2123 | | - return True; |
2124 | | - } |
2125 | | - |
2126 | | - /** |
2127 | | - * Upload Object data from local filename |
2128 | | - * |
2129 | | - * This is a convenience function to upload the data from a local file. A |
2130 | | - * True value for $verify will cause the method to compute the Object's MD5 |
2131 | | - * checksum prior to uploading. |
2132 | | - * |
2133 | | - * Example: |
2134 | | - * <code> |
2135 | | - * # ... authentication/connection/container code excluded |
2136 | | - * # ... see previous examples |
2137 | | - * |
2138 | | - * $my_docs = $conn->get_container("documents"); |
2139 | | - * $doc = $my_docs->get_object("README"); |
2140 | | - * |
2141 | | - * # Upload my local README's content |
2142 | | - * # |
2143 | | - * $doc->load_from_filename("/home/ej/cloudfiles/readme"); |
2144 | | - * </code> |
2145 | | - * |
2146 | | - * @param string $filename full path to local file |
2147 | | - * @param boolean $verify enable local/remote MD5 checksum validation |
2148 | | - * @return boolean <kbd>True</kbd> if data uploaded successfully |
2149 | | - * @throws SyntaxException missing required parameters |
2150 | | - * @throws BadContentTypeException if no Content-Type was/could be set |
2151 | | - * @throws MisMatchedChecksumException $verify is set and checksums unequal |
2152 | | - * @throws InvalidResponseException unexpected response |
2153 | | - * @throws IOException error opening file |
2154 | | - */ |
2155 | | - function load_from_filename($filename, $verify=True) |
2156 | | - { |
2157 | | - $fp = @fopen($filename, "r"); |
2158 | | - if (!$fp) { |
2159 | | - throw new IOException("Could not open file for reading: ".$filename); |
2160 | | - } |
2161 | | - |
2162 | | - clearstatcache(); |
2163 | | - |
2164 | | - $size = (float) sprintf("%u", filesize($filename)); |
2165 | | - if ($size > MAX_OBJECT_SIZE) { |
2166 | | - throw new SyntaxException("File size exceeds maximum object size."); |
2167 | | - } |
2168 | | - |
2169 | | - $this->_guess_content_type($filename); |
2170 | | - |
2171 | | - $this->write($fp, $size, $verify); |
2172 | | - fclose($fp); |
2173 | | - return True; |
2174 | | - } |
2175 | | - |
2176 | | - /** |
2177 | | - * Save Object's data to local filename |
2178 | | - * |
2179 | | - * Given a local filename, the Object's data will be written to the newly |
2180 | | - * created file. |
2181 | | - * |
2182 | | - * Example: |
2183 | | - * <code> |
2184 | | - * # ... authentication/connection/container code excluded |
2185 | | - * # ... see previous examples |
2186 | | - * |
2187 | | - * # Whoops! I deleted my local README, let me download/save it |
2188 | | - * # |
2189 | | - * $my_docs = $conn->get_container("documents"); |
2190 | | - * $doc = $my_docs->get_object("README"); |
2191 | | - * |
2192 | | - * $doc->save_to_filename("/home/ej/cloudfiles/readme.restored"); |
2193 | | - * </code> |
2194 | | - * |
2195 | | - * @param string $filename name of local file to write data to |
2196 | | - * @return boolean <kbd>True</kbd> if successful |
2197 | | - * @throws IOException error opening file |
2198 | | - * @throws InvalidResponseException unexpected response |
2199 | | - */ |
2200 | | - function save_to_filename($filename) |
2201 | | - { |
2202 | | - $fp = @fopen($filename, "wb"); |
2203 | | - if (!$fp) { |
2204 | | - throw new IOException("Could not open file for writing: ".$filename); |
2205 | | - } |
2206 | | - $result = $this->stream($fp); |
2207 | | - fclose($fp); |
2208 | | - return $result; |
2209 | | - } |
2210 | | - /** |
2211 | | - * Purge this Object from CDN Cache. |
2212 | | - * Example: |
2213 | | - * <code> |
2214 | | - * # ... authentication code excluded (see previous examples) ... |
2215 | | - * # |
2216 | | - * $conn = new CF_Authentication($auth); |
2217 | | - * $container = $conn->get_container("cdn_enabled"); |
2218 | | - * $obj = $container->get_object("object"); |
2219 | | - * $obj->purge_from_cdn("user@domain.com"); |
2220 | | - * # or |
2221 | | - * $obj->purge_from_cdn(); |
2222 | | - * # or |
2223 | | - * $obj->purge_from_cdn("user1@domain.com,user2@domain.com"); |
2224 | | - * @returns boolean True if successful |
2225 | | - * @throws CDNNotEnabledException if CDN Is not enabled on this connection |
2226 | | - * @throws InvalidResponseException if the response expected is not returned |
2227 | | - */ |
2228 | | - function purge_from_cdn($email=null) |
2229 | | - { |
2230 | | - if (!$this->container->cfs_http->getCDNMUrl()) |
2231 | | - { |
2232 | | - throw new CDNNotEnabledException( |
2233 | | - "Authentication response did not indicate CDN availability"); |
2234 | | - } |
2235 | | - $status = $this->container->cfs_http->purge_from_cdn($this->container->name . "/" . $this->name, $email); |
2236 | | - if ($status < 199 or $status > 299) { |
2237 | | - throw new InvalidResponseException( |
2238 | | - "Invalid response (".$status."): ".$this->container->cfs_http->get_error()); |
2239 | | - } |
2240 | | - return True; |
2241 | | - } |
2242 | | - |
2243 | | - /** |
2244 | | - * Set Object's MD5 checksum |
2245 | | - * |
2246 | | - * Manually set the Object's ETag. Including the ETag is mandatory for |
2247 | | - * Cloud Files to perform end-to-end verification. Omitting the ETag forces |
2248 | | - * the user to handle any data integrity checks. |
2249 | | - * |
2250 | | - * @param string $etag MD5 checksum hexidecimal string |
2251 | | - */ |
2252 | | - function set_etag($etag) |
2253 | | - { |
2254 | | - $this->etag = $etag; |
2255 | | - $this->_etag_override = True; |
2256 | | - } |
2257 | | - |
2258 | | - /** |
2259 | | - * Object's MD5 checksum |
2260 | | - * |
2261 | | - * Accessor method for reading Object's private ETag attribute. |
2262 | | - * |
2263 | | - * @return string MD5 checksum hexidecimal string |
2264 | | - */ |
2265 | | - function getETag() |
2266 | | - { |
2267 | | - return $this->etag; |
2268 | | - } |
2269 | | - |
2270 | | - /** |
2271 | | - * Compute the MD5 checksum |
2272 | | - * |
2273 | | - * Calculate the MD5 checksum on either a PHP resource or data. The argument |
2274 | | - * may either be a local filename, open resource for reading, or a string. |
2275 | | - * |
2276 | | - * <b>WARNING:</b> if you are uploading a big file over a stream |
2277 | | - * it could get very slow to compute the md5 you probably want to |
2278 | | - * set the $verify parameter to False in the write() method and |
2279 | | - * compute yourself the md5 before if you have it. |
2280 | | - * |
2281 | | - * @param filename|obj|string $data filename, open resource, or string |
2282 | | - * @return string MD5 checksum hexidecimal string |
2283 | | - */ |
2284 | | - function compute_md5sum(&$data) |
2285 | | - { |
2286 | | - |
2287 | | - if (function_exists("hash_init") && is_resource($data)) { |
2288 | | - $ctx = hash_init('md5'); |
2289 | | - while (!feof($data)) { |
2290 | | - $buffer = fgets($data, 65536); |
2291 | | - hash_update($ctx, $buffer); |
2292 | | - } |
2293 | | - $md5 = hash_final($ctx, false); |
2294 | | - rewind($data); |
2295 | | - } elseif ((string)is_file($data)) { |
2296 | | - $md5 = md5_file($data); |
2297 | | - } else { |
2298 | | - $md5 = md5($data); |
2299 | | - } |
2300 | | - return $md5; |
2301 | | - } |
2302 | | - |
2303 | | - /** |
2304 | | - * PRIVATE: fetch information about the remote Object if it exists |
2305 | | - */ |
2306 | | - private function _initialize() |
2307 | | - { |
2308 | | - list($status, $reason, $etag, $last_modified, $content_type, |
2309 | | - $content_length, $metadata) = |
2310 | | - $this->container->cfs_http->head_object($this); |
2311 | | - #if ($status == 401 && $this->_re_auth()) { |
2312 | | - # return $this->_initialize(); |
2313 | | - #} |
2314 | | - if ($status == 404) { |
2315 | | - return False; |
2316 | | - } |
2317 | | - if ($status < 200 || $status > 299) { |
2318 | | - throw new InvalidResponseException("Invalid response (".$status."): " |
2319 | | - . $this->container->cfs_http->get_error()); |
2320 | | - } |
2321 | | - $this->etag = $etag; |
2322 | | - $this->last_modified = $last_modified; |
2323 | | - $this->content_type = $content_type; |
2324 | | - $this->content_length = $content_length; |
2325 | | - $this->metadata = $metadata; |
2326 | | - $this->manifest = NULL; |
2327 | | - return True; |
2328 | | - } |
2329 | | - |
2330 | | - #private function _re_auth() |
2331 | | - #{ |
2332 | | - # $new_auth = new CF_Authentication( |
2333 | | - # $this->cfs_auth->username, |
2334 | | - # $this->cfs_auth->api_key, |
2335 | | - # $this->cfs_auth->auth_host, |
2336 | | - # $this->cfs_auth->account); |
2337 | | - # $new_auth->authenticate(); |
2338 | | - # $this->container->cfs_auth = $new_auth; |
2339 | | - # $this->container->cfs_http->setCFAuth($this->cfs_auth); |
2340 | | - # return True; |
2341 | | - #} |
2342 | | -} |
2343 | | - |
2344 | | -/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
2345 | | - |
2346 | | -/* |
2347 | | - * Local variables: |
2348 | | - * tab-width: 4 |
2349 | | - * c-basic-offset: 4 |
2350 | | - * c-hanging-comment-ender-p: nil |
2351 | | - * End: |
2352 | | - */ |
2353 | | -?> |
Index: trunk/extensions/SwiftMedia/php-cloudfiles/cloudfiles_http.php |
— | — | @@ -1,1397 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * This is an HTTP client class for Cloud Files. It uses PHP's cURL module |
5 | | - * to handle the actual HTTP request/response. This is NOT a generic HTTP |
6 | | - * client class and is only used to abstract out the HTTP communication for |
7 | | - * the PHP Cloud Files API. |
8 | | - * |
9 | | - * This module was designed to re-use existing HTTP(S) connections between |
10 | | - * subsequent operations. For example, performing multiple PUT operations |
11 | | - * will re-use the same connection. |
12 | | - * |
13 | | - * This modules also provides support for streaming content into and out |
14 | | - * of Cloud Files. The majority (all?) of the PHP HTTP client modules expect |
15 | | - * to read the server's response into a string variable. This will not work |
16 | | - * with large files without killing your server. Methods like, |
17 | | - * get_object_to_stream() and put_object() take an open filehandle |
18 | | - * argument for streaming data out of or into Cloud Files. |
19 | | - * |
20 | | - * Requres PHP 5.x (for Exceptions and OO syntax) |
21 | | - * |
22 | | - * See COPYING for license information. |
23 | | - * |
24 | | - * @author Eric "EJ" Johnson <ej@racklabs.com> |
25 | | - * @copyright Copyright (c) 2008, Rackspace US, Inc. |
26 | | - * @package php-cloudfiles-http |
27 | | - */ |
28 | | - |
29 | | -/** |
30 | | - */ |
31 | | -require_once("cloudfiles_exceptions.php"); |
32 | | - |
33 | | -define("PHP_CF_VERSION", "1.7.9"); |
34 | | -define("USER_AGENT", sprintf("PHP-CloudFiles/%s", PHP_CF_VERSION)); |
35 | | -define("ACCOUNT_CONTAINER_COUNT", "X-Account-Container-Count"); |
36 | | -define("ACCOUNT_BYTES_USED", "X-Account-Bytes-Used"); |
37 | | -define("CONTAINER_OBJ_COUNT", "X-Container-Object-Count"); |
38 | | -define("CONTAINER_BYTES_USED", "X-Container-Bytes-Used"); |
39 | | -define("METADATA_HEADER", "X-Object-Meta-"); |
40 | | -define("MANIFEST_HEADER", "X-Object-Manifest"); |
41 | | -define("CDN_URI", "X-CDN-URI"); |
42 | | -define("CDN_SSL_URI", "X-CDN-SSL-URI"); |
43 | | -define("CDN_ENABLED", "X-CDN-Enabled"); |
44 | | -define("CDN_LOG_RETENTION", "X-Log-Retention"); |
45 | | -define("CDN_ACL_USER_AGENT", "X-User-Agent-ACL"); |
46 | | -define("CDN_ACL_REFERRER", "X-Referrer-ACL"); |
47 | | -define("CDN_TTL", "X-TTL"); |
48 | | -define("CDNM_URL", "X-CDN-Management-Url"); |
49 | | -define("STORAGE_URL", "X-Storage-Url"); |
50 | | -define("AUTH_TOKEN", "X-Auth-Token"); |
51 | | -define("AUTH_USER_HEADER", "X-Auth-User"); |
52 | | -define("AUTH_KEY_HEADER", "X-Auth-Key"); |
53 | | -define("AUTH_USER_HEADER_LEGACY", "X-Storage-User"); |
54 | | -define("AUTH_KEY_HEADER_LEGACY", "X-Storage-Pass"); |
55 | | -define("AUTH_TOKEN_LEGACY", "X-Storage-Token"); |
56 | | -define("CDN_EMAIL", "X-Purge-Email"); |
57 | | -/** |
58 | | - * HTTP/cURL wrapper for Cloud Files |
59 | | - * |
60 | | - * This class should not be used directly. It's only purpose is to abstract |
61 | | - * out the HTTP communication from the main API. |
62 | | - * |
63 | | - * @package php-cloudfiles-http |
64 | | - */ |
65 | | -class CF_Http |
66 | | -{ |
67 | | - private $error_str; |
68 | | - private $dbug; |
69 | | - private $cabundle_path; |
70 | | - private $api_version; |
71 | | - |
72 | | - # Authentication instance variables |
73 | | - # |
74 | | - private $storage_url; |
75 | | - private $cdnm_url; |
76 | | - private $auth_token; |
77 | | - |
78 | | - # Request/response variables |
79 | | - # |
80 | | - private $response_status; |
81 | | - private $response_reason; |
82 | | - private $connections; |
83 | | - |
84 | | - # Variables used for content/header callbacks |
85 | | - # |
86 | | - private $_user_read_progress_callback_func; |
87 | | - private $_user_write_progress_callback_func; |
88 | | - private $_write_callback_type; |
89 | | - private $_text_list; |
90 | | - private $_account_container_count; |
91 | | - private $_account_bytes_used; |
92 | | - private $_container_object_count; |
93 | | - private $_container_bytes_used; |
94 | | - private $_obj_etag; |
95 | | - private $_obj_last_modified; |
96 | | - private $_obj_content_type; |
97 | | - private $_obj_content_length; |
98 | | - private $_obj_metadata; |
99 | | - private $_obj_manifest; |
100 | | - private $_obj_write_resource; |
101 | | - private $_obj_write_string; |
102 | | - private $_cdn_enabled; |
103 | | - private $_cdn_ssl_uri; |
104 | | - private $_cdn_uri; |
105 | | - private $_cdn_ttl; |
106 | | - private $_cdn_log_retention; |
107 | | - private $_cdn_acl_user_agent; |
108 | | - private $_cdn_acl_referrer; |
109 | | - |
110 | | - function __construct($api_version) |
111 | | - { |
112 | | - $this->dbug = False; |
113 | | - $this->cabundle_path = NULL; |
114 | | - $this->api_version = $api_version; |
115 | | - $this->error_str = NULL; |
116 | | - |
117 | | - $this->storage_url = NULL; |
118 | | - $this->cdnm_url = NULL; |
119 | | - $this->auth_token = NULL; |
120 | | - |
121 | | - $this->response_status = NULL; |
122 | | - $this->response_reason = NULL; |
123 | | - |
124 | | - # Curl connections array - since there is no way to "re-set" the |
125 | | - # connection paramaters for a cURL handle, we keep an array of |
126 | | - # the unique use-cases and funnel all of those same type |
127 | | - # requests through the appropriate curl connection. |
128 | | - # |
129 | | - $this->connections = array( |
130 | | - "GET_CALL" => NULL, # GET objects/containers/lists |
131 | | - "PUT_OBJ" => NULL, # PUT object |
132 | | - "HEAD" => NULL, # HEAD requests |
133 | | - "PUT_CONT" => NULL, # PUT container |
134 | | - "DEL_POST" => NULL, # DELETE containers/objects, POST objects |
135 | | - ); |
136 | | - |
137 | | - $this->_user_read_progress_callback_func = NULL; |
138 | | - $this->_user_write_progress_callback_func = NULL; |
139 | | - $this->_write_callback_type = NULL; |
140 | | - $this->_text_list = array(); |
141 | | - $this->_return_list = NULL; |
142 | | - $this->_account_container_count = 0; |
143 | | - $this->_account_bytes_used = 0; |
144 | | - $this->_container_object_count = 0; |
145 | | - $this->_container_bytes_used = 0; |
146 | | - $this->_obj_write_resource = NULL; |
147 | | - $this->_obj_write_string = ""; |
148 | | - $this->_obj_etag = NULL; |
149 | | - $this->_obj_last_modified = NULL; |
150 | | - $this->_obj_content_type = NULL; |
151 | | - $this->_obj_content_length = NULL; |
152 | | - $this->_obj_metadata = array(); |
153 | | - $this->_obj_manifest = NULL; |
154 | | - $this->_cdn_enabled = NULL; |
155 | | - $this->_cdn_ssl_uri = NULL; |
156 | | - $this->_cdn_uri = NULL; |
157 | | - $this->_cdn_ttl = NULL; |
158 | | - $this->_cdn_log_retention = NULL; |
159 | | - $this->_cdn_acl_user_agent = NULL; |
160 | | - $this->_cdn_acl_referrer = NULL; |
161 | | - |
162 | | - # The OS list with a PHP without an updated CA File for CURL to |
163 | | - # connect to SSL Websites. It is the first 3 letters of the PHP_OS |
164 | | - # variable. |
165 | | - $OS_CAFILE_NONUPDATED=array( |
166 | | - "win","dar" |
167 | | - ); |
168 | | - |
169 | | - if (in_array((strtolower (substr(PHP_OS, 0,3))), $OS_CAFILE_NONUPDATED)) |
170 | | - $this->ssl_use_cabundle(); |
171 | | - |
172 | | - } |
173 | | - |
174 | | - function ssl_use_cabundle($path=NULL) |
175 | | - { |
176 | | - if ($path) { |
177 | | - $this->cabundle_path = $path; |
178 | | - } else { |
179 | | - $this->cabundle_path = dirname(__FILE__) . "/share/cacert.pem"; |
180 | | - } |
181 | | - if (!file_exists($this->cabundle_path)) { |
182 | | - throw new IOException("Could not use CA bundle: " |
183 | | - . $this->cabundle_path); |
184 | | - } |
185 | | - return; |
186 | | - } |
187 | | - |
188 | | - # Uses separate cURL connection to authenticate |
189 | | - # |
190 | | - function authenticate($user, $pass, $acct=NULL, $host=NULL) |
191 | | - { |
192 | | - $path = array(); |
193 | | - if (isset($acct)){ |
194 | | - $headers = array( |
195 | | - sprintf("%s: %s", AUTH_USER_HEADER_LEGACY, $user), |
196 | | - sprintf("%s: %s", AUTH_KEY_HEADER_LEGACY, $pass), |
197 | | - ); |
198 | | - $path[] = $host; |
199 | | - $path[] = rawurlencode(sprintf("v%d",$this->api_version)); |
200 | | - $path[] = rawurlencode($acct); |
201 | | - } else { |
202 | | - $headers = array( |
203 | | - sprintf("%s: %s", AUTH_USER_HEADER, $user), |
204 | | - sprintf("%s: %s", AUTH_KEY_HEADER, $pass), |
205 | | - ); |
206 | | - $path[] = $host; |
207 | | - } |
208 | | - $path[] = "v1.0"; |
209 | | - $url = implode("/", $path); |
210 | | - |
211 | | - $curl_ch = curl_init(); |
212 | | - if (!is_null($this->cabundle_path)) { |
213 | | - curl_setopt($curl_ch, CURLOPT_SSL_VERIFYPEER, True); |
214 | | - curl_setopt($curl_ch, CURLOPT_CAINFO, $this->cabundle_path); |
215 | | - } |
216 | | - curl_setopt($curl_ch, CURLOPT_SSL_VERIFYPEER, False); |
217 | | - curl_setopt($curl_ch, CURLOPT_VERBOSE, $this->dbug); |
218 | | - curl_setopt($curl_ch, CURLOPT_FOLLOWLOCATION, 1); |
219 | | - curl_setopt($curl_ch, CURLOPT_MAXREDIRS, 4); |
220 | | - curl_setopt($curl_ch, CURLOPT_HEADER, 0); |
221 | | - curl_setopt($curl_ch, CURLOPT_HTTPHEADER, $headers); |
222 | | - curl_setopt($curl_ch, CURLOPT_USERAGENT, USER_AGENT); |
223 | | - curl_setopt($curl_ch, CURLOPT_RETURNTRANSFER, TRUE); |
224 | | - curl_setopt($curl_ch, CURLOPT_HEADERFUNCTION,array(&$this,'_auth_hdr_cb')); |
225 | | - curl_setopt($curl_ch, CURLOPT_CONNECTTIMEOUT, 10); |
226 | | - curl_setopt($curl_ch, CURLOPT_URL, $url); |
227 | | - curl_exec($curl_ch); |
228 | | - curl_close($curl_ch); |
229 | | - |
230 | | - return array($this->response_status, $this->response_reason, |
231 | | - $this->storage_url, $this->cdnm_url, $this->auth_token); |
232 | | - } |
233 | | - |
234 | | - # (CDN) GET /v1/Account |
235 | | - # |
236 | | - function list_cdn_containers($enabled_only) |
237 | | - { |
238 | | - $conn_type = "GET_CALL"; |
239 | | - $url_path = $this->_make_path("CDN"); |
240 | | - |
241 | | - $this->_write_callback_type = "TEXT_LIST"; |
242 | | - if ($enabled_only) |
243 | | - { |
244 | | - $return_code = $this->_send_request($conn_type, $url_path . |
245 | | - '/?enabled_only=true'); |
246 | | - } |
247 | | - else |
248 | | - { |
249 | | - $return_code = $this->_send_request($conn_type, $url_path); |
250 | | - } |
251 | | - if (!$return_code) { |
252 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
253 | | - array(0,$this->error_str,array()); |
254 | | - } |
255 | | - if ($return_code == 401) { |
256 | | - return array($return_code,"Unauthorized",array()); |
257 | | - } |
258 | | - if ($return_code == 404) { |
259 | | - return array($return_code,"Account not found.",array()); |
260 | | - } |
261 | | - if ($return_code == 204) { |
262 | | - return array($return_code,"Account has no CDN enabled Containers.", |
263 | | - array()); |
264 | | - } |
265 | | - if ($return_code == 200) { |
266 | | - $this->create_array(); |
267 | | - return array($return_code,$this->response_reason,$this->_text_list); |
268 | | - } |
269 | | - $this->error_str = "Unexpected HTTP response: ".$this->response_reason; |
270 | | - return array($return_code,$this->error_str,array()); |
271 | | - } |
272 | | - |
273 | | - # (CDN) DELETE /v1/Account/Container or /v1/Account/Container/Object |
274 | | - # |
275 | | - function purge_from_cdn($path, $email=null) |
276 | | - { |
277 | | - if(!$path) |
278 | | - throw new SyntaxException("Path not set"); |
279 | | - $url_path = $this->_make_path("CDN", NULL, $path); |
280 | | - if($email) |
281 | | - { |
282 | | - $hdrs = array(CDN_EMAIL => $email); |
283 | | - $return_code = $this->_send_request("DEL_POST",$url_path,$hdrs,"DELETE"); |
284 | | - } |
285 | | - else |
286 | | - $return_code = $this->_send_request("DEL_POST",$url_path,null,"DELETE"); |
287 | | - return $return_code; |
288 | | - } |
289 | | - |
290 | | - # (CDN) POST /v1/Account/Container |
291 | | - function update_cdn_container($container_name, $ttl=86400, $cdn_log_retention=False, |
292 | | - $cdn_acl_user_agent="", $cdn_acl_referrer) |
293 | | - { |
294 | | - if ($container_name == "") |
295 | | - throw new SyntaxException("Container name not set."); |
296 | | - |
297 | | - if ($container_name != "0" and !isset($container_name)) |
298 | | - throw new SyntaxException("Container name not set."); |
299 | | - |
300 | | - $url_path = $this->_make_path("CDN", $container_name); |
301 | | - $hdrs = array( |
302 | | - CDN_ENABLED => "True", |
303 | | - CDN_TTL => $ttl, |
304 | | - CDN_LOG_RETENTION => $cdn_log_retention ? "True" : "False", |
305 | | - CDN_ACL_USER_AGENT => $cdn_acl_user_agent, |
306 | | - CDN_ACL_REFERRER => $cdn_acl_referrer, |
307 | | - ); |
308 | | - $return_code = $this->_send_request("DEL_POST",$url_path,$hdrs,"POST"); |
309 | | - if ($return_code == 401) { |
310 | | - $this->error_str = "Unauthorized"; |
311 | | - return array($return_code, $this->error_str, NULL); |
312 | | - } |
313 | | - if ($return_code == 404) { |
314 | | - $this->error_str = "Container not found."; |
315 | | - return array($return_code, $this->error_str, NULL); |
316 | | - } |
317 | | - if ($return_code != 202) { |
318 | | - $this->error_str="Unexpected HTTP response: ".$this->response_reason; |
319 | | - return array($return_code, $this->error_str, NULL); |
320 | | - } |
321 | | - return array($return_code, "Accepted", $this->_cdn_uri, $this->_cdn_ssl_uri); |
322 | | - |
323 | | - } |
324 | | - |
325 | | - # (CDN) PUT /v1/Account/Container |
326 | | - # |
327 | | - function add_cdn_container($container_name, $ttl=86400) |
328 | | - { |
329 | | - if ($container_name == "") |
330 | | - throw new SyntaxException("Container name not set."); |
331 | | - |
332 | | - if ($container_name != "0" and !isset($container_name)) |
333 | | - throw new SyntaxException("Container name not set."); |
334 | | - |
335 | | - $url_path = $this->_make_path("CDN", $container_name); |
336 | | - $hdrs = array( |
337 | | - CDN_ENABLED => "True", |
338 | | - CDN_TTL => $ttl, |
339 | | - ); |
340 | | - $return_code = $this->_send_request("PUT_CONT", $url_path, $hdrs); |
341 | | - if ($return_code == 401) { |
342 | | - $this->error_str = "Unauthorized"; |
343 | | - return array($return_code,$this->response_reason,False); |
344 | | - } |
345 | | - if (!in_array($return_code, array(201,202))) { |
346 | | - $this->error_str="Unexpected HTTP response: ".$this->response_reason; |
347 | | - return array($return_code,$this->response_reason,False); |
348 | | - } |
349 | | - return array($return_code,$this->response_reason,$this->_cdn_uri, |
350 | | - $this->_cdn_ssl_uri); |
351 | | - } |
352 | | - |
353 | | - # (CDN) POST /v1/Account/Container |
354 | | - # |
355 | | - function remove_cdn_container($container_name) |
356 | | - { |
357 | | - if ($container_name == "") |
358 | | - throw new SyntaxException("Container name not set."); |
359 | | - |
360 | | - if ($container_name != "0" and !isset($container_name)) |
361 | | - throw new SyntaxException("Container name not set."); |
362 | | - |
363 | | - $url_path = $this->_make_path("CDN", $container_name); |
364 | | - $hdrs = array(CDN_ENABLED => "False"); |
365 | | - $return_code = $this->_send_request("DEL_POST",$url_path,$hdrs,"POST"); |
366 | | - if ($return_code == 401) { |
367 | | - $this->error_str = "Unauthorized"; |
368 | | - return array($return_code, $this->error_str); |
369 | | - } |
370 | | - if ($return_code == 404) { |
371 | | - $this->error_str = "Container not found."; |
372 | | - return array($return_code, $this->error_str); |
373 | | - } |
374 | | - if ($return_code != 202) { |
375 | | - $this->error_str="Unexpected HTTP response: ".$this->response_reason; |
376 | | - return array($return_code, $this->error_str); |
377 | | - } |
378 | | - return array($return_code, "Accepted"); |
379 | | - } |
380 | | - |
381 | | - # (CDN) HEAD /v1/Account |
382 | | - # |
383 | | - function head_cdn_container($container_name) |
384 | | - { |
385 | | - if ($container_name == "") |
386 | | - throw new SyntaxException("Container name not set."); |
387 | | - |
388 | | - if ($container_name != "0" and !isset($container_name)) |
389 | | - throw new SyntaxException("Container name not set."); |
390 | | - |
391 | | - $conn_type = "HEAD"; |
392 | | - $url_path = $this->_make_path("CDN", $container_name); |
393 | | - $return_code = $this->_send_request($conn_type, $url_path, NULL, "GET", True); |
394 | | - |
395 | | - if (!$return_code) { |
396 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
397 | | - return array(0,$this->error_str,NULL,NULL,NULL,NULL,NULL,NULL); |
398 | | - } |
399 | | - if ($return_code == 401) { |
400 | | - return array($return_code,"Unauthorized",NULL,NULL,NULL,NULL,NULL,NULL); |
401 | | - } |
402 | | - if ($return_code == 404) { |
403 | | - return array($return_code,"Account not found.",NULL,NULL,NULL,NULL,NULL,NULL); |
404 | | - } |
405 | | - if ($return_code == 204) { |
406 | | - return array($return_code,$this->response_reason, |
407 | | - $this->_cdn_enabled, $this->_cdn_ssl_uri, |
408 | | - $this->_cdn_uri, $this->_cdn_ttl, |
409 | | - $this->_cdn_log_retention, |
410 | | - $this->_cdn_acl_user_agent, |
411 | | - $this->_cdn_acl_referrer |
412 | | - ); |
413 | | - } |
414 | | - return array($return_code,$this->response_reason, |
415 | | - NULL,NULL,NULL, |
416 | | - $this->_cdn_log_retention, |
417 | | - $this->_cdn_acl_user_agent, |
418 | | - $this->_cdn_acl_referrer |
419 | | - ); |
420 | | - } |
421 | | - |
422 | | - # GET /v1/Account |
423 | | - # |
424 | | - function list_containers($limit=0, $marker=NULL) |
425 | | - { |
426 | | - $conn_type = "GET_CALL"; |
427 | | - $url_path = $this->_make_path(); |
428 | | - |
429 | | - $limit = intval($limit); |
430 | | - $params = array(); |
431 | | - if ($limit > 0) { |
432 | | - $params[] = "limit=$limit"; |
433 | | - } |
434 | | - if ($marker) { |
435 | | - $params[] = "marker=".rawurlencode($marker); |
436 | | - } |
437 | | - if (!empty($params)) { |
438 | | - $url_path .= "?" . implode("&", $params); |
439 | | - } |
440 | | - |
441 | | - $this->_write_callback_type = "TEXT_LIST"; |
442 | | - $return_code = $this->_send_request($conn_type, $url_path); |
443 | | - |
444 | | - if (!$return_code) { |
445 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
446 | | - return array(0,$this->error_str,array()); |
447 | | - } |
448 | | - if ($return_code == 204) { |
449 | | - return array($return_code, "Account has no containers.", array()); |
450 | | - } |
451 | | - if ($return_code == 404) { |
452 | | - $this->error_str = "Invalid account name for authentication token."; |
453 | | - return array($return_code,$this->error_str,array()); |
454 | | - } |
455 | | - if ($return_code == 200) { |
456 | | - $this->create_array(); |
457 | | - return array($return_code, $this->response_reason, $this->_text_list); |
458 | | - } |
459 | | - $this->error_str = "Unexpected HTTP response: ".$this->response_reason; |
460 | | - return array($return_code,$this->error_str,array()); |
461 | | - } |
462 | | - |
463 | | - # GET /v1/Account?format=json |
464 | | - # |
465 | | - function list_containers_info($limit=0, $marker=NULL) |
466 | | - { |
467 | | - $conn_type = "GET_CALL"; |
468 | | - $url_path = $this->_make_path() . "?format=json"; |
469 | | - |
470 | | - $limit = intval($limit); |
471 | | - $params = array(); |
472 | | - if ($limit > 0) { |
473 | | - $params[] = "limit=$limit"; |
474 | | - } |
475 | | - if ($marker) { |
476 | | - $params[] = "marker=".rawurlencode($marker); |
477 | | - } |
478 | | - if (!empty($params)) { |
479 | | - $url_path .= "&" . implode("&", $params); |
480 | | - } |
481 | | - |
482 | | - $this->_write_callback_type = "OBJECT_STRING"; |
483 | | - $return_code = $this->_send_request($conn_type, $url_path); |
484 | | - |
485 | | - if (!$return_code) { |
486 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
487 | | - return array(0,$this->error_str,array()); |
488 | | - } |
489 | | - if ($return_code == 204) { |
490 | | - return array($return_code, "Account has no containers.", array()); |
491 | | - } |
492 | | - if ($return_code == 404) { |
493 | | - $this->error_str = "Invalid account name for authentication token."; |
494 | | - return array($return_code,$this->error_str,array()); |
495 | | - } |
496 | | - if ($return_code == 200) { |
497 | | - $json_body = json_decode($this->_obj_write_string, True); |
498 | | - return array($return_code, $this->response_reason, $json_body); |
499 | | - } |
500 | | - $this->error_str = "Unexpected HTTP response: ".$this->response_reason; |
501 | | - return array($return_code,$this->error_str,array()); |
502 | | - } |
503 | | - |
504 | | - # HEAD /v1/Account |
505 | | - # |
506 | | - function head_account() |
507 | | - { |
508 | | - $conn_type = "HEAD"; |
509 | | - |
510 | | - $url_path = $this->_make_path(); |
511 | | - $return_code = $this->_send_request($conn_type,$url_path); |
512 | | - |
513 | | - if (!$return_code) { |
514 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
515 | | - array(0,$this->error_str,0,0); |
516 | | - } |
517 | | - if ($return_code == 404) { |
518 | | - return array($return_code,"Account not found.",0,0); |
519 | | - } |
520 | | - if ($return_code == 204) { |
521 | | - return array($return_code,$this->response_reason, |
522 | | - $this->_account_container_count, $this->_account_bytes_used); |
523 | | - } |
524 | | - return array($return_code,$this->response_reason,0,0); |
525 | | - } |
526 | | - |
527 | | - # PUT /v1/Account/Container |
528 | | - # |
529 | | - function create_container($container_name) |
530 | | - { |
531 | | - if ($container_name == "") |
532 | | - throw new SyntaxException("Container name not set."); |
533 | | - |
534 | | - if ($container_name != "0" and !isset($container_name)) |
535 | | - throw new SyntaxException("Container name not set."); |
536 | | - |
537 | | - $url_path = $this->_make_path("STORAGE", $container_name); |
538 | | - $return_code = $this->_send_request("PUT_CONT",$url_path); |
539 | | - |
540 | | - if (!$return_code) { |
541 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
542 | | - return False; |
543 | | - } |
544 | | - return $return_code; |
545 | | - } |
546 | | - |
547 | | - # DELETE /v1/Account/Container |
548 | | - # |
549 | | - function delete_container($container_name) |
550 | | - { |
551 | | - if ($container_name == "") |
552 | | - throw new SyntaxException("Container name not set."); |
553 | | - |
554 | | - if ($container_name != "0" and !isset($container_name)) |
555 | | - throw new SyntaxException("Container name not set."); |
556 | | - |
557 | | - $url_path = $this->_make_path("STORAGE", $container_name); |
558 | | - $return_code = $this->_send_request("DEL_POST",$url_path,array(),"DELETE"); |
559 | | - |
560 | | - if (!$return_code) { |
561 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
562 | | - } |
563 | | - if ($return_code == 409) { |
564 | | - $this->error_str = "Container must be empty prior to removing it."; |
565 | | - } |
566 | | - if ($return_code == 404) { |
567 | | - $this->error_str = "Specified container did not exist to delete."; |
568 | | - } |
569 | | - if ($return_code != 204) { |
570 | | - $this->error_str = "Unexpected HTTP return code: $return_code."; |
571 | | - } |
572 | | - return $return_code; |
573 | | - } |
574 | | - |
575 | | - # GET /v1/Account/Container |
576 | | - # |
577 | | - function list_objects($cname,$limit=0,$marker=NULL,$prefix=NULL,$path=NULL) |
578 | | - { |
579 | | - if (!$cname) { |
580 | | - $this->error_str = "Container name not set."; |
581 | | - return array(0, $this->error_str, array()); |
582 | | - } |
583 | | - |
584 | | - $url_path = $this->_make_path("STORAGE", $cname); |
585 | | - |
586 | | - $limit = intval($limit); |
587 | | - $params = array(); |
588 | | - if ($limit > 0) { |
589 | | - $params[] = "limit=$limit"; |
590 | | - } |
591 | | - if ($marker) { |
592 | | - $params[] = "marker=".rawurlencode($marker); |
593 | | - } |
594 | | - if ($prefix) { |
595 | | - $params[] = "prefix=".rawurlencode($prefix); |
596 | | - } |
597 | | - if ($path) { |
598 | | - $params[] = "path=".rawurlencode($path); |
599 | | - } |
600 | | - if (!empty($params)) { |
601 | | - $url_path .= "?" . implode("&", $params); |
602 | | - } |
603 | | - |
604 | | - $conn_type = "GET_CALL"; |
605 | | - $this->_write_callback_type = "TEXT_LIST"; |
606 | | - $return_code = $this->_send_request($conn_type,$url_path); |
607 | | - |
608 | | - if (!$return_code) { |
609 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
610 | | - return array(0,$this->error_str,array()); |
611 | | - } |
612 | | - if ($return_code == 204) { |
613 | | - $this->error_str = "Container has no Objects."; |
614 | | - return array($return_code,$this->error_str,array()); |
615 | | - } |
616 | | - if ($return_code == 404) { |
617 | | - $this->error_str = "Container has no Objects."; |
618 | | - return array($return_code,$this->error_str,array()); |
619 | | - } |
620 | | - if ($return_code == 200) { |
621 | | - $this->create_array(); |
622 | | - return array($return_code,$this->response_reason, $this->_text_list); |
623 | | - } |
624 | | - $this->error_str = "Unexpected HTTP response code: $return_code"; |
625 | | - return array(0,$this->error_str,array()); |
626 | | - } |
627 | | - |
628 | | - # GET /v1/Account/Container?format=json |
629 | | - # |
630 | | - function get_objects($cname,$limit=0,$marker=NULL,$prefix=NULL,$path=NULL) |
631 | | - { |
632 | | - if (!$cname) { |
633 | | - $this->error_str = "Container name not set."; |
634 | | - return array(0, $this->error_str, array()); |
635 | | - } |
636 | | - |
637 | | - $url_path = $this->_make_path("STORAGE", $cname); |
638 | | - |
639 | | - $limit = intval($limit); |
640 | | - $params = array(); |
641 | | - $params[] = "format=json"; |
642 | | - if ($limit > 0) { |
643 | | - $params[] = "limit=$limit"; |
644 | | - } |
645 | | - if ($marker) { |
646 | | - $params[] = "marker=".rawurlencode($marker); |
647 | | - } |
648 | | - if ($prefix) { |
649 | | - $params[] = "prefix=".rawurlencode($prefix); |
650 | | - } |
651 | | - if ($path) { |
652 | | - $params[] = "path=".rawurlencode($path); |
653 | | - } |
654 | | - if (!empty($params)) { |
655 | | - $url_path .= "?" . implode("&", $params); |
656 | | - } |
657 | | - |
658 | | - $conn_type = "GET_CALL"; |
659 | | - $this->_write_callback_type = "OBJECT_STRING"; |
660 | | - $return_code = $this->_send_request($conn_type,$url_path); |
661 | | - |
662 | | - if (!$return_code) { |
663 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
664 | | - return array(0,$this->error_str,array()); |
665 | | - } |
666 | | - if ($return_code == 204) { |
667 | | - $this->error_str = "Container has no Objects."; |
668 | | - return array($return_code,$this->error_str,array()); |
669 | | - } |
670 | | - if ($return_code == 404) { |
671 | | - $this->error_str = "Container has no Objects."; |
672 | | - return array($return_code,$this->error_str,array()); |
673 | | - } |
674 | | - if ($return_code == 200) { |
675 | | - $json_body = json_decode($this->_obj_write_string, True); |
676 | | - return array($return_code,$this->response_reason, $json_body); |
677 | | - } |
678 | | - $this->error_str = "Unexpected HTTP response code: $return_code"; |
679 | | - return array(0,$this->error_str,array()); |
680 | | - } |
681 | | - |
682 | | - |
683 | | - # HEAD /v1/Account/Container |
684 | | - # |
685 | | - function head_container($container_name) |
686 | | - { |
687 | | - |
688 | | - if ($container_name == "") { |
689 | | - $this->error_str = "Container name not set."; |
690 | | - return False; |
691 | | - } |
692 | | - |
693 | | - if ($container_name != "0" and !isset($container_name)) { |
694 | | - $this->error_str = "Container name not set."; |
695 | | - return False; |
696 | | - } |
697 | | - |
698 | | - $conn_type = "HEAD"; |
699 | | - |
700 | | - $url_path = $this->_make_path("STORAGE", $container_name); |
701 | | - $return_code = $this->_send_request($conn_type,$url_path); |
702 | | - |
703 | | - if (!$return_code) { |
704 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
705 | | - array(0,$this->error_str,0,0); |
706 | | - } |
707 | | - if ($return_code == 404) { |
708 | | - return array($return_code,"Container not found.",0,0); |
709 | | - } |
710 | | - if ($return_code == 204 || $return_code == 200) { |
711 | | - return array($return_code,$this->response_reason, |
712 | | - $this->_container_object_count, $this->_container_bytes_used); |
713 | | - } |
714 | | - return array($return_code,$this->response_reason,0,0); |
715 | | - } |
716 | | - |
717 | | - # GET /v1/Account/Container/Object |
718 | | - # |
719 | | - function get_object_to_string(&$obj, $hdrs=array()) |
720 | | - { |
721 | | - if (!is_object($obj) || get_class($obj) != "CF_Object") { |
722 | | - throw new SyntaxException( |
723 | | - "Method argument is not a valid CF_Object."); |
724 | | - } |
725 | | - |
726 | | - $conn_type = "GET_CALL"; |
727 | | - |
728 | | - $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name); |
729 | | - $this->_write_callback_type = "OBJECT_STRING"; |
730 | | - $return_code = $this->_send_request($conn_type,$url_path,$hdrs); |
731 | | - |
732 | | - if (!$return_code) { |
733 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
734 | | - return array($return_code0,$this->error_str,NULL); |
735 | | - } |
736 | | - if ($return_code == 404) { |
737 | | - $this->error_str = "Object not found."; |
738 | | - return array($return_code0,$this->error_str,NULL); |
739 | | - } |
740 | | - if (($return_code < 200) || ($return_code > 299 |
741 | | - && $return_code != 412 && $return_code != 304)) { |
742 | | - $this->error_str = "Unexpected HTTP return code: $return_code"; |
743 | | - return array($return_code,$this->error_str,NULL); |
744 | | - } |
745 | | - return array($return_code,$this->response_reason, $this->_obj_write_string); |
746 | | - } |
747 | | - |
748 | | - # GET /v1/Account/Container/Object |
749 | | - # |
750 | | - function get_object_to_stream(&$obj, &$resource=NULL, $hdrs=array()) |
751 | | - { |
752 | | - if (!is_object($obj) || get_class($obj) != "CF_Object") { |
753 | | - throw new SyntaxException( |
754 | | - "Method argument is not a valid CF_Object."); |
755 | | - } |
756 | | - if (!is_resource($resource)) { |
757 | | - throw new SyntaxException( |
758 | | - "Resource argument not a valid PHP resource."); |
759 | | - } |
760 | | - |
761 | | - $conn_type = "GET_CALL"; |
762 | | - |
763 | | - $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name); |
764 | | - $this->_obj_write_resource = $resource; |
765 | | - $this->_write_callback_type = "OBJECT_STREAM"; |
766 | | - $return_code = $this->_send_request($conn_type,$url_path,$hdrs); |
767 | | - |
768 | | - if (!$return_code) { |
769 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
770 | | - return array($return_code,$this->error_str); |
771 | | - } |
772 | | - if ($return_code == 404) { |
773 | | - $this->error_str = "Object not found."; |
774 | | - return array($return_code,$this->error_str); |
775 | | - } |
776 | | - if (($return_code < 200) || ($return_code > 299 |
777 | | - && $return_code != 412 && $return_code != 304)) { |
778 | | - $this->error_str = "Unexpected HTTP return code: $return_code"; |
779 | | - return array($return_code,$this->error_str); |
780 | | - } |
781 | | - return array($return_code,$this->response_reason); |
782 | | - } |
783 | | - |
784 | | - # PUT /v1/Account/Container/Object |
785 | | - # |
786 | | - function put_object(&$obj, &$fp) |
787 | | - { |
788 | | - if (!is_object($obj) || get_class($obj) != "CF_Object") { |
789 | | - throw new SyntaxException( |
790 | | - "Method argument is not a valid CF_Object."); |
791 | | - } |
792 | | - $source = NULL; |
793 | | - if (is_string($fp)) { |
794 | | - $source = $fp; |
795 | | - } elseif (!is_resource($fp)) { |
796 | | - throw new SyntaxException( |
797 | | - "File pointer argument is not a valid resource."); |
798 | | - } |
799 | | - |
800 | | - $conn_type = "PUT_OBJ"; |
801 | | - $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name); |
802 | | - |
803 | | - $hdrs = $this->_metadata_headers($obj); |
804 | | - |
805 | | - $etag = $obj->getETag(); |
806 | | - if (!$source && isset($etag)) { |
807 | | - $hdrs[] = "ETag: " . $etag; |
808 | | - } |
809 | | - if ($source) { |
810 | | - // If we don't include a content-type it will copy over the existing one. |
811 | | - } elseif (!$obj->content_type) { |
812 | | - $hdrs[] = "Content-Type: application/octet-stream"; |
813 | | - } else { |
814 | | - $hdrs[] = "Content-Type: " . $obj->content_type; |
815 | | - } |
816 | | - |
817 | | - $this->_init($conn_type); |
818 | | - if ($source) { |
819 | | - $hdrs[] = "X-Copy-From: " . rawurlencode($source); |
820 | | - curl_setopt($this->connections[$conn_type], |
821 | | - CURLOPT_INFILESIZE, 0); |
822 | | - } else { |
823 | | - curl_setopt($this->connections[$conn_type], |
824 | | - CURLOPT_INFILE, $fp); |
825 | | - if (!$obj->content_length) { |
826 | | - # We don''t know the Content-Length, so assumed "chunked" PUT |
827 | | - # |
828 | | - curl_setopt($this->connections[$conn_type], CURLOPT_UPLOAD, True); |
829 | | - $hdrs[] = 'Transfer-Encoding: chunked'; |
830 | | - } else { |
831 | | - # We know the Content-Length, so use regular transfer |
832 | | - # |
833 | | - curl_setopt($this->connections[$conn_type], |
834 | | - CURLOPT_INFILESIZE, $obj->content_length); |
835 | | - } |
836 | | - } |
837 | | - $return_code = $this->_send_request($conn_type,$url_path,$hdrs); |
838 | | - |
839 | | - if (!$return_code) { |
840 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
841 | | - return array(0,$this->error_str,NULL); |
842 | | - } |
843 | | - if ($return_code == 412) { |
844 | | - $this->error_str = "Missing Content-Type header"; |
845 | | - return array($return_code,$this->error_str,NULL); |
846 | | - } |
847 | | - if ($return_code == 422) { |
848 | | - $this->error_str = "Derived and computed checksums do not match."; |
849 | | - return array($return_code,$this->error_str,NULL); |
850 | | - } |
851 | | - if ($return_code != 201) { |
852 | | - $this->error_str = "Unexpected HTTP return code: $return_code"; |
853 | | - return array($return_code,$this->error_str,NULL); |
854 | | - } |
855 | | - return array($return_code,$this->response_reason,$this->_obj_etag); |
856 | | - } |
857 | | - |
858 | | - # POST /v1/Account/Container/Object |
859 | | - # |
860 | | - function update_object(&$obj) |
861 | | - { |
862 | | - if (!is_object($obj) || get_class($obj) != "CF_Object") { |
863 | | - throw new SyntaxException( |
864 | | - "Method argument is not a valid CF_Object."); |
865 | | - } |
866 | | - |
867 | | - if (!is_array($obj->metadata) && !$obj->manifest) { |
868 | | - |
869 | | - $this->error_str = "Metadata array is empty."; |
870 | | - return 0; |
871 | | - } |
872 | | - |
873 | | - $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name); |
874 | | - |
875 | | - $hdrs = $this->_metadata_headers($obj); |
876 | | - $return_code = $this->_send_request("DEL_POST",$url_path,$hdrs,"POST"); |
877 | | - if (!$return_code) { |
878 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
879 | | - return 0; |
880 | | - } |
881 | | - if ($return_code == 404) { |
882 | | - $this->error_str = "Account, Container, or Object not found."; |
883 | | - } |
884 | | - if ($return_code != 202) { |
885 | | - $this->error_str = "Unexpected HTTP return code: $return_code"; |
886 | | - } |
887 | | - return $return_code; |
888 | | - } |
889 | | - |
890 | | - # HEAD /v1/Account/Container/Object |
891 | | - # |
892 | | - function head_object(&$obj) |
893 | | - { |
894 | | - if (!is_object($obj) || get_class($obj) != "CF_Object") { |
895 | | - throw new SyntaxException( |
896 | | - "Method argument is not a valid CF_Object."); |
897 | | - } |
898 | | - |
899 | | - $conn_type = "HEAD"; |
900 | | - |
901 | | - $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name); |
902 | | - $return_code = $this->_send_request($conn_type,$url_path); |
903 | | - |
904 | | - if (!$return_code) { |
905 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
906 | | - return array(0, $this->error_str." ".$this->response_reason, |
907 | | - NULL, NULL, NULL, NULL, array()); |
908 | | - } |
909 | | - |
910 | | - if ($return_code == 404) { |
911 | | - return array($return_code, $this->response_reason, |
912 | | - NULL, NULL, NULL, NULL, array()); |
913 | | - } |
914 | | - if ($return_code == 204 || $return_code == 200) { |
915 | | - return array($return_code,$this->response_reason, |
916 | | - $this->_obj_etag, |
917 | | - $this->_obj_last_modified, |
918 | | - $this->_obj_content_type, |
919 | | - $this->_obj_content_length, |
920 | | - $this->_obj_metadata, |
921 | | - $this->_obj_manifest); |
922 | | - } |
923 | | - $this->error_str = "Unexpected HTTP return code: $return_code"; |
924 | | - return array($return_code, $this->error_str." ".$this->response_reason, |
925 | | - NULL, NULL, NULL, NULL, array()); |
926 | | - } |
927 | | - |
928 | | - # DELETE /v1/Account/Container/Object |
929 | | - # |
930 | | - function delete_object($container_name, $object_name) |
931 | | - { |
932 | | - if ($container_name == "") { |
933 | | - $this->error_str = "Container name not set."; |
934 | | - return 0; |
935 | | - } |
936 | | - |
937 | | - if ($container_name != "0" and !isset($container_name)) { |
938 | | - $this->error_str = "Container name not set."; |
939 | | - return 0; |
940 | | - } |
941 | | - |
942 | | - if (!$object_name) { |
943 | | - $this->error_str = "Object name not set."; |
944 | | - return 0; |
945 | | - } |
946 | | - |
947 | | - $url_path = $this->_make_path("STORAGE", $container_name,$object_name); |
948 | | - $return_code = $this->_send_request("DEL_POST",$url_path,NULL,"DELETE"); |
949 | | - if (!$return_code) { |
950 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
951 | | - return 0; |
952 | | - } |
953 | | - if ($return_code == 404) { |
954 | | - $this->error_str = "Specified container did not exist to delete."; |
955 | | - } |
956 | | - if ($return_code != 204) { |
957 | | - $this->error_str = "Unexpected HTTP return code: $return_code."; |
958 | | - } |
959 | | - return $return_code; |
960 | | - } |
961 | | - |
962 | | - function get_error() |
963 | | - { |
964 | | - return $this->error_str; |
965 | | - } |
966 | | - |
967 | | - function setDebug($bool) |
968 | | - { |
969 | | - $this->dbug = $bool; |
970 | | - foreach ($this->connections as $k => $v) { |
971 | | - if (!is_null($v)) { |
972 | | - curl_setopt($this->connections[$k], CURLOPT_VERBOSE, $this->dbug); |
973 | | - } |
974 | | - } |
975 | | - } |
976 | | - |
977 | | - function getCDNMUrl() |
978 | | - { |
979 | | - return $this->cdnm_url; |
980 | | - } |
981 | | - |
982 | | - function getStorageUrl() |
983 | | - { |
984 | | - return $this->storage_url; |
985 | | - } |
986 | | - |
987 | | - function getAuthToken() |
988 | | - { |
989 | | - return $this->auth_token; |
990 | | - } |
991 | | - |
992 | | - function setCFAuth($cfs_auth, $servicenet=False) |
993 | | - { |
994 | | - if ($servicenet) { |
995 | | - $this->storage_url = "https://snet-" . substr($cfs_auth->storage_url, 8); |
996 | | - } else { |
997 | | - $this->storage_url = $cfs_auth->storage_url; |
998 | | - } |
999 | | - $this->auth_token = $cfs_auth->auth_token; |
1000 | | - $this->cdnm_url = $cfs_auth->cdnm_url; |
1001 | | - } |
1002 | | - |
1003 | | - function setReadProgressFunc($func_name) |
1004 | | - { |
1005 | | - $this->_user_read_progress_callback_func = $func_name; |
1006 | | - } |
1007 | | - |
1008 | | - function setWriteProgressFunc($func_name) |
1009 | | - { |
1010 | | - $this->_user_write_progress_callback_func = $func_name; |
1011 | | - } |
1012 | | - |
1013 | | - private function _header_cb($ch, $header) |
1014 | | - { |
1015 | | - preg_match("/^HTTP\/1\.[01] (\d{3}) (.*)/", $header, $matches); |
1016 | | - if (isset($matches[1])) { |
1017 | | - $this->response_status = $matches[1]; |
1018 | | - } |
1019 | | - if (isset($matches[2])) { |
1020 | | - $this->response_reason = $matches[2]; |
1021 | | - } |
1022 | | - if (stripos($header, CDN_ENABLED) === 0) { |
1023 | | - $val = trim(substr($header, strlen(CDN_ENABLED)+1)); |
1024 | | - if (strtolower($val) == "true") { |
1025 | | - $this->_cdn_enabled = True; |
1026 | | - } elseif (strtolower($val) == "false") { |
1027 | | - $this->_cdn_enabled = False; |
1028 | | - } else { |
1029 | | - $this->_cdn_enabled = NULL; |
1030 | | - } |
1031 | | - return strlen($header); |
1032 | | - } |
1033 | | - if (stripos($header, CDN_URI) === 0) { |
1034 | | - $this->_cdn_uri = trim(substr($header, strlen(CDN_URI)+1)); |
1035 | | - return strlen($header); |
1036 | | - } |
1037 | | - if (stripos($header, CDN_SSL_URI) === 0) { |
1038 | | - $this->_cdn_ssl_uri = trim(substr($header, strlen(CDN_SSL_URI)+1)); |
1039 | | - return strlen($header); |
1040 | | - } |
1041 | | - if (stripos($header, CDN_TTL) === 0) { |
1042 | | - $this->_cdn_ttl = trim(substr($header, strlen(CDN_TTL)+1))+0; |
1043 | | - return strlen($header); |
1044 | | - } |
1045 | | - if (stripos($header, MANIFEST_HEADER) === 0) { |
1046 | | - $this->_obj_manifest = trim(substr($header, strlen(MANIFEST_HEADER)+1)); |
1047 | | - return strlen($header); |
1048 | | - } |
1049 | | - if (stripos($header, CDN_LOG_RETENTION) === 0) { |
1050 | | - $this->_cdn_log_retention = |
1051 | | - trim(substr($header, strlen(CDN_LOG_RETENTION)+1)) == "True" ? True : False; |
1052 | | - return strlen($header); |
1053 | | - } |
1054 | | - |
1055 | | - if (stripos($header, CDN_ACL_USER_AGENT) === 0) { |
1056 | | - $this->_cdn_acl_user_agent = |
1057 | | - trim(substr($header, strlen(CDN_ACL_USER_AGENT)+1)); |
1058 | | - return strlen($header); |
1059 | | - } |
1060 | | - |
1061 | | - if (stripos($header, CDN_ACL_REFERRER) === 0) { |
1062 | | - $this->_cdn_acl_referrer = |
1063 | | - trim(substr($header, strlen(CDN_ACL_REFERRER)+1)); |
1064 | | - return strlen($header); |
1065 | | - } |
1066 | | - |
1067 | | - if (stripos($header, ACCOUNT_CONTAINER_COUNT) === 0) { |
1068 | | - $this->_account_container_count = (float) trim(substr($header, |
1069 | | - strlen(ACCOUNT_CONTAINER_COUNT)+1))+0; |
1070 | | - return strlen($header); |
1071 | | - } |
1072 | | - if (stripos($header, ACCOUNT_BYTES_USED) === 0) { |
1073 | | - $this->_account_bytes_used = (float) trim(substr($header, |
1074 | | - strlen(ACCOUNT_BYTES_USED)+1))+0; |
1075 | | - return strlen($header); |
1076 | | - } |
1077 | | - if (stripos($header, CONTAINER_OBJ_COUNT) === 0) { |
1078 | | - $this->_container_object_count = (float) trim(substr($header, |
1079 | | - strlen(CONTAINER_OBJ_COUNT)+1))+0; |
1080 | | - return strlen($header); |
1081 | | - } |
1082 | | - if (stripos($header, CONTAINER_BYTES_USED) === 0) { |
1083 | | - $this->_container_bytes_used = (float) trim(substr($header, |
1084 | | - strlen(CONTAINER_BYTES_USED)+1))+0; |
1085 | | - return strlen($header); |
1086 | | - } |
1087 | | - if (stripos($header, METADATA_HEADER) === 0) { |
1088 | | - # $header => X-Object-Meta-Foo: bar baz |
1089 | | - $temp = substr($header, strlen(METADATA_HEADER)); |
1090 | | - # $temp => Foo: bar baz |
1091 | | - $parts = explode(":", $temp); |
1092 | | - # $parts[0] => Foo |
1093 | | - $val = substr(strstr($temp, ":"), 1); |
1094 | | - # $val => bar baz |
1095 | | - $this->_obj_metadata[$parts[0]] = trim($val); |
1096 | | - return strlen($header); |
1097 | | - } |
1098 | | - if (stripos($header, "ETag:") === 0) { |
1099 | | - # $header => ETag: abc123def456... |
1100 | | - $val = substr(strstr($header, ":"), 1); |
1101 | | - # $val => abc123def456... |
1102 | | - $this->_obj_etag = trim($val); |
1103 | | - return strlen($header); |
1104 | | - } |
1105 | | - if (stripos($header, "Last-Modified:") === 0) { |
1106 | | - $val = substr(strstr($header, ":"), 1); |
1107 | | - $this->_obj_last_modified = trim($val); |
1108 | | - return strlen($header); |
1109 | | - } |
1110 | | - if (stripos($header, "Content-Type:") === 0) { |
1111 | | - $val = substr(strstr($header, ":"), 1); |
1112 | | - $this->_obj_content_type = trim($val); |
1113 | | - return strlen($header); |
1114 | | - } |
1115 | | - if (stripos($header, "Content-Length:") === 0) { |
1116 | | - $val = substr(strstr($header, ":"), 1); |
1117 | | - $this->_obj_content_length = (float) trim($val)+0; |
1118 | | - return strlen($header); |
1119 | | - } |
1120 | | - return strlen($header); |
1121 | | - } |
1122 | | - |
1123 | | - private function _read_cb($ch, $fd, $length) |
1124 | | - { |
1125 | | - $data = fread($fd, $length); |
1126 | | - $len = strlen($data); |
1127 | | - if (isset($this->_user_write_progress_callback_func)) { |
1128 | | - call_user_func($this->_user_write_progress_callback_func, $len); |
1129 | | - } |
1130 | | - return $data; |
1131 | | - } |
1132 | | - |
1133 | | - private function _write_cb($ch, $data) |
1134 | | - { |
1135 | | - $dlen = strlen($data); |
1136 | | - switch ($this->_write_callback_type) { |
1137 | | - case "TEXT_LIST": |
1138 | | - $this->_return_list = $this->_return_list . $data; |
1139 | | - //= explode("\n",$data); # keep tab,space |
1140 | | - //his->_text_list[] = rtrim($data,"\n\r\x0B"); # keep tab,space |
1141 | | - break; |
1142 | | - case "OBJECT_STREAM": |
1143 | | - fwrite($this->_obj_write_resource, $data, $dlen); |
1144 | | - break; |
1145 | | - case "OBJECT_STRING": |
1146 | | - $this->_obj_write_string .= $data; |
1147 | | - break; |
1148 | | - } |
1149 | | - if (isset($this->_user_read_progress_callback_func)) { |
1150 | | - call_user_func($this->_user_read_progress_callback_func, $dlen); |
1151 | | - } |
1152 | | - return $dlen; |
1153 | | - } |
1154 | | - |
1155 | | - private function _auth_hdr_cb($ch, $header) |
1156 | | - { |
1157 | | - preg_match("/^HTTP\/1\.[01] (\d{3}) (.*)/", $header, $matches); |
1158 | | - if (isset($matches[1])) { |
1159 | | - $this->response_status = $matches[1]; |
1160 | | - } |
1161 | | - if (isset($matches[2])) { |
1162 | | - $this->response_reason = $matches[2]; |
1163 | | - } |
1164 | | - if (stripos($header, STORAGE_URL) === 0) { |
1165 | | - $this->storage_url = trim(substr($header, strlen(STORAGE_URL)+1)); |
1166 | | - } |
1167 | | - if (stripos($header, CDNM_URL) === 0) { |
1168 | | - $this->cdnm_url = trim(substr($header, strlen(CDNM_URL)+1)); |
1169 | | - } |
1170 | | - if (stripos($header, AUTH_TOKEN) === 0) { |
1171 | | - $this->auth_token = trim(substr($header, strlen(AUTH_TOKEN)+1)); |
1172 | | - } |
1173 | | - if (stripos($header, AUTH_TOKEN_LEGACY) === 0) { |
1174 | | - $this->auth_token = trim(substr($header,strlen(AUTH_TOKEN_LEGACY)+1)); |
1175 | | - } |
1176 | | - return strlen($header); |
1177 | | - } |
1178 | | - |
1179 | | - private function _make_headers($hdrs=NULL) |
1180 | | - { |
1181 | | - $new_headers = array(); |
1182 | | - $has_stoken = False; |
1183 | | - $has_uagent = False; |
1184 | | - if (is_array($hdrs)) { |
1185 | | - foreach ($hdrs as $h => $v) { |
1186 | | - if (is_int($h)) { |
1187 | | - $parts = explode(":", $v); |
1188 | | - $header = $parts[0]; |
1189 | | - $value = trim(substr(strstr($v, ":"), 1)); |
1190 | | - } else { |
1191 | | - $header = $h; |
1192 | | - $value = trim($v); |
1193 | | - } |
1194 | | - |
1195 | | - if (stripos($header, AUTH_TOKEN) === 0) { |
1196 | | - $has_stoken = True; |
1197 | | - } |
1198 | | - if (stripos($header, "user-agent") === 0) { |
1199 | | - $has_uagent = True; |
1200 | | - } |
1201 | | - $new_headers[] = $header . ": " . $value; |
1202 | | - } |
1203 | | - } |
1204 | | - if (!$has_stoken) { |
1205 | | - $new_headers[] = AUTH_TOKEN . ": " . $this->auth_token; |
1206 | | - } |
1207 | | - if (!$has_uagent) { |
1208 | | - $new_headers[] = "User-Agent: " . USER_AGENT; |
1209 | | - } |
1210 | | - return $new_headers; |
1211 | | - } |
1212 | | - |
1213 | | - private function _init($conn_type, $force_new=False) |
1214 | | - { |
1215 | | - if (!array_key_exists($conn_type, $this->connections)) { |
1216 | | - $this->error_str = "Invalid CURL_XXX connection type"; |
1217 | | - return False; |
1218 | | - } |
1219 | | - |
1220 | | - if (is_null($this->connections[$conn_type]) || $force_new) { |
1221 | | - $ch = curl_init(); |
1222 | | - } else { |
1223 | | - return; |
1224 | | - } |
1225 | | - |
1226 | | - if ($this->dbug) { curl_setopt($ch, CURLOPT_VERBOSE, 1); } |
1227 | | - |
1228 | | - if (!is_null($this->cabundle_path)) { |
1229 | | - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, True); |
1230 | | - curl_setopt($ch, CURLOPT_CAINFO, $this->cabundle_path); |
1231 | | - } |
1232 | | - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, False); |
1233 | | - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); |
1234 | | - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); |
1235 | | - curl_setopt($ch, CURLOPT_MAXREDIRS, 4); |
1236 | | - curl_setopt($ch, CURLOPT_HEADER, 0); |
1237 | | - curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$this, '_header_cb')); |
1238 | | - |
1239 | | - if ($conn_type == "GET_CALL") { |
1240 | | - curl_setopt($ch, CURLOPT_WRITEFUNCTION, array(&$this, '_write_cb')); |
1241 | | - } |
1242 | | - |
1243 | | - if ($conn_type == "PUT_OBJ") { |
1244 | | - curl_setopt($ch, CURLOPT_PUT, 1); |
1245 | | - curl_setopt($ch, CURLOPT_READFUNCTION, array(&$this, '_read_cb')); |
1246 | | - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
1247 | | - } |
1248 | | - if ($conn_type == "HEAD") { |
1249 | | - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "HEAD"); |
1250 | | - curl_setopt($ch, CURLOPT_NOBODY, 1); |
1251 | | - } |
1252 | | - if ($conn_type == "PUT_CONT") { |
1253 | | - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); |
1254 | | - curl_setopt($ch, CURLOPT_INFILESIZE, 0); |
1255 | | - curl_setopt($ch, CURLOPT_NOBODY, 1); |
1256 | | - } |
1257 | | - if ($conn_type == "DEL_POST") { |
1258 | | - curl_setopt($ch, CURLOPT_NOBODY, 1); |
1259 | | - } |
1260 | | - $this->connections[$conn_type] = $ch; |
1261 | | - return; |
1262 | | - } |
1263 | | - |
1264 | | - private function _reset_callback_vars() |
1265 | | - { |
1266 | | - $this->_text_list = array(); |
1267 | | - $this->_return_list = NULL; |
1268 | | - $this->_account_container_count = 0; |
1269 | | - $this->_account_bytes_used = 0; |
1270 | | - $this->_container_object_count = 0; |
1271 | | - $this->_container_bytes_used = 0; |
1272 | | - $this->_obj_etag = NULL; |
1273 | | - $this->_obj_last_modified = NULL; |
1274 | | - $this->_obj_content_type = NULL; |
1275 | | - $this->_obj_content_length = NULL; |
1276 | | - $this->_obj_metadata = array(); |
1277 | | - $this->_obj_manifest = NULL; |
1278 | | - $this->_obj_write_string = ""; |
1279 | | - $this->_cdn_enabled = NULL; |
1280 | | - $this->_cdn_ssl_uri = NULL; |
1281 | | - $this->_cdn_uri = NULL; |
1282 | | - $this->_cdn_ttl = NULL; |
1283 | | - $this->response_status = 0; |
1284 | | - $this->response_reason = ""; |
1285 | | - } |
1286 | | - |
1287 | | - private function _make_path($t="STORAGE",$c=NULL,$o=NULL) |
1288 | | - { |
1289 | | - $path = array(); |
1290 | | - switch ($t) { |
1291 | | - case "STORAGE": |
1292 | | - $path[] = $this->storage_url; break; |
1293 | | - case "CDN": |
1294 | | - $path[] = $this->cdnm_url; break; |
1295 | | - } |
1296 | | - if ($c == "0") |
1297 | | - $path[] = rawurlencode($c); |
1298 | | - |
1299 | | - if ($c) { |
1300 | | - $path[] = rawurlencode($c); |
1301 | | - } |
1302 | | - if ($o) { |
1303 | | - # mimic Python''s urllib.quote() feature of a "safe" '/' character |
1304 | | - # |
1305 | | - $path[] = str_replace("%2F","/",rawurlencode($o)); |
1306 | | - } |
1307 | | - return implode("/",$path); |
1308 | | - } |
1309 | | - |
1310 | | - private function _metadata_headers(&$obj) |
1311 | | - { |
1312 | | - $hdrs = array(); |
1313 | | - if ($obj->manifest) |
1314 | | - $hdrs[MANIFEST_HEADER] = $obj->manifest; |
1315 | | - foreach ($obj->metadata as $k => $v) { |
1316 | | - if (strpos($k,":") !== False) { |
1317 | | - throw new SyntaxException( |
1318 | | - "Metadata keys cannot contain a ':' character."); |
1319 | | - } |
1320 | | - $k = trim($k); |
1321 | | - $key = sprintf("%s%s", METADATA_HEADER, $k); |
1322 | | - if (!array_key_exists($key, $hdrs)) { |
1323 | | - if (strlen($k) > 128 || strlen($v) > 256) { |
1324 | | - $this->error_str = "Metadata key or value exceeds "; |
1325 | | - $this->error_str .= "maximum length: ($k: $v)"; |
1326 | | - return 0; |
1327 | | - } |
1328 | | - $hdrs[] = sprintf("%s%s: %s", METADATA_HEADER, $k, trim($v)); |
1329 | | - } |
1330 | | - } |
1331 | | - return $hdrs; |
1332 | | - } |
1333 | | - |
1334 | | - private function _send_request($conn_type, $url_path, $hdrs=NULL, $method="GET", $force_new=False) |
1335 | | - { |
1336 | | - $this->_init($conn_type, $force_new); |
1337 | | - $this->_reset_callback_vars(); |
1338 | | - $headers = $this->_make_headers($hdrs); |
1339 | | - |
1340 | | - if (gettype($this->connections[$conn_type]) == "unknown type") |
1341 | | - throw new ConnectionNotOpenException ( |
1342 | | - "Connection is not open." |
1343 | | - ); |
1344 | | - |
1345 | | - switch ($method) { |
1346 | | - case "DELETE": |
1347 | | - curl_setopt($this->connections[$conn_type], |
1348 | | - CURLOPT_CUSTOMREQUEST, "DELETE"); |
1349 | | - break; |
1350 | | - case "POST": |
1351 | | - curl_setopt($this->connections[$conn_type], |
1352 | | - CURLOPT_CUSTOMREQUEST, "POST"); |
1353 | | - default: |
1354 | | - break; |
1355 | | - } |
1356 | | - |
1357 | | - curl_setopt($this->connections[$conn_type], |
1358 | | - CURLOPT_HTTPHEADER, $headers); |
1359 | | - |
1360 | | - curl_setopt($this->connections[$conn_type], |
1361 | | - CURLOPT_URL, $url_path); |
1362 | | - |
1363 | | - if (!curl_exec($this->connections[$conn_type]) && curl_errno($this->connections[$conn_type]) !== 0) { |
1364 | | - $this->error_str = "(curl error: " |
1365 | | - . curl_errno($this->connections[$conn_type]) . ") "; |
1366 | | - $this->error_str .= curl_error($this->connections[$conn_type]); |
1367 | | - return False; |
1368 | | - } |
1369 | | - return curl_getinfo($this->connections[$conn_type], CURLINFO_HTTP_CODE); |
1370 | | - } |
1371 | | - |
1372 | | - function close() |
1373 | | - { |
1374 | | - foreach ($this->connections as $cnx) { |
1375 | | - if (isset($cnx)) { |
1376 | | - curl_close($cnx); |
1377 | | - $this->connections[$cnx] = NULL; |
1378 | | - } |
1379 | | - } |
1380 | | - } |
1381 | | - private function create_array() |
1382 | | - { |
1383 | | - $this->_text_list = explode("\n",rtrim($this->_return_list,"\n\x0B")); |
1384 | | - return True; |
1385 | | - } |
1386 | | - |
1387 | | -} |
1388 | | - |
1389 | | -/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
1390 | | - |
1391 | | -/* |
1392 | | - * Local variables: |
1393 | | - * tab-width: 4 |
1394 | | - * c-basic-offset: 4 |
1395 | | - * c-hanging-comment-ender-p: nil |
1396 | | - * End: |
1397 | | - */ |
1398 | | -?> |