├── reset.sh ├── bucky.db ├── bucky.gif ├── addon ├── bucky.png ├── manifest.json └── bucky.js ├── lib ├── .DS_Store └── requestcore │ ├── .DS_Store │ └── requestcore.class.php ├── scr ├── run_bucky.png ├── all_buckets.png ├── bucky_addon.png ├── manual_check.png ├── vulnerable_poc.png └── dashboard_loading.png ├── services └── .DS_Store ├── utilities ├── .DS_Store ├── response.class.php ├── manifest.class.php ├── info.class.php ├── request.class.php ├── stepconfig.class.php ├── json.class.php ├── batchrequest.class.php ├── policy.class.php ├── credentials.class.php ├── complextype.class.php ├── credential.class.php ├── mimetypes.class.php ├── simplexml.class.php ├── gzipdecode.class.php ├── array.class.php └── utilities.class.php ├── index.php ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── dbreset.php ├── run.sh ├── manual_check.php ├── all_buckets.php ├── process.php ├── README.md ├── config.inc.php └── sdk.class.php /reset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm bucky.db 3 | php dbreset.php -------------------------------------------------------------------------------- /bucky.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smaranchand/bucky/HEAD/bucky.db -------------------------------------------------------------------------------- /bucky.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smaranchand/bucky/HEAD/bucky.gif -------------------------------------------------------------------------------- /addon/bucky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smaranchand/bucky/HEAD/addon/bucky.png -------------------------------------------------------------------------------- /lib/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smaranchand/bucky/HEAD/lib/.DS_Store -------------------------------------------------------------------------------- /scr/run_bucky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smaranchand/bucky/HEAD/scr/run_bucky.png -------------------------------------------------------------------------------- /scr/all_buckets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smaranchand/bucky/HEAD/scr/all_buckets.png -------------------------------------------------------------------------------- /scr/bucky_addon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smaranchand/bucky/HEAD/scr/bucky_addon.png -------------------------------------------------------------------------------- /scr/manual_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smaranchand/bucky/HEAD/scr/manual_check.png -------------------------------------------------------------------------------- /services/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smaranchand/bucky/HEAD/services/.DS_Store -------------------------------------------------------------------------------- /utilities/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smaranchand/bucky/HEAD/utilities/.DS_Store -------------------------------------------------------------------------------- /scr/vulnerable_poc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smaranchand/bucky/HEAD/scr/vulnerable_poc.png -------------------------------------------------------------------------------- /lib/requestcore/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smaranchand/bucky/HEAD/lib/requestcore/.DS_Store -------------------------------------------------------------------------------- /scr/dashboard_loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smaranchand/bucky/HEAD/scr/dashboard_loading.png -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | Bucky 9 | 10 | 11 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /addon/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "Bucky", 4 | "version": "1.0", 5 | 6 | 7 | "description": "Bucky discovers AWS S3 buckets from the web pages and sends it to the backend engine to check for misconfiguration.", 8 | 9 | "icons": { 10 | "48": "bucky.png" 11 | }, 12 | 13 | "content_scripts": [ 14 | { 15 | "matches": ["*://*/*"], 16 | "js": ["bucky.js"] 17 | } 18 | ], 19 | 20 | "permissions": [ 21 | "http://127.0.0.1/*", 22 | "webRequest" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /dbreset.php: -------------------------------------------------------------------------------- 1 | open('bucky.db'); 6 | } 7 | } 8 | $db = new MyDB(); 9 | if(!$db) { 10 | echo $db->lastErrorMsg(); 11 | } else { 12 | $sql =<<exec($sql); 23 | if(!$ret){ 24 | echo $db->lastErrorMsg(); 25 | } else { 26 | echo "Database setup successful."; 27 | } 28 | $db->close(); 29 | } 30 | ?> 31 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #Bucky is AWS S3 bucket discovery tool developed by https://twitter.com/smaranchand 3 | #Bucky Backend Engine automatically takes input from Bucky addon and check for misconfiguration. 4 | #Download Bucky aaddon from https://addons.mozilla.org/en-US/firefox/addon/bucky/ 5 | #No changes done. 6 | echo " 7 | ____ _ __ ___ 8 | | _ \ | | /_ | / _ \ 9 | | |_) |_ _ ___| | ___ _ __ _| || | | | 10 | | _ <| | | |/ __| |/ / | | | \ \ / / || | | | 11 | | |_) | |_| | (__| <| |_| | \ V /| || |_| | 12 | |____/ \__,_|\___|_|\_\\__, | \_/ |_(_)___/ 13 | __/ | 14 | |___/ 15 | An automatic tool to find misconfigured AWS S3 buckets. 16 | Developed by : https://twitter.com/smaranchand 17 | "; 18 | php -S 127.0.0.1:13337 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /addon/bucky.js: -------------------------------------------------------------------------------- 1 | //If you think we can improve Bucky, then suggestions are welcomed. 2 | var sourcecode = document.documentElement.outerHTML; 3 | var pageurl= document.URL; 4 | var hostname= window.location.hostname; 5 | var s3bucketurl= sourcecode.match(/https:\/\/[a-z0-9-.]{3,63}\.s3\.([a-z0-9-]{5,19}\.|)amazonaws\.com/g); 6 | if (s3bucketurl==null) 7 | { 8 | var s3bucketname= sourcecode.match(/(?<=\/\/s3\.amazonaws.com\/)[a-z0-9-.]{3,63}(?=\/)/); 9 | if (s3bucketname==null) 10 | { 11 | } 12 | else 13 | sendBucket(); 14 | 15 | } 16 | else 17 | { 18 | var s3bucketname= String(s3bucketurl[0]).match(/(?<=\/\/).*(?=\.s3)/); 19 | sendBucket(); 20 | } 21 | 22 | function sendBucket() { 23 | 24 | var xhr = new XMLHttpRequest(); 25 | xhr.open("POST", "http://127.0.0.1:13337/process.php", true); 26 | xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5"); 27 | xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 28 | var body = ("bucketname="+s3bucketname+"&sourceurl="+pageurl+"&hostname="+hostname); 29 | xhr.send(body); 30 | 31 | } -------------------------------------------------------------------------------- /manual_check.php: -------------------------------------------------------------------------------- 1 | 2 | Manual Check 3 | 4 | 5 | 38 | 39 |
40 |

Check Manually | All Buckets

41 |
42 |
43 | 44 |
45 | 46 | 47 | 48 | 49 |
50 | 51 | -------------------------------------------------------------------------------- /utilities/response.class.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | All Buckets 4 | 50 | 51 |
52 | 53 |

All Buckets | Check Manually

54 |
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | open('bucky.db'); 68 | } 69 | } 70 | 71 | $db = new MyDB(); 72 | if(!$db) { 73 | echo $db->lastErrorMsg(); 74 | } else { 75 | 76 | } 77 | 78 | $sql =<<query($sql); 83 | while($row = $ret->fetchArray(SQLITE3_ASSOC) ) { 84 | echo ""; 85 | echo ""; 86 | echo ""; 87 | echo ""; 88 | echo ""; 89 | echo ""; 90 | echo ""; 91 | } 92 | $db->close(); 93 | ?> -------------------------------------------------------------------------------- /utilities/manifest.class.php: -------------------------------------------------------------------------------- 1 | function. 36 | * @return string A YAML manifest document. 37 | */ 38 | public static function json($json) 39 | { 40 | $map = json_decode($json, true); 41 | return sfYaml::dump($map); 42 | } 43 | 44 | /** 45 | * Takes an associative array to convert to a YAML manifest. 46 | * 47 | * @param array $map (Required) An associative array. 48 | * @return string A YAML manifest document. 49 | */ 50 | public static function map($map) 51 | { 52 | return sfYaml::dump($map); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /utilities/info.class.php: -------------------------------------------------------------------------------- 1 | api_version; 64 | unset($obj); 65 | } 66 | 67 | return $collect; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /process.php: -------------------------------------------------------------------------------- 1 | open('bucky.db'); 12 | } 13 | } 14 | 15 | $db = new MyDB(); 16 | if(!$db){ 17 | echo $db->lastErrorMsg(); 18 | } else { 19 | } 20 | 21 | $sql =<<YES' ); 24 | 25 | EOF; 26 | 27 | $ret = $db->exec($sql); 28 | if(!$ret) { 29 | echo $db->lastErrorMsg(); 30 | } else { 31 | 32 | header("refresh:3; url=all_buckets.php"); 33 | echo "S3 Bucket $newbucket seems vulnerable, Check dashboard for more information."; 34 | 35 | } 36 | $db->close(); 37 | } 38 | 39 | function bucketfailed(){ 40 | $newbucket=$_POST['bucketname']; 41 | $sourceurl=$_POST['sourceurl']; 42 | $hostname=$_POST['hostname']; 43 | $serverip= gethostbyname("$hostname"); 44 | class MyDB extends SQLite3 { 45 | function __construct() { 46 | $this->open('bucky.db'); 47 | } 48 | } 49 | 50 | $db = new MyDB(); 51 | if(!$db){ 52 | echo $db->lastErrorMsg(); 53 | } else { 54 | } 55 | 56 | $sql =<<exec($sql); 63 | if(!$ret) { 64 | echo $db->lastErrorMsg(); 65 | } else { 66 | header("refresh:3; url=manual_check.php"); 67 | echo "S3 Bucket $newbucket doesnot seems vulnerable, Check dashboard for more information."; 68 | } 69 | $db->close(); 70 | } 71 | 72 | $newbucket=$_POST['bucketname']; 73 | error_reporting(0); 74 | require_once 'sdk.class.php'; 75 | $s3 = new AmazonS3(); 76 | $response = $s3->create_object($newbucket, 'bucky.txt', array( 77 | 'contentType' => 'text/plain', 78 | 'body' => 'S3 bucket misconfiguration is discovered. 79 | Discovered by Bucky. 80 | Developed by: https://twitter.com/smaranchand', 81 | 'acl'=>AmazonS3::ACL_PUBLIC, 82 | )); 83 | if ((int) $response->isOK()) 84 | bucketsuccess(); 85 | else 86 | bucketfailed(); 87 | ?> 88 | -------------------------------------------------------------------------------- /utilities/request.class.php: -------------------------------------------------------------------------------- 1 | ). 33 | */ 34 | public $request_class = 'CFRequest'; 35 | 36 | /** 37 | * The default class to use for HTTP Responses (defaults to ). 38 | */ 39 | public $response_class = 'CFResponse'; 40 | 41 | /** 42 | * The active credential set. 43 | */ 44 | public $credentials; 45 | 46 | 47 | /*%******************************************************************************************%*/ 48 | // CONSTRUCTOR 49 | 50 | /** 51 | * Constructs a new instance of this class. 52 | * 53 | * @param string $url (Optional) The URL to request or service endpoint to query. 54 | * @param string $proxy (Optional) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` 55 | * @param array $helpers (Optional) An associative array of classnames to use for request, and response functionality. Gets passed in automatically by the calling class. 56 | * @param CFCredential $credentials (Required) The credentials to use for signing and making requests. 57 | * @return $this A reference to the current instance. 58 | */ 59 | public function __construct($url = null, $proxy = null, $helpers = null, CFCredential $credentials = null) 60 | { 61 | parent::__construct($url, $proxy, $helpers); 62 | 63 | // Standard settings for all requests 64 | $this->set_useragent(CFRUNTIME_USERAGENT); 65 | $this->credentials = $credentials; 66 | $this->cacert_location = ($this->credentials['certificate_authority'] ? $this->credentials['certificate_authority'] : false); 67 | 68 | if (strpos(parse_url($url, PHP_URL_HOST), 'dynamodb') === 0) 69 | { 70 | $this->use_gzip_enconding = false; 71 | } 72 | 73 | return $this; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /utilities/stepconfig.class.php: -------------------------------------------------------------------------------- 1 | config = $config; 52 | } 53 | 54 | /** 55 | * Constructs a new instance of this class, and allows chaining. 56 | * 57 | * @param array $config (Required) An associative array representing the Hadoop step configuration. 58 | * @return $this A reference to the current instance. 59 | */ 60 | public static function init($config) 61 | { 62 | if (version_compare(PHP_VERSION, '5.3.0', '<')) 63 | { 64 | throw new Exception('PHP 5.3 or newer is required to instantiate a new class with CLASS::init().'); 65 | } 66 | 67 | $self = get_called_class(); 68 | return new $self($config); 69 | } 70 | 71 | /** 72 | * Returns a JSON representation of the object when typecast as a string. 73 | * 74 | * @return string A JSON representation of the object. 75 | * @link http://www.php.net/manual/en/language.oop5.magic.php#language.oop5.magic.tostring PHP Magic Methods 76 | */ 77 | public function __toString() 78 | { 79 | return json_encode($this->config); 80 | } 81 | 82 | /** 83 | * Returns the configuration data. 84 | * 85 | * @return array The configuration data. 86 | */ 87 | public function get_config() 88 | { 89 | return $this->config; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /utilities/json.class.php: -------------------------------------------------------------------------------- 1 | SimpleXMLElement. Has a default value of CFSimpleXML. 36 | * @return CFSimpleXML An XML representation of the data. 37 | */ 38 | public static function to_xml($json, $parser = 'CFSimpleXML') 39 | { 40 | // If we haven't parsed the JSON, do it 41 | if (!is_array($json)) 42 | { 43 | // Handle the case of JSON-encoded NULL value 44 | if ($json === 'null') 45 | { 46 | $json = null; 47 | } 48 | else 49 | { 50 | $json = json_decode($json, true); 51 | 52 | if (function_exists('json_last_error')) 53 | { 54 | // Did we encounter an error? 55 | switch (json_last_error()) 56 | { 57 | case JSON_ERROR_DEPTH: 58 | throw new JSON_Exception('Maximum stack depth exceeded.'); 59 | 60 | case JSON_ERROR_CTRL_CHAR: 61 | throw new JSON_Exception('Unexpected control character found.'); 62 | 63 | case JSON_ERROR_SYNTAX: 64 | throw new JSON_Exception('Syntax error; Malformed JSON.'); 65 | 66 | case JSON_ERROR_STATE_MISMATCH: 67 | throw new JSON_Exception('Invalid or malformed JSON.'); 68 | } 69 | } 70 | // json_last_error() not available? 71 | elseif ($json === null) 72 | { 73 | throw new JSON_Exception('Unknown JSON error. Be sure to validate your JSON and read the notes on http://php.net/json_decode.'); 74 | } 75 | } 76 | } 77 | 78 | // Hand off for the recursive work 79 | $string = Transmogrifier::to_xml($json, 'rootElement'); 80 | 81 | return simplexml_load_string($string, $parser, LIBXML_NOCDATA); 82 | } 83 | } 84 | 85 | 86 | /** 87 | * Default JSON Exception. 88 | */ 89 | class JSON_Exception extends Exception {} 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![Bucky](https://github.com/smaranchand/bucky/blob/master/bucky.gif?raw=true) 3 | 4 | # Project is on temporary hold. 5 | 6 | # Bucky 7 | Bucky is an automatic tool designed to discover S3 bucket misconfiguration, Bucky consists up of two modules Bucky firefox addon and Bucky backend engine. Bucky addon reads the source code of the webpages and uses Regular Expression(Regex) to match the S3 bucket used as Content Delivery Network(CDN) and sends it to the Bucky Backend engine. The backend engine receives the data from addon and checks if the S3 bucket is publicly writeable or not. Bucky automatically uploads a text file as Proof Of Concept(PoC) if the bucket is vulnerable. 8 | 9 | 10 | # Working 11 | Bucky addon sends the details of s3 bucket name discovered from a user visited web pages to backend engine. 12 | It uses [AWS PHP SDK](https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/getting-started_installation.html) to discover misconfiguration. 13 | Users can also check for S3 bucket misconfiguration manually. All the results from automatic and manuall check are populated to dashboard. 14 | 15 | Checkout video https://vimeo.com/444442588 16 | 17 | # Installation 18 | 19 | ``` 20 | git clone https://github.com/smaranchand/bucky.git 21 | cd bucky 22 | 23 | ``` 24 | 25 | Requirements: AWS Access Keys and PHP installation 26 | 27 | Get AWS Access Keys: https://console.aws.amazon.com/iam/home?#/security_credentials 28 | 29 | PHP installation: Install according to your OS, apt install php7.3 / brew install php7.3 30 | 31 | 32 | Currently, Bucky addon is not published in the Firefox addon store; as soon as the addon will be published, the addon link will be provided. 33 | 34 | For now, users can manually load the addon into the browser to do so 35 | 36 | 1. Open Firefox browser and visit about:debugging 37 | 2. Click on "This Firefox" > Load Temporary Add-on 38 | 3. Select the addon located at bucky/addon/bucky.js 39 | 40 | Add AWS Access keys: 41 | ``` 42 | cd bucky/ 43 | nano config.inc.php 44 | Add your AWS Access Key ID and Secret Access Key. (On-Line 57 and 61) 45 | ``` 46 | 47 | 48 | # Usage 49 | 50 | To use Bucky, load the Bucky addon to the browser and start backend engine. 51 | ``` 52 | cd bucky/ 53 | chmod +x run.sh 54 | ./run.sh 55 | 56 | The backend engine runs on http://127.0.0.1:13337 57 | Browse websites, Bucky will discover S3 buckets automatically and will be reflected in the dashboard. 58 | Visit the above address to access Bucky dashboard. 59 | ``` 60 | 61 | # Screenshots 62 | Running Bucky 63 | 64 | ![run_bucky](https://github.com/smaranchand/bucky/blob/master/scr/run_bucky.png?raw=true) 65 | 66 | Loading Addon 67 | 68 | ![load_addon](https://github.com/smaranchand/bucky/blob/master/scr/bucky_addon.png?raw=true) 69 | User Interface 70 | 71 | ![dashboard](https://github.com/smaranchand/bucky/blob/master/scr/dashboard_loading.png?raw=true) 72 | 73 | All Buckets 74 | 75 | ![all_buckets](https://github.com/smaranchand/bucky/blob/master/scr/all_buckets.png?raw=true) 76 | Manual Check 77 | 78 | ![manual_check](https://github.com/smaranchand/bucky/blob/master/scr/manual_check.png?raw=true) 79 | 80 | POC By Bucky 81 | 82 | ![Bucky_POC](https://github.com/smaranchand/bucky/blob/master/scr/vulnerable_poc.png?raw=true) 83 | 84 | 85 | 86 | # Note 87 | Bucky is not a perfect tool to discover S3 buckets, it is well known that Bucky lacks many feautres and it may fail to detect the misconfiguration sometimes. Certain changes and development are in pipeline. I really appreciate the feedbacks and contribution. 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /config.inc.php: -------------------------------------------------------------------------------- 1 | array( 54 | 55 | // Amazon Web Services Key. Found in the AWS Security Credentials. You can also pass 56 | // this value as the first parameter to a service constructor. 57 | 'key' => 'YOUR_AWS_KEY', 58 | 59 | // Amazon Web Services Secret Key. Found in the AWS Security Credentials. You can also 60 | // pass this value as the second parameter to a service constructor. 61 | 'secret' => 'YOUR_SECRET', 62 | 63 | // This option allows you to configure a preferred storage type to use for caching by 64 | // default. This can be changed later using the set_cache_config() method. 65 | // 66 | // Valid values are: `apc`, `xcache`, or a file system path such as `./cache` or 67 | // `/tmp/cache/`. 68 | 'default_cache_config' => '', 69 | 70 | // Determines which Cerificate Authority file to use. 71 | // 72 | // A value of boolean `false` will use the Certificate Authority file available on the 73 | // system. A value of boolean `true` will use the Certificate Authority provided by the 74 | // SDK. Passing a file system path to a Certificate Authority file (chmodded to `0755`) 75 | // will use that. 76 | // 77 | // Leave this set to `false` if you're not sure. 78 | 'certificate_authority' => false 79 | ), 80 | 81 | // Specify a default credential set to use if there are more than one. 82 | '@default' => 'development' 83 | )); 84 | -------------------------------------------------------------------------------- /utilities/batchrequest.class.php: -------------------------------------------------------------------------------- 1 | queue = array(); 80 | $this->limit = $limit ? $limit : -1; 81 | $this->credentials = new CFCredential(array()); 82 | return $this; 83 | } 84 | 85 | /** 86 | * Sets the AWS credentials to use for the batch request. 87 | * 88 | * @param CFCredential $credentials (Required) The credentials to use for signing and making requests. 89 | * @return $this A reference to the current instance. 90 | */ 91 | public function use_credentials(CFCredential $credentials) 92 | { 93 | $this->credentials = $credentials; 94 | return $this; 95 | } 96 | 97 | /** 98 | * Adds a new cURL handle to the request queue. 99 | * 100 | * @param resource $handle (Required) A cURL resource to add to the queue. 101 | * @return $this A reference to the current instance. 102 | */ 103 | public function add($handle) 104 | { 105 | $this->queue[] = $handle; 106 | return $this; 107 | } 108 | 109 | /** 110 | * Executes the batch request queue. 111 | * 112 | * @param array $opt (DO NOT USE) Enabled for compatibility with the method this overrides, although any values passed will be ignored. 113 | * @return array An indexed array of objects. 114 | */ 115 | public function send($opt = null) 116 | { 117 | $http = new $this->request_class(null, $this->proxy, null, $this->credentials); 118 | 119 | // Make the request 120 | $response = $http->send_multi_request($this->queue, array( 121 | 'limit' => $this->limit 122 | )); 123 | 124 | return $response; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /utilities/policy.class.php: -------------------------------------------------------------------------------- 1 | (e.g. , ). 45 | * @param string|array $policy (Required) The associative array representing the S3 policy to use, or a string of JSON content. 46 | * @return $this A reference to the current instance. 47 | * @link http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/index.html?HTTPPOSTForms.html S3 Policies 48 | * @link http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?AccessPolicyLanguage.html Access Policy Language 49 | */ 50 | public function __construct($auth, $policy) 51 | { 52 | $this->auth = $auth; 53 | 54 | if (is_array($policy)) // We received an associative array... 55 | { 56 | $this->json_policy = json_encode($policy); 57 | } 58 | else // We received a valid, parseable JSON string... 59 | { 60 | $this->json_policy = json_encode(json_decode($policy, true)); 61 | } 62 | 63 | return $this; 64 | } 65 | 66 | /** 67 | * Alternate approach to constructing a new instance. Supports chaining. 68 | * 69 | * @param CFRuntime $auth (Required) An instance of any authenticated AWS object that is an instance of (e.g. , ). 70 | * @param string|array $policy (Required) The associative array representing the S3 policy to use, or a string of JSON content. 71 | * @return $this A reference to the current instance. 72 | */ 73 | public static function init($auth, $policy) 74 | { 75 | if (version_compare(PHP_VERSION, '5.3.0', '<')) 76 | { 77 | throw new Exception('PHP 5.3 or newer is required to instantiate a new class with CLASS::init().'); 78 | } 79 | 80 | $self = get_called_class(); 81 | return new $self($auth, $policy); 82 | } 83 | 84 | /** 85 | * Get the key from the authenticated instance. 86 | * 87 | * @return string The key from the authenticated instance. 88 | */ 89 | public function get_key() 90 | { 91 | return $this->auth->key; 92 | } 93 | 94 | /** 95 | * Base64-encodes the JSON string. 96 | * 97 | * @return string The Base64-encoded version of the JSON string. 98 | */ 99 | public function get_policy() 100 | { 101 | return base64_encode($this->json_policy); 102 | } 103 | 104 | /** 105 | * Gets the JSON string with the whitespace removed. 106 | * 107 | * @return string The JSON string without extraneous whitespace. 108 | */ 109 | public function get_json() 110 | { 111 | return $this->json_policy; 112 | } 113 | 114 | /** 115 | * Gets the JSON string with the whitespace removed. 116 | * 117 | * @return string The Base64-encoded, signed JSON string. 118 | */ 119 | public function get_policy_signature() 120 | { 121 | return base64_encode(hash_hmac('sha1', $this->get_policy(), $this->auth->secret_key)); 122 | } 123 | 124 | /** 125 | * Decode a policy that was returned from the service. 126 | * 127 | * @param string $response (Required) The policy returned by AWS that you want to decode into an object. 128 | * @return string The Base64-encoded, signed JSON string. 129 | */ 130 | public static function decode_policy($response) 131 | { 132 | return json_decode(urldecode($response), true); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /utilities/credentials.class.php: -------------------------------------------------------------------------------- 1 | class enables developers to easily switch between multiple sets of credentials. 23 | * 24 | * @version 2012.07.13 25 | * @license See the included NOTICE.md file for more information. 26 | * @copyright See the included NOTICE.md file for more information. 27 | * @link http://aws.amazon.com/php/ PHP Developer Center 28 | */ 29 | class CFCredentials 30 | { 31 | /** 32 | * The key used to specify the default credential set 33 | */ 34 | const DEFAULT_KEY = '@default'; 35 | 36 | /** 37 | * The key used to identify inherited credentials 38 | */ 39 | const INHERIT_KEY = '@inherit'; 40 | 41 | /** 42 | * Stores the credentials 43 | */ 44 | protected static $credentials = array(); 45 | 46 | /** 47 | * Prevents this class from being constructed 48 | */ 49 | final private function __construct() {} 50 | 51 | /** 52 | * Stores the credentials for re-use. 53 | * 54 | * @param array $credential_sets (Required) The named credential sets that should be made available to the application. 55 | * @return void 56 | */ 57 | public static function set(array $credential_sets) 58 | { 59 | // Make sure a default credential set is specified or can be inferred 60 | if (count($credential_sets) === 1) 61 | { 62 | $credential_sets[self::DEFAULT_KEY] = reset($credential_sets); 63 | } 64 | 65 | // Resolve any @inherit tags 66 | foreach ($credential_sets as $credential_name => &$credential_set) 67 | { 68 | if (is_array($credential_set)) 69 | { 70 | foreach ($credential_set as $credential_key => &$credential_value) 71 | { 72 | if ($credential_key === self::INHERIT_KEY) 73 | { 74 | if (!isset($credential_sets[$credential_value])) 75 | { 76 | throw new CFCredentials_Exception('The credential set, "' . $credential_value . '", does not exist and cannot be inherited.'); 77 | } 78 | 79 | $credential_set = array_merge($credential_sets[$credential_value], $credential_set); 80 | unset($credential_set[self::INHERIT_KEY]); 81 | } 82 | } 83 | } 84 | } 85 | 86 | // Normalize the value of the @default credential set 87 | if (isset($credential_sets[self::DEFAULT_KEY])) 88 | { 89 | $default = $credential_sets[self::DEFAULT_KEY]; 90 | if (is_string($default)) 91 | { 92 | if (!isset($credential_sets[$default])) 93 | { 94 | throw new CFCredentials_Exception('The credential set, "' . $default . '", does not exist and cannot be used as the default credential set.'); 95 | } 96 | 97 | $credential_sets[self::DEFAULT_KEY] = $credential_sets[$default]; 98 | } 99 | } 100 | 101 | // Store the credentials 102 | self::$credentials = $credential_sets; 103 | } 104 | 105 | /** 106 | * Retrieves the requested credentials from the internal credential store. 107 | * 108 | * @param string $credential_set (Optional) The name of the credential set to retrieve. The default value is set in DEFAULT_KEY. 109 | * @return stdClass A stdClass object where the properties represent the keys that were provided. 110 | */ 111 | public static function get($credential_name = self::DEFAULT_KEY) 112 | { 113 | // Make sure the credential set exists 114 | if (!isset(self::$credentials[$credential_name])) 115 | { 116 | throw new CFCredentials_Exception('The credential set, "' . $credential_name . '", does not exist and cannot be retrieved.'); 117 | } 118 | 119 | // Return the credential set as an object 120 | return new CFCredential(self::$credentials[$credential_name]); 121 | } 122 | 123 | /** 124 | * Retrieves a list of all available credential set names. 125 | * 126 | * @return CFArray A list of all available credential set names. 127 | */ 128 | public static function list_sets() 129 | { 130 | return new CFArray(array_keys(self::$credentials)); 131 | } 132 | } 133 | 134 | class CFCredentials_Exception extends Exception {} 135 | -------------------------------------------------------------------------------- /utilities/complextype.class.php: -------------------------------------------------------------------------------- 1 | function. 35 | * @param string $member (Optional) The name of the "member" property that AWS uses for lists in certain services. Defaults to an empty string. 36 | * @param string $default_key (Optional) The default key to use when the value for `$data` is a string. Defaults to an empty string. 37 | * @return array The option group parameters to merge into another method's `$opt` parameter. 38 | */ 39 | public static function json($json, $member = '', $default_key = '') 40 | { 41 | return self::option_group(json_decode($json, true), $member, $default_key); 42 | } 43 | 44 | /** 45 | * Takes a YAML object, as a string, to convert to query string keys. 46 | * 47 | * @param string $yaml (Required) A YAML object. 48 | * @param string $member (Optional) The name of the "member" property that AWS uses for lists in certain services. Defaults to an empty string. 49 | * @param string $default_key (Optional) The default key to use when the value for `$data` is a string. Defaults to an empty string. 50 | * @return array The option group parameters to merge into another method's `$opt` parameter. 51 | */ 52 | public static function yaml($yaml, $member = '', $default_key = '') 53 | { 54 | return self::option_group(sfYaml::load($yaml), $member, $default_key); 55 | } 56 | 57 | /** 58 | * Takes an associative array to convert to query string keys. 59 | * 60 | * @param array $map (Required) An associative array. 61 | * @param string $member (Optional) The name of the "member" property that AWS uses for lists in certain services. Defaults to an empty string. 62 | * @param string $default_key (Optional) The default key to use when the value for `$data` is a string. Defaults to an empty string. 63 | * @return array The option group parameters to merge into another method's `$opt` parameter. 64 | */ 65 | public static function map($map, $member = '', $default_key = '') 66 | { 67 | return self::option_group($map, $member, $default_key); 68 | } 69 | 70 | /** 71 | * A protected method that is used by , and . 72 | * 73 | * @param string|array $data (Required) The data to iterate over. 74 | * @param string $member (Optional) The name of the "member" property that AWS uses for lists in certain services. Defaults to an empty string. 75 | * @param string $key (Optional) The default key to use when the value for `$data` is a string. Defaults to an empty string. 76 | * @param array $out (Optional) INTERNAL ONLY. The array that contains the calculated values up to this point. 77 | * @return array The option group parameters to merge into another method's `$opt` parameter. 78 | */ 79 | public static function option_group($data, $member = '', $key = '', &$out = array()) 80 | { 81 | $reset = $key; 82 | 83 | if (is_array($data)) 84 | { 85 | foreach ($data as $k => $v) 86 | { 87 | // Avoid 0-based indexes. 88 | if (is_int($k)) 89 | { 90 | $k = $k + 1; 91 | 92 | if ($member !== '') 93 | { 94 | $key .= '.' . $member; 95 | } 96 | } 97 | 98 | $key .= ($key === '' ? $k : '.' . $k); 99 | 100 | if (is_array($v)) 101 | { 102 | self::option_group($v, $member, $key, $out); 103 | } 104 | elseif ($v instanceof CFStepConfig) 105 | { 106 | self::option_group($v->get_config(), $member, $key, $out); 107 | } 108 | else 109 | { 110 | $out[$key] = $v; 111 | } 112 | 113 | $key = $reset; 114 | } 115 | } 116 | else 117 | { 118 | $out[$key] = $data; 119 | } 120 | 121 | return $out; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /utilities/credential.class.php: -------------------------------------------------------------------------------- 1 | class represents an individual credential set. 23 | * 24 | * @version 2011.11.15 25 | * @license See the included NOTICE.md file for more information. 26 | * @copyright See the included NOTICE.md file for more information. 27 | * @link http://aws.amazon.com/php/ PHP Developer Center 28 | */ 29 | class CFCredential implements ArrayAccess 30 | { 31 | /** 32 | * Stores the internal representation of the collection. 33 | */ 34 | private $collection; 35 | 36 | /** 37 | * Default getter. Enables syntax such as $object->method->chained_method();. Also supports 38 | * $object->key. Matching methods are prioritized over matching keys. 39 | * 40 | * @param string $name (Required) The name of the method to execute or key to retrieve. 41 | * @return mixed The results of calling the function $name(), or the value of the key $object[$name]. 42 | */ 43 | public function __get($name) 44 | { 45 | return $this[$name]; 46 | } 47 | 48 | /** 49 | * Default setter. 50 | * 51 | * @param string $name (Required) The name of the method to execute. 52 | * @param string $value (Required) The value to pass to the method. 53 | * @return mixed The results of calling the function, $name. 54 | */ 55 | public function __set($name, $value) 56 | { 57 | $this[$name] = $value; 58 | return $this; 59 | } 60 | 61 | /** 62 | * Create a clone of the object. 63 | * 64 | * @return CFCredential A clone of the current instance. 65 | */ 66 | public function __clone() 67 | { 68 | $this->collection = clone $this->collection; 69 | } 70 | 71 | 72 | /*%******************************************************************************************%*/ 73 | // CONSTRUCTOR 74 | 75 | /** 76 | * Constructs a new instance of the class. 77 | */ 78 | public function __construct($value = array()) 79 | { 80 | $this->collection = new ArrayObject($value, ArrayObject::ARRAY_AS_PROPS); 81 | } 82 | 83 | /** 84 | * Check whether or not a specific offset exists. 85 | * 86 | * @param integer $offset (Required) The location in the collection to verify the existence of. 87 | * @return boolean A value of true indicates that the collection offset exists. A value of false indicates that it does not. 88 | */ 89 | public function offsetExists($offset) 90 | { 91 | return $this->collection->offsetExists($offset); 92 | } 93 | 94 | /** 95 | * Get the value for a specific offset. 96 | * 97 | * @param integer $offset (Required) The location in the collection to retrieve the value for. 98 | * @return mixed The value of the collection offset. NULL is returned if the offset does not exist. 99 | */ 100 | public function offsetGet($offset) 101 | { 102 | if ($this->collection->offsetExists($offset)) 103 | { 104 | return $this->collection->offsetGet($offset); 105 | } 106 | 107 | return null; 108 | } 109 | 110 | /** 111 | * Set the value for a specific offset. 112 | * 113 | * @param integer $offset (Required) The location in the collection to set a new value for. 114 | * @param mixed $value (Required) The new value for the collection location. 115 | * @return CFCredential A reference to the current collection. 116 | */ 117 | public function offsetSet($offset, $value) 118 | { 119 | $this->collection->offsetSet($offset, $value); 120 | return $this; 121 | } 122 | 123 | /** 124 | * Unset the value for a specific offset. 125 | * 126 | * @param integer $offset (Required) The location in the collection to unset. 127 | * @return CFCredential A reference to the current collection. 128 | */ 129 | public function offsetUnset($offset) 130 | { 131 | $this->collection->offsetUnset($offset); 132 | return $this; 133 | } 134 | 135 | /** 136 | * Merge another instance of onto this one. 137 | * 138 | * @param CFCredential $credential (Required) Another instance of . 139 | * @return CFCredential A reference to the current collection. 140 | */ 141 | public function merge(CFCredential $credential) 142 | { 143 | $merged = array_merge($this->to_array(), $credential->to_array()); 144 | $this->collection->exchangeArray($merged); 145 | return $this; 146 | } 147 | 148 | /** 149 | * Retrieves the data as a standard array. 150 | * 151 | * @return array The data as an array. 152 | */ 153 | public function to_array() 154 | { 155 | return $this->collection->getArrayCopy(); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /utilities/mimetypes.class.php: -------------------------------------------------------------------------------- 1 | 'video/3gpp', 36 | 'ai' => 'application/postscript', 37 | 'aif' => 'audio/x-aiff', 38 | 'aifc' => 'audio/x-aiff', 39 | 'aiff' => 'audio/x-aiff', 40 | 'asc' => 'text/plain', 41 | 'atom' => 'application/atom+xml', 42 | 'au' => 'audio/basic', 43 | 'avi' => 'video/x-msvideo', 44 | 'bcpio' => 'application/x-bcpio', 45 | 'bin' => 'application/octet-stream', 46 | 'bmp' => 'image/bmp', 47 | 'cdf' => 'application/x-netcdf', 48 | 'cgm' => 'image/cgm', 49 | 'class' => 'application/octet-stream', 50 | 'cpio' => 'application/x-cpio', 51 | 'cpt' => 'application/mac-compactpro', 52 | 'csh' => 'application/x-csh', 53 | 'css' => 'text/css', 54 | 'dcr' => 'application/x-director', 55 | 'dif' => 'video/x-dv', 56 | 'dir' => 'application/x-director', 57 | 'djv' => 'image/vnd.djvu', 58 | 'djvu' => 'image/vnd.djvu', 59 | 'dll' => 'application/octet-stream', 60 | 'dmg' => 'application/octet-stream', 61 | 'dms' => 'application/octet-stream', 62 | 'doc' => 'application/msword', 63 | 'dtd' => 'application/xml-dtd', 64 | 'dv' => 'video/x-dv', 65 | 'dvi' => 'application/x-dvi', 66 | 'dxr' => 'application/x-director', 67 | 'eps' => 'application/postscript', 68 | 'etx' => 'text/x-setext', 69 | 'exe' => 'application/octet-stream', 70 | 'ez' => 'application/andrew-inset', 71 | 'flv' => 'video/x-flv', 72 | 'gif' => 'image/gif', 73 | 'gram' => 'application/srgs', 74 | 'grxml' => 'application/srgs+xml', 75 | 'gtar' => 'application/x-gtar', 76 | 'gz' => 'application/x-gzip', 77 | 'hdf' => 'application/x-hdf', 78 | 'hqx' => 'application/mac-binhex40', 79 | 'htm' => 'text/html', 80 | 'html' => 'text/html', 81 | 'ice' => 'x-conference/x-cooltalk', 82 | 'ico' => 'image/x-icon', 83 | 'ics' => 'text/calendar', 84 | 'ief' => 'image/ief', 85 | 'ifb' => 'text/calendar', 86 | 'iges' => 'model/iges', 87 | 'igs' => 'model/iges', 88 | 'jnlp' => 'application/x-java-jnlp-file', 89 | 'jp2' => 'image/jp2', 90 | 'jpe' => 'image/jpeg', 91 | 'jpeg' => 'image/jpeg', 92 | 'jpg' => 'image/jpeg', 93 | 'js' => 'application/x-javascript', 94 | 'kar' => 'audio/midi', 95 | 'latex' => 'application/x-latex', 96 | 'lha' => 'application/octet-stream', 97 | 'lzh' => 'application/octet-stream', 98 | 'm3u' => 'audio/x-mpegurl', 99 | 'm4a' => 'audio/mp4a-latm', 100 | 'm4p' => 'audio/mp4a-latm', 101 | 'm4u' => 'video/vnd.mpegurl', 102 | 'm4v' => 'video/x-m4v', 103 | 'mac' => 'image/x-macpaint', 104 | 'man' => 'application/x-troff-man', 105 | 'mathml' => 'application/mathml+xml', 106 | 'me' => 'application/x-troff-me', 107 | 'mesh' => 'model/mesh', 108 | 'mid' => 'audio/midi', 109 | 'midi' => 'audio/midi', 110 | 'mif' => 'application/vnd.mif', 111 | 'mov' => 'video/quicktime', 112 | 'movie' => 'video/x-sgi-movie', 113 | 'mp2' => 'audio/mpeg', 114 | 'mp3' => 'audio/mpeg', 115 | 'mp4' => 'video/mp4', 116 | 'mpe' => 'video/mpeg', 117 | 'mpeg' => 'video/mpeg', 118 | 'mpg' => 'video/mpeg', 119 | 'mpga' => 'audio/mpeg', 120 | 'ms' => 'application/x-troff-ms', 121 | 'msh' => 'model/mesh', 122 | 'mxu' => 'video/vnd.mpegurl', 123 | 'nc' => 'application/x-netcdf', 124 | 'oda' => 'application/oda', 125 | 'ogg' => 'application/ogg', 126 | 'ogv' => 'video/ogv', 127 | 'pbm' => 'image/x-portable-bitmap', 128 | 'pct' => 'image/pict', 129 | 'pdb' => 'chemical/x-pdb', 130 | 'pdf' => 'application/pdf', 131 | 'pgm' => 'image/x-portable-graymap', 132 | 'pgn' => 'application/x-chess-pgn', 133 | 'pic' => 'image/pict', 134 | 'pict' => 'image/pict', 135 | 'png' => 'image/png', 136 | 'pnm' => 'image/x-portable-anymap', 137 | 'pnt' => 'image/x-macpaint', 138 | 'pntg' => 'image/x-macpaint', 139 | 'ppm' => 'image/x-portable-pixmap', 140 | 'ppt' => 'application/vnd.ms-powerpoint', 141 | 'ps' => 'application/postscript', 142 | 'qt' => 'video/quicktime', 143 | 'qti' => 'image/x-quicktime', 144 | 'qtif' => 'image/x-quicktime', 145 | 'ra' => 'audio/x-pn-realaudio', 146 | 'ram' => 'audio/x-pn-realaudio', 147 | 'ras' => 'image/x-cmu-raster', 148 | 'rdf' => 'application/rdf+xml', 149 | 'rgb' => 'image/x-rgb', 150 | 'rm' => 'application/vnd.rn-realmedia', 151 | 'roff' => 'application/x-troff', 152 | 'rtf' => 'text/rtf', 153 | 'rtx' => 'text/richtext', 154 | 'sgm' => 'text/sgml', 155 | 'sgml' => 'text/sgml', 156 | 'sh' => 'application/x-sh', 157 | 'shar' => 'application/x-shar', 158 | 'silo' => 'model/mesh', 159 | 'sit' => 'application/x-stuffit', 160 | 'skd' => 'application/x-koan', 161 | 'skm' => 'application/x-koan', 162 | 'skp' => 'application/x-koan', 163 | 'skt' => 'application/x-koan', 164 | 'smi' => 'application/smil', 165 | 'smil' => 'application/smil', 166 | 'snd' => 'audio/basic', 167 | 'so' => 'application/octet-stream', 168 | 'spl' => 'application/x-futuresplash', 169 | 'src' => 'application/x-wais-source', 170 | 'sv4cpio' => 'application/x-sv4cpio', 171 | 'sv4crc' => 'application/x-sv4crc', 172 | 'svg' => 'image/svg+xml', 173 | 'swf' => 'application/x-shockwave-flash', 174 | 't' => 'application/x-troff', 175 | 'tar' => 'application/x-tar', 176 | 'tcl' => 'application/x-tcl', 177 | 'tex' => 'application/x-tex', 178 | 'texi' => 'application/x-texinfo', 179 | 'texinfo' => 'application/x-texinfo', 180 | 'tif' => 'image/tiff', 181 | 'tiff' => 'image/tiff', 182 | 'tr' => 'application/x-troff', 183 | 'tsv' => 'text/tab-separated-values', 184 | 'txt' => 'text/plain', 185 | 'ustar' => 'application/x-ustar', 186 | 'vcd' => 'application/x-cdlink', 187 | 'vrml' => 'model/vrml', 188 | 'vxml' => 'application/voicexml+xml', 189 | 'wav' => 'audio/x-wav', 190 | 'wbmp' => 'image/vnd.wap.wbmp', 191 | 'wbxml' => 'application/vnd.wap.wbxml', 192 | 'webm' => 'video/webm', 193 | 'wml' => 'text/vnd.wap.wml', 194 | 'wmlc' => 'application/vnd.wap.wmlc', 195 | 'wmls' => 'text/vnd.wap.wmlscript', 196 | 'wmlsc' => 'application/vnd.wap.wmlscriptc', 197 | 'wmv' => 'video/x-ms-wmv', 198 | 'wrl' => 'model/vrml', 199 | 'xbm' => 'image/x-xbitmap', 200 | 'xht' => 'application/xhtml+xml', 201 | 'xhtml' => 'application/xhtml+xml', 202 | 'xls' => 'application/vnd.ms-excel', 203 | 'xml' => 'application/xml', 204 | 'xpm' => 'image/x-xpixmap', 205 | 'xsl' => 'application/xml', 206 | 'xslt' => 'application/xslt+xml', 207 | 'xul' => 'application/vnd.mozilla.xul+xml', 208 | 'xwd' => 'image/x-xwindowdump', 209 | 'xyz' => 'chemical/x-xyz', 210 | 'zip' => 'application/zip', 211 | ); 212 | 213 | /** 214 | * Attempt to match the file extension to a known mime-type. 215 | * 216 | * @param string $ext (Required) The file extension to attempt to map. 217 | * @return string The mime-type to use for the file extension. 218 | */ 219 | public static function get_mimetype($ext) 220 | { 221 | $ext = strtolower($ext); // Make sure the passed in extension is lowercase 222 | return isset(self::$mime_types[$ext]) ? self::$mime_types[$ext] : 'application/octet-stream'; 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /utilities/simplexml.class.php: -------------------------------------------------------------------------------- 1 | element. 56 | */ 57 | public function __call($name, $arguments) 58 | { 59 | // Remap $this 60 | $self = $this; 61 | 62 | // Re-base the XML 63 | $self = new CFSimpleXML($self->asXML()); 64 | 65 | // Determine XPath query 66 | $self->xpath_expression = 'descendant-or-self::' . $name; 67 | 68 | // Get the results and augment with CFArray 69 | $results = $self->xpath($self->xpath_expression); 70 | if (!count($results)) return false; 71 | $results = new CFArray($results); 72 | 73 | // If an integer was passed, return only that result 74 | if (isset($arguments[0]) && is_int($arguments[0])) 75 | { 76 | if (isset($results[$arguments[0]])) 77 | { 78 | return $results[$arguments[0]]; 79 | } 80 | 81 | return false; 82 | } 83 | 84 | return $results; 85 | } 86 | 87 | /** 88 | * Gets the current XML node as a true string. 89 | * 90 | * @return string The current XML node as a true string. 91 | */ 92 | public function __toString() 93 | { 94 | return $this->to_string(); 95 | } 96 | 97 | /** 98 | * Alternate approach to constructing a new instance. Supports chaining. 99 | * 100 | * @param string $data (Required) A well-formed XML string or the path or URL to an XML document if $data_is_url is true. 101 | * @param integer $options (Optional) Used to specify additional LibXML parameters. The default value is 0. 102 | * @param boolean $data_is_url (Optional) Specify a value of true to specify that data is a path or URL to an XML document instead of string data. The default value is false. 103 | * @param string $ns (Optional) The XML namespace to return values for. 104 | * @param boolean $is_prefix (Optional) (No description provided by PHP.net.) 105 | * @return CFSimpleXML Creates a new element. 106 | */ 107 | public static function init($data, $options = 0, $data_is_url, $ns, $is_prefix = false) 108 | { 109 | if (version_compare(PHP_VERSION, '5.3.0', '<')) 110 | { 111 | throw new Exception('PHP 5.3 or newer is required to instantiate a new class with CLASS::init().'); 112 | } 113 | 114 | $self = get_called_class(); 115 | return new $self($data, $options, $data_is_url, $ns, $is_prefix); 116 | } 117 | 118 | 119 | /*%******************************************************************************************%*/ 120 | // TRAVERSAL 121 | 122 | /** 123 | * Wraps the results of an XPath query in a object. 124 | * 125 | * @param string $expr (Required) The XPath expression to use to query the XML response. 126 | * @return CFArray A object containing the results of the XPath query. 127 | */ 128 | public function query($expr) 129 | { 130 | return new CFArray($this->xpath($expr)); 131 | } 132 | 133 | /** 134 | * Gets the parent or a preferred ancestor of the current element. 135 | * 136 | * @param string $node (Optional) Name of the ancestor element to match and return. 137 | * @return CFSimpleXML A object containing the requested node. 138 | */ 139 | public function parent($node = null) 140 | { 141 | if ($node) 142 | { 143 | $parents = $this->xpath('ancestor-or-self::' . $node); 144 | } 145 | else 146 | { 147 | $parents = $this->xpath('parent::*'); 148 | } 149 | 150 | return $parents[0]; 151 | } 152 | 153 | 154 | /*%******************************************************************************************%*/ 155 | // ALTERNATE FORMATS 156 | 157 | /** 158 | * Gets the current XML node as a true string. 159 | * 160 | * @return string The current XML node as a true string. 161 | */ 162 | public function to_string() 163 | { 164 | $s = parent::__toString(); 165 | 166 | if ($this->attributes()) 167 | { 168 | return json_decode(substr($s, 14)); 169 | } 170 | 171 | return $s; 172 | } 173 | 174 | /** 175 | * Gets the current XML node as , a child class of PHP's class. 176 | * 177 | * @return CFArray The current XML node as a object. 178 | */ 179 | public function to_array() 180 | { 181 | return new CFArray(json_decode(json_encode($this), true)); 182 | } 183 | 184 | /** 185 | * Gets the current XML node as a stdClass object. 186 | * 187 | * @return array The current XML node as a stdClass object. 188 | */ 189 | public function to_stdClass() 190 | { 191 | return json_decode(json_encode($this)); 192 | } 193 | 194 | /** 195 | * Gets the current XML node as a JSON string. 196 | * 197 | * @return string The current XML node as a JSON string. 198 | */ 199 | public function to_json() 200 | { 201 | return json_encode($this); 202 | } 203 | 204 | /** 205 | * Gets the current XML node as a YAML string. 206 | * 207 | * @return string The current XML node as a YAML string. 208 | */ 209 | public function to_yaml() 210 | { 211 | return sfYaml::dump(json_decode(json_encode($this), true), 5); 212 | } 213 | 214 | 215 | /*%******************************************************************************************%*/ 216 | // COMPARISONS 217 | 218 | /** 219 | * Whether or not the current node exactly matches the compared value. 220 | * 221 | * @param string $value (Required) The value to compare the current node to. 222 | * @return boolean Whether or not the current node exactly matches the compared value. 223 | */ 224 | public function is($value) 225 | { 226 | return ((string) $this === $value); 227 | } 228 | 229 | /** 230 | * Whether or not the current node contains the compared value. 231 | * 232 | * @param string $value (Required) The value to use to determine whether it is contained within the node. 233 | * @return boolean Whether or not the current node contains the compared value. 234 | */ 235 | public function contains($value) 236 | { 237 | return (stripos((string) $this, $value) !== false); 238 | } 239 | 240 | /** 241 | * Whether or not the current node matches the regular expression pattern. 242 | * 243 | * @param string $pattern (Required) The pattern to match the current node against. 244 | * @return boolean Whether or not the current node matches the pattern. 245 | */ 246 | public function matches($pattern) 247 | { 248 | return (bool) preg_match($pattern, (string) $this); 249 | } 250 | 251 | /** 252 | * Whether or not the current node starts with the compared value. 253 | * 254 | * @param string $value (Required) The value to compare the current node to. 255 | * @return boolean Whether or not the current node starts with the compared value. 256 | */ 257 | public function starts_with($value) 258 | { 259 | return $this->matches("@^$value@u"); 260 | } 261 | 262 | /** 263 | * Whether or not the current node ends with the compared value. 264 | * 265 | * @param string $value (Required) The value to compare the current node to. 266 | * @return boolean Whether or not the current node ends with the compared value. 267 | */ 268 | public function ends_with($value) 269 | { 270 | return $this->matches("@$value$@u"); 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /utilities/gzipdecode.class.php: -------------------------------------------------------------------------------- 1 | compressed_data = $data; 200 | $this->compressed_size = strlen($data); 201 | } 202 | 203 | /** 204 | * Decode the GZIP stream 205 | * 206 | * @access public 207 | */ 208 | public function parse() 209 | { 210 | if ($this->compressed_size >= $this->min_compressed_size) 211 | { 212 | // Check ID1, ID2, and CM 213 | if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08") 214 | { 215 | return false; 216 | } 217 | 218 | // Get the FLG (FLaGs) 219 | $this->flags = ord($this->compressed_data[3]); 220 | 221 | // FLG bits above (1 << 4) are reserved 222 | if ($this->flags > 0x1F) 223 | { 224 | return false; 225 | } 226 | 227 | // Advance the pointer after the above 228 | $this->position += 4; 229 | 230 | // MTIME 231 | $mtime = substr($this->compressed_data, $this->position, 4); 232 | // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness 233 | if (current(unpack('S', "\x00\x01")) === 1) 234 | { 235 | $mtime = strrev($mtime); 236 | } 237 | $this->MTIME = current(unpack('l', $mtime)); 238 | $this->position += 4; 239 | 240 | // Get the XFL (eXtra FLags) 241 | $this->XFL = ord($this->compressed_data[$this->position++]); 242 | 243 | // Get the OS (Operating System) 244 | $this->OS = ord($this->compressed_data[$this->position++]); 245 | 246 | // Parse the FEXTRA 247 | if ($this->flags & 4) 248 | { 249 | // Read subfield IDs 250 | $this->SI1 = $this->compressed_data[$this->position++]; 251 | $this->SI2 = $this->compressed_data[$this->position++]; 252 | 253 | // SI2 set to zero is reserved for future use 254 | if ($this->SI2 === "\x00") 255 | { 256 | return false; 257 | } 258 | 259 | // Get the length of the extra field 260 | $len = current(unpack('v', substr($this->compressed_data, $this->position, 2))); 261 | $position += 2; 262 | 263 | // Check the length of the string is still valid 264 | $this->min_compressed_size += $len + 4; 265 | if ($this->compressed_size >= $this->min_compressed_size) 266 | { 267 | // Set the extra field to the given data 268 | $this->extra_field = substr($this->compressed_data, $this->position, $len); 269 | $this->position += $len; 270 | } 271 | else 272 | { 273 | return false; 274 | } 275 | } 276 | 277 | // Parse the FNAME 278 | if ($this->flags & 8) 279 | { 280 | // Get the length of the filename 281 | $len = strcspn($this->compressed_data, "\x00", $this->position); 282 | 283 | // Check the length of the string is still valid 284 | $this->min_compressed_size += $len + 1; 285 | if ($this->compressed_size >= $this->min_compressed_size) 286 | { 287 | // Set the original filename to the given string 288 | $this->filename = substr($this->compressed_data, $this->position, $len); 289 | $this->position += $len + 1; 290 | } 291 | else 292 | { 293 | return false; 294 | } 295 | } 296 | 297 | // Parse the FCOMMENT 298 | if ($this->flags & 16) 299 | { 300 | // Get the length of the comment 301 | $len = strcspn($this->compressed_data, "\x00", $this->position); 302 | 303 | // Check the length of the string is still valid 304 | $this->min_compressed_size += $len + 1; 305 | if ($this->compressed_size >= $this->min_compressed_size) 306 | { 307 | // Set the original comment to the given string 308 | $this->comment = substr($this->compressed_data, $this->position, $len); 309 | $this->position += $len + 1; 310 | } 311 | else 312 | { 313 | return false; 314 | } 315 | } 316 | 317 | // Parse the FHCRC 318 | if ($this->flags & 2) 319 | { 320 | // Check the length of the string is still valid 321 | $this->min_compressed_size += $len + 2; 322 | if ($this->compressed_size >= $this->min_compressed_size) 323 | { 324 | // Read the CRC 325 | $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2))); 326 | 327 | // Check the CRC matches 328 | if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc) 329 | { 330 | $this->position += 2; 331 | } 332 | else 333 | { 334 | return false; 335 | } 336 | } 337 | else 338 | { 339 | return false; 340 | } 341 | } 342 | 343 | // Decompress the actual data 344 | if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false) 345 | { 346 | return false; 347 | } 348 | else 349 | { 350 | $this->position = $this->compressed_size - 8; 351 | } 352 | 353 | // Check CRC of data 354 | $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4))); 355 | $this->position += 4; 356 | /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc)) 357 | { 358 | return false; 359 | }*/ 360 | 361 | // Check ISIZE of data 362 | $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4))); 363 | $this->position += 4; 364 | if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize)) 365 | { 366 | return false; 367 | } 368 | 369 | // Wow, against all odds, we've actually got a valid gzip string 370 | return true; 371 | } 372 | else 373 | { 374 | return false; 375 | } 376 | } 377 | } 378 | -------------------------------------------------------------------------------- /utilities/array.class.php: -------------------------------------------------------------------------------- 1 | object extends PHP's built-in object by providing convenience methods for 23 | * rapidly manipulating array data. Specifically, the `CFArray` object is intended for working with 24 | * and objects that are returned by AWS services. 25 | * 26 | * @version 2012.01.17 27 | * @license See the included NOTICE.md file for more information. 28 | * @copyright See the included NOTICE.md file for more information. 29 | * @link http://aws.amazon.com/php/ PHP Developer Center 30 | * @link http://php.net/ArrayObject ArrayObject 31 | */ 32 | class CFArray extends ArrayObject 33 | { 34 | /** 35 | * Constructs a new instance of . 36 | * 37 | * @param mixed $input (Optional) The input parameter accepts an array or an Object. The default value is an empty array. 38 | * @param integer $flags (Optional) Flags to control the behavior of the ArrayObject object. Defaults to . 39 | * @param string $iterator_class (Optional) Specify the class that will be used for iteration of the object. is the default class used. 40 | * @return mixed Either an array of matches, or a single element. 41 | */ 42 | public function __construct($input = array(), $flags = self::STD_PROP_LIST, $iterator_class = 'ArrayIterator') 43 | { 44 | // Provide a default value 45 | $input = $input ? $input : array(); 46 | 47 | try { 48 | return parent::__construct($input, $flags, $iterator_class); 49 | } 50 | catch (InvalidArgumentException $e) 51 | { 52 | throw new CFArray_Exception($e->getMessage()); 53 | } 54 | } 55 | 56 | /** 57 | * Alternate approach to constructing a new instance. Supports chaining. 58 | * 59 | * @param mixed $input (Optional) The input parameter accepts an array or an Object. The default value is an empty array. 60 | * @param integer $flags (Optional) Flags to control the behavior of the ArrayObject object. Defaults to . 61 | * @param string $iterator_class (Optional) Specify the class that will be used for iteration of the object. is the default class used. 62 | * @return mixed Either an array of matches, or a single element. 63 | */ 64 | public static function init($input = array(), $flags = self::STD_PROP_LIST, $iterator_class = 'ArrayIterator') 65 | { 66 | if (version_compare(PHP_VERSION, '5.3.0', '<')) 67 | { 68 | throw new Exception('PHP 5.3 or newer is required to instantiate a new class with CLASS::init().'); 69 | } 70 | 71 | $self = get_called_class(); 72 | return new $self($input, $flags, $iterator_class); 73 | } 74 | 75 | /** 76 | * Handles how the object is rendered when cast as a string. 77 | * 78 | * @return string The word "Array". 79 | */ 80 | public function __toString() 81 | { 82 | return 'Array'; 83 | } 84 | 85 | 86 | /*%******************************************************************************************%*/ 87 | // REFORMATTING 88 | 89 | /** 90 | * Maps each element in the object as an integer. 91 | * 92 | * @return array The contents of the object mapped as integers. 93 | */ 94 | public function map_integer() 95 | { 96 | return array_map('intval', $this->getArrayCopy()); 97 | } 98 | 99 | /** 100 | * Maps each element in the CFArray object as a string. 101 | * 102 | * @param string $pcre (Optional) A Perl-Compatible Regular Expression (PCRE) to filter the names against. 103 | * @return array The contents of the object mapped as strings. If there are no results, the method will return an empty array. 104 | */ 105 | public function map_string($pcre = null) 106 | { 107 | $list = array_map('strval', $this->getArrayCopy()); 108 | $dlist = array(); 109 | 110 | if ($pcre) 111 | { 112 | foreach ($list as $item) 113 | { 114 | $dlist[] = preg_match($pcre, $item) ? $item : null; 115 | } 116 | 117 | $list = array_values(array_filter($dlist)); 118 | } 119 | 120 | return $list; 121 | } 122 | 123 | 124 | /*%******************************************************************************************%*/ 125 | // CONFIRMATION 126 | 127 | /** 128 | * Verifies that _all_ responses were successful. A single failed request will cause to return false. Equivalent to , except it applies to all responses. 129 | * 130 | * @return boolean Whether _all_ requests were successful or not. 131 | */ 132 | public function areOK() 133 | { 134 | $dlist = array(); 135 | $list = $this->getArrayCopy(); 136 | 137 | foreach ($list as $response) 138 | { 139 | if ($response instanceof CFResponse) 140 | { 141 | $dlist[] = $response->isOK(); 142 | } 143 | } 144 | 145 | return (array_search(false, $dlist, true) !== false) ? false : true; 146 | } 147 | 148 | 149 | /*%******************************************************************************************%*/ 150 | // ITERATING AND EXECUTING 151 | 152 | /** 153 | * Iterates over a object, and executes a function for each matched element. 154 | * 155 | * The callback function takes three parameters:
    156 | *
  • $item - mixed - Optional - The individual node in the array.
  • 157 | *
  • $key - mixed - Optional - The key for the array node.
  • 158 | *
  • $bind - mixed - Optional - The variable that was passed into the $bind parameter.
159 | * 160 | * @param string|function $callback (Required) The callback function to execute. PHP 5.3 or newer can use an anonymous function. 161 | * @param mixed $bind (Optional) A variable from the calling scope to pass-by-reference into the local scope of the callback function. 162 | * @return CFArray The original object. 163 | */ 164 | public function each($callback, &$bind = null) 165 | { 166 | $items = $this->getArrayCopy(); 167 | 168 | foreach ($items as $key => &$item) 169 | { 170 | $callback($item, $key, $bind); 171 | } 172 | 173 | return $this; 174 | } 175 | 176 | /** 177 | * Passes each element in the current object through a function, and produces a new object containing the return values. 178 | * 179 | * The callback function takes three parameters:
    180 | *
  • $item - mixed - Optional - The individual node in the array.
  • 181 | *
  • $key - mixed - Optional - The key for the array node.
  • 182 | *
  • $bind - mixed - Optional - The variable that was passed into the $bind parameter.
183 | * 184 | * @param string|function $callback (Required) The callback function to execute. PHP 5.3 or newer can use an anonymous function. 185 | * @param mixed $bind (Optional) A variable from the calling scope to pass-by-reference into the local scope of the callback function. 186 | * @return CFArray A new object containing the return values. 187 | */ 188 | public function map($callback, &$bind = null) 189 | { 190 | $items = $this->getArrayCopy(); 191 | $collect = array(); 192 | 193 | foreach ($items as $key => &$item) 194 | { 195 | $collect[] = $callback($item, $key, $bind); 196 | } 197 | 198 | return new CFArray($collect); 199 | } 200 | 201 | /** 202 | * Filters the list of nodes by passing each value in the current object through a function. The node will be removed if the function returns `false`. 203 | * 204 | * The callback function takes three parameters:
    205 | *
  • $item - mixed - Optional - The individual node in the array.
  • 206 | *
  • $key - mixed - Optional - The key for the array node.
  • 207 | *
  • $bind - mixed - Optional - The variable that was passed into the $bind parameter.
208 | * 209 | * @param string|function $callback (Required) The callback function to execute. PHP 5.3 or newer can use an anonymous function. 210 | * @param mixed $bind (Optional) A variable from the calling scope to pass-by-reference into the local scope of the callback function. 211 | * @return CFArray A new object containing the return values. 212 | */ 213 | public function filter($callback, &$bind = null) 214 | { 215 | $items = $this->getArrayCopy(); 216 | $collect = array(); 217 | 218 | foreach ($items as $key => &$item) 219 | { 220 | if ($callback($item, $key, $bind) !== false) 221 | { 222 | $collect[] = $item; 223 | } 224 | } 225 | 226 | return new CFArray($collect); 227 | } 228 | 229 | /** 230 | * Alias for . This functionality was incorrectly named _reduce_ in earlier versions of the SDK. 231 | * 232 | * @param string|function $callback (Required) The callback function to execute. PHP 5.3 or newer can use an anonymous function. 233 | * @param mixed $bind (Optional) A variable from the calling scope to pass-by-reference into the local scope of the callback function. 234 | * @return CFArray A new object containing the return values. 235 | */ 236 | public function reduce($callback, &$bind = null) 237 | { 238 | return $this->filter($callback, $bind); 239 | } 240 | 241 | 242 | /*%******************************************************************************************%*/ 243 | // TRAVERSAL 244 | 245 | /** 246 | * Gets the first result in the array. 247 | * 248 | * @return mixed The first result in the object. Returns `false` if there are no items in the array. 249 | */ 250 | public function first() 251 | { 252 | $items = $this->getArrayCopy(); 253 | return count($items) ? $items[0] : false; 254 | } 255 | 256 | /** 257 | * Gets the last result in the array. 258 | * 259 | * @return mixed The last result in the object. Returns `false` if there are no items in the array. 260 | */ 261 | public function last() 262 | { 263 | $items = $this->getArrayCopy(); 264 | return count($items) ? end($items) : false; 265 | } 266 | 267 | /** 268 | * Removes all `null` values from an array. 269 | * 270 | * @return CFArray A new object containing the non-null values. 271 | */ 272 | public function compress() 273 | { 274 | return new CFArray(array_filter($this->getArrayCopy())); 275 | } 276 | 277 | /** 278 | * Reindexes the array, starting from zero. 279 | * 280 | * @return CFArray A new object with indexes starting at zero. 281 | */ 282 | public function reindex() 283 | { 284 | return new CFArray(array_values($this->getArrayCopy())); 285 | } 286 | 287 | 288 | /*%******************************************************************************************%*/ 289 | // ALTERNATE FORMATS 290 | 291 | /** 292 | * Gets the current XML node as a JSON string. 293 | * 294 | * @return string The current XML node as a JSON string. 295 | */ 296 | public function to_json() 297 | { 298 | return json_encode($this->getArrayCopy()); 299 | } 300 | 301 | /** 302 | * Gets the current XML node as a YAML string. 303 | * 304 | * @return string The current XML node as a YAML string. 305 | */ 306 | public function to_yaml() 307 | { 308 | return sfYaml::dump($this->getArrayCopy(), 5); 309 | } 310 | } 311 | 312 | class CFArray_Exception extends Exception {} 313 | -------------------------------------------------------------------------------- /utilities/utilities.class.php: -------------------------------------------------------------------------------- 1 | getConstant($const); 88 | } 89 | 90 | /** 91 | * Convert a HEX value to Base64. 92 | * 93 | * @param string $str (Required) Value to convert. 94 | * @return string Base64-encoded string. 95 | */ 96 | public function hex_to_base64($str) 97 | { 98 | $raw = ''; 99 | 100 | for ($i = 0; $i < strlen($str); $i += 2) 101 | { 102 | $raw .= chr(hexdec(substr($str, $i, 2))); 103 | } 104 | 105 | return base64_encode($raw); 106 | } 107 | 108 | /** 109 | * Convert an associative array into a query string. 110 | * 111 | * @param array $array (Required) Array to convert. 112 | * @return string URL-friendly query string. 113 | */ 114 | public function to_query_string($array) 115 | { 116 | $temp = array(); 117 | 118 | foreach ($array as $key => $value) 119 | { 120 | if (is_string($key) && !is_array($value)) 121 | { 122 | $temp[] = rawurlencode($key) . '=' . rawurlencode($value); 123 | } 124 | } 125 | 126 | return implode('&', $temp); 127 | } 128 | 129 | /** 130 | * Convert an associative array into a sign-able string. 131 | * 132 | * @param array $array (Required) Array to convert. 133 | * @return string URL-friendly sign-able string. 134 | */ 135 | public function to_signable_string($array) 136 | { 137 | $t = array(); 138 | 139 | foreach ($array as $k => $v) 140 | { 141 | $t[] = $this->encode_signature2($k) . '=' . $this->encode_signature2($v); 142 | } 143 | 144 | return implode('&', $t); 145 | } 146 | 147 | /** 148 | * Encode the value according to RFC 3986. 149 | * 150 | * @param string $string (Required) String to convert. 151 | * @return string URL-friendly sign-able string. 152 | */ 153 | public function encode_signature2($string) 154 | { 155 | $string = rawurlencode($string); 156 | return str_replace('%7E', '~', $string); 157 | } 158 | 159 | /** 160 | * Convert a query string into an associative array. Multiple, identical keys will become an indexed array. 161 | * 162 | * @param string $qs (Required) Query string to convert. 163 | * @return array Associative array of keys and values. 164 | */ 165 | public function query_to_array($qs) 166 | { 167 | $query = explode('&', $qs); 168 | $data = array(); 169 | 170 | foreach ($query as $q) 171 | { 172 | $q = explode('=', $q); 173 | 174 | if (isset($data[$q[0]]) && is_array($data[$q[0]])) 175 | { 176 | $data[$q[0]][] = urldecode($q[1]); 177 | } 178 | else if (isset($data[$q[0]]) && !is_array($data[$q[0]])) 179 | { 180 | $data[$q[0]] = array($data[$q[0]]); 181 | $data[$q[0]][] = urldecode($q[1]); 182 | } 183 | else 184 | { 185 | $data[urldecode($q[0])] = urldecode($q[1]); 186 | } 187 | } 188 | return $data; 189 | } 190 | 191 | /** 192 | * Return human readable file sizes. 193 | * 194 | * @author Aidan Lister 195 | * @author Ryan Parman 196 | * @license http://www.php.net/license/3_01.txt PHP License 197 | * @param integer $size (Required) Filesize in bytes. 198 | * @param string $unit (Optional) The maximum unit to use. Defaults to the largest appropriate unit. 199 | * @param string $default (Optional) The format for the return string. Defaults to `%01.2f %s`. 200 | * @return string The human-readable file size. 201 | * @link http://aidanlister.com/repos/v/function.size_readable.php Original Function 202 | */ 203 | public function size_readable($size, $unit = null, $default = null) 204 | { 205 | // Units 206 | $sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB'); 207 | $mod = 1024; 208 | $ii = count($sizes) - 1; 209 | 210 | // Max unit 211 | $unit = array_search((string) $unit, $sizes); 212 | if ($unit === null || $unit === false) 213 | { 214 | $unit = $ii; 215 | } 216 | 217 | // Return string 218 | if ($default === null) 219 | { 220 | $default = '%01.2f %s'; 221 | } 222 | 223 | // Loop 224 | $i = 0; 225 | while ($unit != $i && $size >= 1024 && $i < $ii) 226 | { 227 | $size /= $mod; 228 | $i++; 229 | } 230 | 231 | return sprintf($default, $size, $sizes[$i]); 232 | } 233 | 234 | /** 235 | * Convert a number of seconds into Hours:Minutes:Seconds. 236 | * 237 | * @param integer $seconds (Required) The number of seconds to convert. 238 | * @return string The formatted time. 239 | */ 240 | public function time_hms($seconds) 241 | { 242 | $time = ''; 243 | 244 | // First pass 245 | $hours = (int) ($seconds / 3600); 246 | $seconds = $seconds % 3600; 247 | $minutes = (int) ($seconds / 60); 248 | $seconds = $seconds % 60; 249 | 250 | // Cleanup 251 | $time .= ($hours) ? $hours . ':' : ''; 252 | $time .= ($minutes < 10 && $hours > 0) ? '0' . $minutes : $minutes; 253 | $time .= ':'; 254 | $time .= ($seconds < 10) ? '0' . $seconds : $seconds; 255 | 256 | return $time; 257 | } 258 | 259 | /** 260 | * Returns the first value that is set. Based on [Try.these()](http://api.prototypejs.org/language/Try/these/) from [Prototype](http://prototypejs.org). 261 | * 262 | * @param array $attrs (Required) The attributes to test, as strings. Intended for testing properties of the $base object, but also works with variables if you place an @ symbol at the beginning of the command. 263 | * @param object $base (Optional) The base object to use, if any. 264 | * @param mixed $default (Optional) What to return if there are no matches. Defaults to `null`. 265 | * @return mixed Either a matching property of a given object, boolean `false`, or any other data type you might choose. 266 | */ 267 | public function try_these($attrs, $base = null, $default = null) 268 | { 269 | if ($base) 270 | { 271 | foreach ($attrs as $attr) 272 | { 273 | if (isset($base->$attr)) 274 | { 275 | return $base->$attr; 276 | } 277 | } 278 | } 279 | else 280 | { 281 | foreach ($attrs as $attr) 282 | { 283 | if (isset($attr)) 284 | { 285 | return $attr; 286 | } 287 | } 288 | } 289 | 290 | return $default; 291 | } 292 | 293 | /** 294 | * Can be removed once all calls are updated. 295 | * 296 | * @deprecated Use instead. 297 | * @param mixed $obj (Required) The PHP object to convert into a JSON string. 298 | * @return string A JSON string. 299 | */ 300 | public function json_encode($obj) 301 | { 302 | return json_encode($obj); 303 | } 304 | 305 | /** 306 | * Converts a SimpleXML response to an array structure. 307 | * 308 | * @param ResponseCore $response (Required) A response value. 309 | * @return array The response value as a standard, multi-dimensional array. 310 | */ 311 | public function convert_response_to_array(ResponseCore $response) 312 | { 313 | return json_decode(json_encode($response), true); 314 | } 315 | 316 | /** 317 | * Checks to see if a date stamp is ISO-8601 formatted, and if not, makes it so. 318 | * 319 | * @param string $datestamp (Required) A date stamp, or a string that can be parsed into a date stamp. 320 | * @return string An ISO-8601 formatted date stamp. 321 | */ 322 | public function convert_date_to_iso8601($datestamp) 323 | { 324 | if (!preg_match('/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}((\+|-)\d{2}:\d{2}|Z)/m', $datestamp)) 325 | { 326 | return gmdate(self::DATE_FORMAT_ISO8601, strtotime($datestamp)); 327 | } 328 | 329 | return $datestamp; 330 | } 331 | 332 | /** 333 | * Determines whether the data is Base64 encoded or not. 334 | * 335 | * @license http://us.php.net/manual/en/function.base64-decode.php#81425 PHP License 336 | * @param string $s (Required) The string to test. 337 | * @return boolean Whether the string is Base64 encoded or not. 338 | */ 339 | public function is_base64($s) 340 | { 341 | return (bool) preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $s); 342 | } 343 | 344 | /** 345 | * Determines whether the data is a JSON string or not. 346 | * 347 | * @param string $s (Required) The string to test. 348 | * @return boolean Whether the string is a valid JSON object or not. 349 | */ 350 | public function is_json($s) 351 | { 352 | return !!(json_decode($s) instanceof stdClass); 353 | } 354 | 355 | /** 356 | * Decodes `\uXXXX` entities into their real unicode character equivalents. 357 | * 358 | * @param string $s (Required) The string to decode. 359 | * @return string The decoded string. 360 | */ 361 | public function decode_uhex($s) 362 | { 363 | preg_match_all('/\\\u([0-9a-f]{4})/i', $s, $matches); 364 | $matches = $matches[count($matches) - 1]; 365 | $map = array(); 366 | 367 | foreach ($matches as $match) 368 | { 369 | if (!isset($map[$match])) 370 | { 371 | $map['\u' . $match] = html_entity_decode('&#' . hexdec($match) . ';', ENT_NOQUOTES, 'UTF-8'); 372 | } 373 | } 374 | 375 | return str_replace(array_keys($map), $map, $s); 376 | } 377 | 378 | /** 379 | * Generates a random GUID. 380 | * 381 | * @author Alix Axel 382 | * @license http://www.php.net/license/3_01.txt PHP License 383 | * @return string A random GUID. 384 | */ 385 | public function generate_guid() 386 | { 387 | return sprintf( 388 | '%04X%04X-%04X-%04X-%04X-%04X%04X%04X', 389 | mt_rand(0, 65535), 390 | mt_rand(0, 65535), 391 | mt_rand(0, 65535), 392 | mt_rand(16384, 20479), 393 | mt_rand(32768, 49151), 394 | mt_rand(0, 65535), 395 | mt_rand(0, 65535), 396 | mt_rand(0, 65535) 397 | ); 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /lib/requestcore/requestcore.class.php: -------------------------------------------------------------------------------- 1 | ). 91 | */ 92 | public $request_class = 'RequestCore'; 93 | 94 | /** 95 | * The default class to use for HTTP Responses (defaults to ). 96 | */ 97 | public $response_class = 'ResponseCore'; 98 | 99 | /** 100 | * Default useragent string to use. 101 | */ 102 | public $useragent = 'RequestCore/1.4.4'; 103 | 104 | /** 105 | * File to read from while streaming up. 106 | */ 107 | public $read_file = null; 108 | 109 | /** 110 | * The resource to read from while streaming up. 111 | */ 112 | public $read_stream = null; 113 | 114 | /** 115 | * The size of the stream to read from. 116 | */ 117 | public $read_stream_size = null; 118 | 119 | /** 120 | * The length already read from the stream. 121 | */ 122 | public $read_stream_read = 0; 123 | 124 | /** 125 | * File to write to while streaming down. 126 | */ 127 | public $write_file = null; 128 | 129 | /** 130 | * The resource to write to while streaming down. 131 | */ 132 | public $write_stream = null; 133 | 134 | /** 135 | * Stores the intended starting seek position. 136 | */ 137 | public $seek_position = null; 138 | 139 | /** 140 | * The location of the cacert.pem file to use. 141 | */ 142 | public $cacert_location = false; 143 | 144 | /** 145 | * The state of SSL certificate verification. 146 | */ 147 | public $ssl_verification = true; 148 | 149 | /** 150 | * The user-defined callback function to call when a stream is read from. 151 | */ 152 | public $registered_streaming_read_callback = null; 153 | 154 | /** 155 | * The user-defined callback function to call when a stream is written to. 156 | */ 157 | public $registered_streaming_write_callback = null; 158 | 159 | /** 160 | * Whether or not the set_time_limit function should be called. 161 | */ 162 | public $allow_set_time_limit = true; 163 | 164 | /** 165 | * Whether or not to use gzip encoding via CURLOPT_ENCODING 166 | */ 167 | public $use_gzip_enconding = true; 168 | 169 | 170 | /*%******************************************************************************************%*/ 171 | // CONSTANTS 172 | 173 | /** 174 | * GET HTTP Method 175 | */ 176 | const HTTP_GET = 'GET'; 177 | 178 | /** 179 | * POST HTTP Method 180 | */ 181 | const HTTP_POST = 'POST'; 182 | 183 | /** 184 | * PUT HTTP Method 185 | */ 186 | const HTTP_PUT = 'PUT'; 187 | 188 | /** 189 | * DELETE HTTP Method 190 | */ 191 | const HTTP_DELETE = 'DELETE'; 192 | 193 | /** 194 | * HEAD HTTP Method 195 | */ 196 | const HTTP_HEAD = 'HEAD'; 197 | 198 | 199 | /*%******************************************************************************************%*/ 200 | // CONSTRUCTOR/DESTRUCTOR 201 | 202 | /** 203 | * Constructs a new instance of this class. 204 | * 205 | * @param string $url (Optional) The URL to request or service endpoint to query. 206 | * @param string $proxy (Optional) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` 207 | * @param array $helpers (Optional) An associative array of classnames to use for request, and response functionality. Gets passed in automatically by the calling class. 208 | * @return $this A reference to the current instance. 209 | */ 210 | public function __construct($url = null, $proxy = null, $helpers = null) 211 | { 212 | // Set some default values. 213 | $this->request_url = $url; 214 | $this->method = self::HTTP_GET; 215 | $this->request_headers = array(); 216 | $this->request_body = ''; 217 | 218 | // Determine if set_time_limit can be called 219 | if (strpos(ini_get('disable_functions'), 'set_time_limit') !== false) 220 | { 221 | $this->allow_set_time_limit = false; 222 | } 223 | 224 | // Set a new Request class if one was set. 225 | if (isset($helpers['request']) && !empty($helpers['request'])) 226 | { 227 | $this->request_class = $helpers['request']; 228 | } 229 | 230 | // Set a new Request class if one was set. 231 | if (isset($helpers['response']) && !empty($helpers['response'])) 232 | { 233 | $this->response_class = $helpers['response']; 234 | } 235 | 236 | if ($proxy) 237 | { 238 | $this->set_proxy($proxy); 239 | } 240 | 241 | return $this; 242 | } 243 | 244 | /** 245 | * Destructs the instance. Closes opened file handles. 246 | * 247 | * @return $this A reference to the current instance. 248 | */ 249 | public function __destruct() 250 | { 251 | if (isset($this->read_file) && isset($this->read_stream)) 252 | { 253 | fclose($this->read_stream); 254 | } 255 | 256 | if (isset($this->write_file) && isset($this->write_stream)) 257 | { 258 | fclose($this->write_stream); 259 | } 260 | 261 | return $this; 262 | } 263 | 264 | 265 | /*%******************************************************************************************%*/ 266 | // REQUEST METHODS 267 | 268 | /** 269 | * Sets the credentials to use for authentication. 270 | * 271 | * @param string $user (Required) The username to authenticate with. 272 | * @param string $pass (Required) The password to authenticate with. 273 | * @return $this A reference to the current instance. 274 | */ 275 | public function set_credentials($user, $pass) 276 | { 277 | $this->username = $user; 278 | $this->password = $pass; 279 | return $this; 280 | } 281 | 282 | /** 283 | * Adds a custom HTTP header to the cURL request. 284 | * 285 | * @param string $key (Required) The custom HTTP header to set. 286 | * @param mixed $value (Required) The value to assign to the custom HTTP header. 287 | * @return $this A reference to the current instance. 288 | */ 289 | public function add_header($key, $value) 290 | { 291 | $this->request_headers[$key] = $value; 292 | return $this; 293 | } 294 | 295 | /** 296 | * Removes an HTTP header from the cURL request. 297 | * 298 | * @param string $key (Required) The custom HTTP header to set. 299 | * @return $this A reference to the current instance. 300 | */ 301 | public function remove_header($key) 302 | { 303 | if (isset($this->request_headers[$key])) 304 | { 305 | unset($this->request_headers[$key]); 306 | } 307 | return $this; 308 | } 309 | 310 | /** 311 | * Set the method type for the request. 312 | * 313 | * @param string $method (Required) One of the following constants: , , , , . 314 | * @return $this A reference to the current instance. 315 | */ 316 | public function set_method($method) 317 | { 318 | $this->method = strtoupper($method); 319 | return $this; 320 | } 321 | 322 | /** 323 | * Sets a custom useragent string for the class. 324 | * 325 | * @param string $ua (Required) The useragent string to use. 326 | * @return $this A reference to the current instance. 327 | */ 328 | public function set_useragent($ua) 329 | { 330 | $this->useragent = $ua; 331 | return $this; 332 | } 333 | 334 | /** 335 | * Set the body to send in the request. 336 | * 337 | * @param string $body (Required) The textual content to send along in the body of the request. 338 | * @return $this A reference to the current instance. 339 | */ 340 | public function set_body($body) 341 | { 342 | $this->request_body = $body; 343 | return $this; 344 | } 345 | 346 | /** 347 | * Set the URL to make the request to. 348 | * 349 | * @param string $url (Required) The URL to make the request to. 350 | * @return $this A reference to the current instance. 351 | */ 352 | public function set_request_url($url) 353 | { 354 | $this->request_url = $url; 355 | return $this; 356 | } 357 | 358 | /** 359 | * Set additional CURLOPT settings. These will merge with the default settings, and override if 360 | * there is a duplicate. 361 | * 362 | * @param array $curlopts (Optional) A set of key-value pairs that set `CURLOPT` options. These will merge with the existing CURLOPTs, and ones passed here will override the defaults. Keys should be the `CURLOPT_*` constants, not strings. 363 | * @return $this A reference to the current instance. 364 | */ 365 | public function set_curlopts($curlopts) 366 | { 367 | $this->curlopts = $curlopts; 368 | return $this; 369 | } 370 | 371 | /** 372 | * Sets the length in bytes to read from the stream while streaming up. 373 | * 374 | * @param integer $size (Required) The length in bytes to read from the stream. 375 | * @return $this A reference to the current instance. 376 | */ 377 | public function set_read_stream_size($size) 378 | { 379 | $this->read_stream_size = $size; 380 | 381 | return $this; 382 | } 383 | 384 | /** 385 | * Sets the resource to read from while streaming up. Reads the stream from its current position until 386 | * EOF or `$size` bytes have been read. If `$size` is not given it will be determined by and 387 | * . 388 | * 389 | * @param resource $resource (Required) The readable resource to read from. 390 | * @param integer $size (Optional) The size of the stream to read. 391 | * @return $this A reference to the current instance. 392 | */ 393 | public function set_read_stream($resource, $size = null) 394 | { 395 | if (!isset($size) || $size < 0) 396 | { 397 | $stats = fstat($resource); 398 | 399 | if ($stats && $stats['size'] >= 0) 400 | { 401 | $position = ftell($resource); 402 | 403 | if ($position !== false && $position >= 0) 404 | { 405 | $size = $stats['size'] - $position; 406 | } 407 | } 408 | } 409 | 410 | $this->read_stream = $resource; 411 | 412 | return $this->set_read_stream_size($size); 413 | } 414 | 415 | /** 416 | * Sets the file to read from while streaming up. 417 | * 418 | * @param string $location (Required) The readable location to read from. 419 | * @return $this A reference to the current instance. 420 | */ 421 | public function set_read_file($location) 422 | { 423 | $this->read_file = $location; 424 | $read_file_handle = fopen($location, 'r'); 425 | 426 | return $this->set_read_stream($read_file_handle); 427 | } 428 | 429 | /** 430 | * Sets the resource to write to while streaming down. 431 | * 432 | * @param resource $resource (Required) The writeable resource to write to. 433 | * @return $this A reference to the current instance. 434 | */ 435 | public function set_write_stream($resource) 436 | { 437 | $this->write_stream = $resource; 438 | 439 | return $this; 440 | } 441 | 442 | /** 443 | * Sets the file to write to while streaming down. 444 | * 445 | * @param string $location (Required) The writeable location to write to. 446 | * @return $this A reference to the current instance. 447 | */ 448 | public function set_write_file($location) 449 | { 450 | $this->write_file = $location; 451 | $write_file_handle = fopen($location, 'w'); 452 | 453 | return $this->set_write_stream($write_file_handle); 454 | } 455 | 456 | /** 457 | * Set the proxy to use for making requests. 458 | * 459 | * @param string $proxy (Required) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` 460 | * @return $this A reference to the current instance. 461 | */ 462 | public function set_proxy($proxy) 463 | { 464 | $proxy = parse_url($proxy); 465 | $proxy['user'] = isset($proxy['user']) ? $proxy['user'] : null; 466 | $proxy['pass'] = isset($proxy['pass']) ? $proxy['pass'] : null; 467 | $proxy['port'] = isset($proxy['port']) ? $proxy['port'] : null; 468 | $this->proxy = $proxy; 469 | return $this; 470 | } 471 | 472 | /** 473 | * Set the intended starting seek position. 474 | * 475 | * @param integer $position (Required) The byte-position of the stream to begin reading from. 476 | * @return $this A reference to the current instance. 477 | */ 478 | public function set_seek_position($position) 479 | { 480 | $this->seek_position = isset($position) ? (integer) $position : null; 481 | 482 | return $this; 483 | } 484 | 485 | /** 486 | * Register a callback function to execute whenever a data stream is read from using 487 | * . 488 | * 489 | * The user-defined callback function should accept three arguments: 490 | * 491 | *
    492 | *
  • $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
  • 493 | *
  • $file_handle - resource - Required - The file handle resource that represents the file on the local file system.
  • 494 | *
  • $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
  • 495 | *
496 | * 497 | * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
    498 | *
  • The name of a global function to execute, passed as a string.
  • 499 | *
  • A method to execute, passed as array('ClassName', 'MethodName').
  • 500 | *
  • An anonymous function (PHP 5.3+).
501 | * @return $this A reference to the current instance. 502 | */ 503 | public function register_streaming_read_callback($callback) 504 | { 505 | $this->registered_streaming_read_callback = $callback; 506 | 507 | return $this; 508 | } 509 | 510 | /** 511 | * Register a callback function to execute whenever a data stream is written to using 512 | * . 513 | * 514 | * The user-defined callback function should accept two arguments: 515 | * 516 | *
    517 | *
  • $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
  • 518 | *
  • $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
  • 519 | *
520 | * 521 | * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
    522 | *
  • The name of a global function to execute, passed as a string.
  • 523 | *
  • A method to execute, passed as array('ClassName', 'MethodName').
  • 524 | *
  • An anonymous function (PHP 5.3+).
525 | * @return $this A reference to the current instance. 526 | */ 527 | public function register_streaming_write_callback($callback) 528 | { 529 | $this->registered_streaming_write_callback = $callback; 530 | 531 | return $this; 532 | } 533 | 534 | 535 | /*%******************************************************************************************%*/ 536 | // PREPARE, SEND, AND PROCESS REQUEST 537 | 538 | /** 539 | * A callback function that is invoked by cURL for streaming up. 540 | * 541 | * @param resource $curl_handle (Required) The cURL handle for the request. 542 | * @param resource $file_handle (Required) The open file handle resource. 543 | * @param integer $length (Required) The maximum number of bytes to read. 544 | * @return binary Binary data from a stream. 545 | */ 546 | public function streaming_read_callback($curl_handle, $file_handle, $length) 547 | { 548 | // Once we've sent as much as we're supposed to send... 549 | if ($this->read_stream_read >= $this->read_stream_size) 550 | { 551 | // Send EOF 552 | return ''; 553 | } 554 | 555 | // If we're at the beginning of an upload and need to seek... 556 | if ($this->read_stream_read == 0 && isset($this->seek_position) && $this->seek_position !== ftell($this->read_stream)) 557 | { 558 | if (fseek($this->read_stream, $this->seek_position) !== 0) 559 | { 560 | throw new RequestCore_Exception('The stream does not support seeking and is either not at the requested position or the position is unknown.'); 561 | } 562 | } 563 | 564 | $read = fread($this->read_stream, min($this->read_stream_size - $this->read_stream_read, $length)); // Remaining upload data or cURL's requested chunk size 565 | $this->read_stream_read += strlen($read); 566 | 567 | $out = $read === false ? '' : $read; 568 | 569 | // Execute callback function 570 | if ($this->registered_streaming_read_callback) 571 | { 572 | call_user_func($this->registered_streaming_read_callback, $curl_handle, $file_handle, $out); 573 | } 574 | 575 | return $out; 576 | } 577 | 578 | /** 579 | * A callback function that is invoked by cURL for streaming down. 580 | * 581 | * @param resource $curl_handle (Required) The cURL handle for the request. 582 | * @param binary $data (Required) The data to write. 583 | * @return integer The number of bytes written. 584 | */ 585 | public function streaming_write_callback($curl_handle, $data) 586 | { 587 | $length = strlen($data); 588 | $written_total = 0; 589 | $written_last = 0; 590 | 591 | while ($written_total < $length) 592 | { 593 | $written_last = fwrite($this->write_stream, substr($data, $written_total)); 594 | 595 | if ($written_last === false) 596 | { 597 | return $written_total; 598 | } 599 | 600 | $written_total += $written_last; 601 | } 602 | 603 | // Execute callback function 604 | if ($this->registered_streaming_write_callback) 605 | { 606 | call_user_func($this->registered_streaming_write_callback, $curl_handle, $written_total); 607 | } 608 | 609 | return $written_total; 610 | } 611 | 612 | /** 613 | * Prepares and adds the details of the cURL request. This can be passed along to a 614 | * function. 615 | * 616 | * @return resource The handle for the cURL object. 617 | */ 618 | public function prep_request() 619 | { 620 | $curl_handle = curl_init(); 621 | 622 | // Set default options. 623 | curl_setopt($curl_handle, CURLOPT_URL, $this->request_url); 624 | curl_setopt($curl_handle, CURLOPT_FILETIME, true); 625 | curl_setopt($curl_handle, CURLOPT_FRESH_CONNECT, false); 626 | curl_setopt($curl_handle, CURLOPT_CLOSEPOLICY, CURLCLOSEPOLICY_LEAST_RECENTLY_USED); 627 | curl_setopt($curl_handle, CURLOPT_MAXREDIRS, 5); 628 | curl_setopt($curl_handle, CURLOPT_HEADER, true); 629 | curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true); 630 | curl_setopt($curl_handle, CURLOPT_TIMEOUT, 5184000); 631 | curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 120); 632 | curl_setopt($curl_handle, CURLOPT_NOSIGNAL, true); 633 | curl_setopt($curl_handle, CURLOPT_REFERER, $this->request_url); 634 | curl_setopt($curl_handle, CURLOPT_USERAGENT, $this->useragent); 635 | curl_setopt($curl_handle, CURLOPT_READFUNCTION, array($this, 'streaming_read_callback')); 636 | 637 | // Verification of the SSL cert 638 | if ($this->ssl_verification) 639 | { 640 | curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, true); 641 | curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, 2); 642 | } 643 | else 644 | { 645 | curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, false); 646 | curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, false); 647 | } 648 | 649 | // chmod the file as 0755 650 | if ($this->cacert_location === true) 651 | { 652 | curl_setopt($curl_handle, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem'); 653 | } 654 | elseif (is_string($this->cacert_location)) 655 | { 656 | curl_setopt($curl_handle, CURLOPT_CAINFO, $this->cacert_location); 657 | } 658 | 659 | // Debug mode 660 | if ($this->debug_mode) 661 | { 662 | curl_setopt($curl_handle, CURLOPT_VERBOSE, true); 663 | } 664 | 665 | // Handle open_basedir & safe mode 666 | if (!ini_get('safe_mode') && !ini_get('open_basedir')) 667 | { 668 | curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true); 669 | } 670 | 671 | // Enable a proxy connection if requested. 672 | if ($this->proxy) 673 | { 674 | curl_setopt($curl_handle, CURLOPT_HTTPPROXYTUNNEL, true); 675 | 676 | $host = $this->proxy['host']; 677 | $host .= ($this->proxy['port']) ? ':' . $this->proxy['port'] : ''; 678 | curl_setopt($curl_handle, CURLOPT_PROXY, $host); 679 | 680 | if (isset($this->proxy['user']) && isset($this->proxy['pass'])) 681 | { 682 | curl_setopt($curl_handle, CURLOPT_PROXYUSERPWD, $this->proxy['user'] . ':' . $this->proxy['pass']); 683 | } 684 | } 685 | 686 | // Set credentials for HTTP Basic/Digest Authentication. 687 | if ($this->username && $this->password) 688 | { 689 | curl_setopt($curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); 690 | curl_setopt($curl_handle, CURLOPT_USERPWD, $this->username . ':' . $this->password); 691 | } 692 | 693 | // Handle the encoding if we can. 694 | if ($this->use_gzip_enconding && extension_loaded('zlib')) 695 | { 696 | curl_setopt($curl_handle, CURLOPT_ENCODING, 'gzip, deflate'); 697 | } 698 | 699 | // Process custom headers 700 | if (isset($this->request_headers) && count($this->request_headers)) 701 | { 702 | $temp_headers = array(); 703 | 704 | if (!array_key_exists('Expect', $this->request_headers)) 705 | { 706 | $this->request_headers['Expect'] = ''; 707 | } 708 | 709 | foreach ($this->request_headers as $k => $v) 710 | { 711 | $temp_headers[] = $k . ': ' . $v; 712 | } 713 | 714 | curl_setopt($curl_handle, CURLOPT_HTTPHEADER, $temp_headers); 715 | } 716 | 717 | switch ($this->method) 718 | { 719 | case self::HTTP_PUT: 720 | curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'PUT'); 721 | if (isset($this->read_stream)) 722 | { 723 | if (!isset($this->read_stream_size) || $this->read_stream_size < 0) 724 | { 725 | throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.'); 726 | } 727 | 728 | curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size); 729 | curl_setopt($curl_handle, CURLOPT_UPLOAD, true); 730 | } 731 | else 732 | { 733 | curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); 734 | } 735 | break; 736 | 737 | case self::HTTP_POST: 738 | curl_setopt($curl_handle, CURLOPT_POST, true); 739 | curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); 740 | break; 741 | 742 | case self::HTTP_HEAD: 743 | curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, self::HTTP_HEAD); 744 | curl_setopt($curl_handle, CURLOPT_NOBODY, 1); 745 | break; 746 | 747 | default: // Assumed GET 748 | curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, $this->method); 749 | if (isset($this->write_stream)) 750 | { 751 | curl_setopt($curl_handle, CURLOPT_WRITEFUNCTION, array($this, 'streaming_write_callback')); 752 | curl_setopt($curl_handle, CURLOPT_HEADER, false); 753 | } 754 | else 755 | { 756 | curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); 757 | } 758 | break; 759 | } 760 | 761 | // Merge in the CURLOPTs 762 | if (isset($this->curlopts) && sizeof($this->curlopts) > 0) 763 | { 764 | foreach ($this->curlopts as $k => $v) 765 | { 766 | curl_setopt($curl_handle, $k, $v); 767 | } 768 | } 769 | 770 | return $curl_handle; 771 | } 772 | 773 | /** 774 | * Take the post-processed cURL data and break it down into useful header/body/info chunks. Uses the 775 | * data stored in the `curl_handle` and `response` properties unless replacement data is passed in via 776 | * parameters. 777 | * 778 | * @param resource $curl_handle (Optional) The reference to the already executed cURL request. 779 | * @param string $response (Optional) The actual response content itself that needs to be parsed. 780 | * @return ResponseCore A object containing a parsed HTTP response. 781 | */ 782 | public function process_response($curl_handle = null, $response = null) 783 | { 784 | // Accept a custom one if it's passed. 785 | if ($curl_handle && $response) 786 | { 787 | $this->curl_handle = $curl_handle; 788 | $this->response = $response; 789 | } 790 | 791 | // As long as this came back as a valid resource... 792 | if (is_resource($this->curl_handle)) 793 | { 794 | // Determine what's what. 795 | $header_size = curl_getinfo($this->curl_handle, CURLINFO_HEADER_SIZE); 796 | $this->response_headers = substr($this->response, 0, $header_size); 797 | $this->response_body = substr($this->response, $header_size); 798 | $this->response_code = curl_getinfo($this->curl_handle, CURLINFO_HTTP_CODE); 799 | $this->response_info = curl_getinfo($this->curl_handle); 800 | 801 | // Parse out the headers 802 | $this->response_headers = explode("\r\n\r\n", trim($this->response_headers)); 803 | $this->response_headers = array_pop($this->response_headers); 804 | $this->response_headers = explode("\r\n", $this->response_headers); 805 | array_shift($this->response_headers); 806 | 807 | // Loop through and split up the headers. 808 | $header_assoc = array(); 809 | foreach ($this->response_headers as $header) 810 | { 811 | $kv = explode(': ', $header); 812 | $header_assoc[strtolower($kv[0])] = $kv[1]; 813 | } 814 | 815 | // Reset the headers to the appropriate property. 816 | $this->response_headers = $header_assoc; 817 | $this->response_headers['_info'] = $this->response_info; 818 | $this->response_headers['_info']['method'] = $this->method; 819 | 820 | if ($curl_handle && $response) 821 | { 822 | return new $this->response_class($this->response_headers, $this->response_body, $this->response_code, $this->curl_handle); 823 | } 824 | } 825 | 826 | // Return false 827 | return false; 828 | } 829 | 830 | /** 831 | * Sends the request, calling necessary utility functions to update built-in properties. 832 | * 833 | * @param boolean $parse (Optional) Whether to parse the response with ResponseCore or not. 834 | * @return string The resulting unparsed data from the request. 835 | */ 836 | public function send_request($parse = false) 837 | { 838 | if ($this->allow_set_time_limit) 839 | { 840 | set_time_limit(0); 841 | } 842 | 843 | $curl_handle = $this->prep_request(); 844 | $this->response = curl_exec($curl_handle); 845 | 846 | if ($this->response === false) 847 | { 848 | throw new cURL_Exception('cURL resource: ' . (string) $curl_handle . '; cURL error: ' . curl_error($curl_handle) . ' (cURL error code ' . curl_errno($curl_handle) . '). See http://curl.haxx.se/libcurl/c/libcurl-errors.html for an explanation of error codes.'); 849 | } 850 | 851 | $parsed_response = $this->process_response($curl_handle, $this->response); 852 | 853 | curl_close($curl_handle); 854 | 855 | if ($parse) 856 | { 857 | return $parsed_response; 858 | } 859 | 860 | return $this->response; 861 | } 862 | 863 | /** 864 | * Sends the request using , enabling parallel requests. Uses the "rolling" method. 865 | * 866 | * @param array $handles (Required) An indexed array of cURL handles to process simultaneously. 867 | * @param array $opt (Optional) An associative array of parameters that can have the following keys:
    868 | *
  • callback - string|array - Optional - The string name of a function to pass the response data to. If this is a method, pass an array where the [0] index is the class and the [1] index is the method name.
  • 869 | *
  • limit - integer - Optional - The number of simultaneous requests to make. This can be useful for scaling around slow server responses. Defaults to trusting cURLs judgement as to how many to use.
870 | * @return array Post-processed cURL responses. 871 | */ 872 | public function send_multi_request($handles, $opt = null) 873 | { 874 | if ($this->allow_set_time_limit) 875 | { 876 | set_time_limit(0); 877 | } 878 | 879 | // Skip everything if there are no handles to process. 880 | if (count($handles) === 0) return array(); 881 | 882 | if (!$opt) $opt = array(); 883 | 884 | // Initialize any missing options 885 | $limit = isset($opt['limit']) ? $opt['limit'] : -1; 886 | 887 | // Initialize 888 | $handle_list = $handles; 889 | $http = new $this->request_class(); 890 | $multi_handle = curl_multi_init(); 891 | $handles_post = array(); 892 | $added = count($handles); 893 | $last_handle = null; 894 | $count = 0; 895 | $i = 0; 896 | 897 | // Loop through the cURL handles and add as many as it set by the limit parameter. 898 | while ($i < $added) 899 | { 900 | if ($limit > 0 && $i >= $limit) break; 901 | curl_multi_add_handle($multi_handle, array_shift($handles)); 902 | $i++; 903 | } 904 | 905 | do 906 | { 907 | $active = false; 908 | 909 | // Start executing and wait for a response. 910 | while (($status = curl_multi_exec($multi_handle, $active)) === CURLM_CALL_MULTI_PERFORM) 911 | { 912 | // Start looking for possible responses immediately when we have to add more handles 913 | if (count($handles) > 0) break; 914 | } 915 | 916 | // Figure out which requests finished. 917 | $to_process = array(); 918 | 919 | while ($done = curl_multi_info_read($multi_handle)) 920 | { 921 | // Since curl_errno() isn't reliable for handles that were in multirequests, we check the 'result' of the info read, which contains the curl error number, (listed here http://curl.haxx.se/libcurl/c/libcurl-errors.html ) 922 | if ($done['result'] > 0) 923 | { 924 | throw new cURL_Multi_Exception('cURL resource: ' . (string) $done['handle'] . '; cURL error: ' . curl_error($done['handle']) . ' (cURL error code ' . $done['result'] . '). See http://curl.haxx.se/libcurl/c/libcurl-errors.html for an explanation of error codes.'); 925 | } 926 | 927 | // Because curl_multi_info_read() might return more than one message about a request, we check to see if this request is already in our array of completed requests 928 | elseif (!isset($to_process[(int) $done['handle']])) 929 | { 930 | $to_process[(int) $done['handle']] = $done; 931 | } 932 | } 933 | 934 | // Actually deal with the request 935 | foreach ($to_process as $pkey => $done) 936 | { 937 | $response = $http->process_response($done['handle'], curl_multi_getcontent($done['handle'])); 938 | $key = array_search($done['handle'], $handle_list, true); 939 | $handles_post[$key] = $response; 940 | 941 | if (count($handles) > 0) 942 | { 943 | curl_multi_add_handle($multi_handle, array_shift($handles)); 944 | } 945 | 946 | curl_multi_remove_handle($multi_handle, $done['handle']); 947 | curl_close($done['handle']); 948 | } 949 | } 950 | while ($active || count($handles_post) < $added); 951 | 952 | curl_multi_close($multi_handle); 953 | 954 | ksort($handles_post, SORT_NUMERIC); 955 | return $handles_post; 956 | } 957 | 958 | 959 | /*%******************************************************************************************%*/ 960 | // RESPONSE METHODS 961 | 962 | /** 963 | * Get the HTTP response headers from the request. 964 | * 965 | * @param string $header (Optional) A specific header value to return. Defaults to all headers. 966 | * @return string|array All or selected header values. 967 | */ 968 | public function get_response_header($header = null) 969 | { 970 | if ($header) 971 | { 972 | return $this->response_headers[strtolower($header)]; 973 | } 974 | return $this->response_headers; 975 | } 976 | 977 | /** 978 | * Get the HTTP response body from the request. 979 | * 980 | * @return string The response body. 981 | */ 982 | public function get_response_body() 983 | { 984 | return $this->response_body; 985 | } 986 | 987 | /** 988 | * Get the HTTP response code from the request. 989 | * 990 | * @return string The HTTP response code. 991 | */ 992 | public function get_response_code() 993 | { 994 | return $this->response_code; 995 | } 996 | } 997 | 998 | 999 | /** 1000 | * Container for all response-related methods. 1001 | */ 1002 | class ResponseCore 1003 | { 1004 | /** 1005 | * Stores the HTTP header information. 1006 | */ 1007 | public $header; 1008 | 1009 | /** 1010 | * Stores the SimpleXML response. 1011 | */ 1012 | public $body; 1013 | 1014 | /** 1015 | * Stores the HTTP response code. 1016 | */ 1017 | public $status; 1018 | 1019 | /** 1020 | * Constructs a new instance of this class. 1021 | * 1022 | * @param array $header (Required) Associative array of HTTP headers (typically returned by ). 1023 | * @param string $body (Required) XML-formatted response from AWS. 1024 | * @param integer $status (Optional) HTTP response status code from the request. 1025 | * @return object Contains an `header` property (HTTP headers as an associative array), a or `body` property, and an `status` code. 1026 | */ 1027 | public function __construct($header, $body, $status = null) 1028 | { 1029 | $this->header = $header; 1030 | $this->body = $body; 1031 | $this->status = $status; 1032 | 1033 | return $this; 1034 | } 1035 | 1036 | /** 1037 | * Did we receive the status code we expected? 1038 | * 1039 | * @param integer|array $codes (Optional) The status code(s) to expect. Pass an for a single acceptable value, or an of integers for multiple acceptable values. 1040 | * @return boolean Whether we received the expected status code or not. 1041 | */ 1042 | public function isOK($codes = array(200, 201, 204, 206)) 1043 | { 1044 | if (is_array($codes)) 1045 | { 1046 | return in_array($this->status, $codes); 1047 | } 1048 | 1049 | return $this->status === $codes; 1050 | } 1051 | } 1052 | 1053 | class cURL_Exception extends Exception {} 1054 | class cURL_Multi_Exception extends cURL_Exception {} 1055 | class RequestCore_Exception extends Exception {} 1056 | -------------------------------------------------------------------------------- /sdk.class.php: -------------------------------------------------------------------------------- 1 | ). 131 | */ 132 | public $utilities_class = 'CFUtilities'; 133 | 134 | /** 135 | * The default class to use for HTTP requests (defaults to ). 136 | */ 137 | public $request_class = 'CFRequest'; 138 | 139 | /** 140 | * The default class to use for HTTP responses (defaults to ). 141 | */ 142 | public $response_class = 'CFResponse'; 143 | 144 | /** 145 | * The default class to use for parsing XML (defaults to ). 146 | */ 147 | public $parser_class = 'CFSimpleXML'; 148 | 149 | /** 150 | * The default class to use for handling batch requests (defaults to ). 151 | */ 152 | public $batch_class = 'CFBatchRequest'; 153 | 154 | /** 155 | * The state of SSL/HTTPS use. 156 | */ 157 | public $use_ssl = true; 158 | 159 | /** 160 | * The state of SSL certificate verification. 161 | */ 162 | public $ssl_verification = true; 163 | 164 | /** 165 | * The proxy to use for connecting. 166 | */ 167 | public $proxy = null; 168 | 169 | /** 170 | * The alternate hostname to use, if any. 171 | */ 172 | public $hostname = null; 173 | 174 | /** 175 | * The state of the capability to override the hostname with . 176 | */ 177 | public $override_hostname = true; 178 | 179 | /** 180 | * The alternate port number to use, if any. 181 | */ 182 | public $port_number = null; 183 | 184 | /** 185 | * The alternate resource prefix to use, if any. 186 | */ 187 | public $resource_prefix = null; 188 | 189 | /** 190 | * The state of cache flow usage. 191 | */ 192 | public $use_cache_flow = false; 193 | 194 | /** 195 | * The caching class to use. 196 | */ 197 | public $cache_class = null; 198 | 199 | /** 200 | * The caching location to use. 201 | */ 202 | public $cache_location = null; 203 | 204 | /** 205 | * When the cache should be considered stale. 206 | */ 207 | public $cache_expires = null; 208 | 209 | /** 210 | * The state of cache compression. 211 | */ 212 | public $cache_compress = null; 213 | 214 | /** 215 | * The current instantiated cache object. 216 | */ 217 | public $cache_object = null; 218 | 219 | /** 220 | * The current instantiated batch request object. 221 | */ 222 | public $batch_object = null; 223 | 224 | /** 225 | * The internally instantiated batch request object. 226 | */ 227 | public $internal_batch_object = null; 228 | 229 | /** 230 | * The state of batch flow usage. 231 | */ 232 | public $use_batch_flow = false; 233 | 234 | /** 235 | * The state of the cache deletion setting. 236 | */ 237 | public $delete_cache = false; 238 | 239 | /** 240 | * The state of the debug mode setting. 241 | */ 242 | public $debug_mode = false; 243 | 244 | /** 245 | * The number of times to retry failed requests. 246 | */ 247 | public $max_retries = 3; 248 | 249 | /** 250 | * The user-defined callback function to call when a stream is read from. 251 | */ 252 | public $registered_streaming_read_callback = null; 253 | 254 | /** 255 | * The user-defined callback function to call when a stream is written to. 256 | */ 257 | public $registered_streaming_write_callback = null; 258 | 259 | /** 260 | * The credentials to use for authentication. 261 | */ 262 | public $credentials = array(); 263 | 264 | /** 265 | * The authentication class to use. 266 | */ 267 | public $auth_class = null; 268 | 269 | /** 270 | * The operation to execute. 271 | */ 272 | public $operation = null; 273 | 274 | /** 275 | * The payload to send. 276 | */ 277 | public $payload = array(); 278 | 279 | /** 280 | * The string prefix to prepend to the operation name. 281 | */ 282 | public $operation_prefix = ''; 283 | 284 | /** 285 | * The number of times a request has been retried. 286 | */ 287 | public $redirects = 0; 288 | 289 | /** 290 | * The state of whether the response should be parsed or not. 291 | */ 292 | public $parse_the_response = true; 293 | 294 | 295 | /*%******************************************************************************************%*/ 296 | // CONSTRUCTOR 297 | 298 | /** 299 | * The constructor. This class should not be instantiated directly. Rather, a service-specific class 300 | * should be instantiated. 301 | * 302 | * @param array $options (Optional) An associative array of parameters that can have the following keys:
    303 | *
  • certificate_authority - boolean - Optional - Determines which Cerificate Authority file to use. A value of boolean false will use the Certificate Authority file available on the system. A value of boolean true will use the Certificate Authority provided by the SDK. Passing a file system path to a Certificate Authority file (chmodded to 0755) will use that. Leave this set to false if you're not sure.
  • 304 | *
  • credentials - string - Optional - The name of the credential set to use for authentication.
  • 305 | *
  • default_cache_config - string - Optional - This option allows a preferred storage type to be configured for long-term caching. This can be changed later using the method. Valid values are: apc, xcache, or a file system path such as ./cache or /tmp/cache/.
  • 306 | *
  • key - string - Optional - Your AWS key, or a session key. If blank, the default credential set will be used.
  • 307 | *
  • instance_profile_timeout - integer - Optional - When retrieving IAM instance profile credentials, there is a hard connection timeout that defaults to 2 seconds to prevent unnecessary on non-EC2 systems. This setting allows you to change that timeout if needed.
  • 308 | *
  • secret - string - Optional - Your AWS secret key, or a session secret key. If blank, the default credential set will be used.
  • 309 | *
  • token - string - Optional - An AWS session token.
  • 310 | *
  • use_instance_profile_credentials - boolean - Optional - Forces the use of IAM Instance Profile credentials, even when regular credentials are provided.
311 | * @return void 312 | */ 313 | public function __construct(array $options = array()) 314 | { 315 | // Instantiate the utilities class. 316 | $this->util = new $this->utilities_class(); 317 | 318 | // Determine the current service. 319 | $this->service = get_class($this); 320 | 321 | // Create credentials based on the options 322 | $runtime_credentials = new CFCredential($options); 323 | $credentials_provided = false; 324 | 325 | // Retrieve a credential set from config.inc.php if it exists 326 | if (isset($options['credentials'])) 327 | { 328 | // Use a specific credential set and merge with the runtime credentials 329 | $this->credentials = CFCredentials::get($options['credentials']) 330 | ->merge($runtime_credentials); 331 | } 332 | else 333 | { 334 | try 335 | { 336 | // Use the default credential set and merge with the runtime credentials 337 | $this->credentials = CFCredentials::get(CFCredentials::DEFAULT_KEY) 338 | ->merge($runtime_credentials); 339 | } 340 | catch (CFCredentials_Exception $e) 341 | { 342 | // Only the runtime credentials were provided 343 | $this->credentials = $runtime_credentials; 344 | } 345 | } 346 | 347 | // Check if keys were actually provided 348 | if (isset($this->credentials['key']) && isset($this->credentials['secret'])) 349 | { 350 | $credentials_provided = true; 351 | } 352 | 353 | // Check for an instance profile credentials override 354 | if (isset($this->credentials['use_instance_profile_credentials']) && $this->credentials['use_instance_profile_credentials']) 355 | { 356 | $credentials_provided = false; 357 | } 358 | 359 | // Automatically enable whichever caching mechanism is set to default. 360 | $this->set_cache_config($this->credentials->default_cache_config); 361 | 362 | // If no credentials were provided, try to get them from the EC2 instance profile 363 | if (!$credentials_provided) 364 | { 365 | // Default caching mechanism is required 366 | if (!$this->credentials->default_cache_config) 367 | { 368 | // @codeCoverageIgnoreStart 369 | throw new CFCredentials_Exception('No credentials were provided. The SDK attempts to retrieve Instance ' 370 | . 'Profile credentials from the EC2 Instance Metadata Service, but doing this requires the ' 371 | . '"default_cache_config" option to be set in the config.inc.php file or constructor. In order to ' 372 | . 'cache the retrieved credentials.'); 373 | // @codeCoverageIgnoreEnd 374 | } 375 | 376 | // Instantiate and invoke the cache for instance profile credentials 377 | $cache = new $this->cache_class('instance_profile_credentials', $this->cache_location, 0, $this->cache_compress); 378 | if ($data = $cache->read()) 379 | { 380 | $cache->expire_in((strtotime($data['expires']) - time()) * 0.85); 381 | } 382 | $instance_profile_credentials = $cache->response_manager(array($this, 'cache_instance_profile_credentials'), array($cache, $options)); 383 | 384 | $this->credentials->key = $instance_profile_credentials['key']; 385 | $this->credentials->secret = $instance_profile_credentials['secret']; 386 | $this->credentials->token = $instance_profile_credentials['token']; 387 | } 388 | 389 | // Set internal credentials after they are resolved 390 | $this->key = $this->credentials->key; 391 | $this->secret_key = $this->credentials->secret; 392 | $this->auth_token = $this->credentials->token; 393 | } 394 | 395 | /** 396 | * Alternate approach to constructing a new instance. Supports chaining. 397 | * 398 | * @param array $options (Optional) An associative array of parameters that can have the following keys:
    399 | *
  • certificate_authority - boolean - Optional - Determines which Cerificate Authority file to use. A value of boolean false will use the Certificate Authority file available on the system. A value of boolean true will use the Certificate Authority provided by the SDK. Passing a file system path to a Certificate Authority file (chmodded to 0755) will use that. Leave this set to false if you're not sure.
  • 400 | *
  • credentials - string - Optional - The name of the credential set to use for authentication.
  • 401 | *
  • default_cache_config - string - Optional - This option allows a preferred storage type to be configured for long-term caching. This can be changed later using the method. Valid values are: apc, xcache, or a file system path such as ./cache or /tmp/cache/.
  • 402 | *
  • key - string - Optional - Your AWS key, or a session key. If blank, the default credential set will be used.
  • 403 | *
  • secret - string - Optional - Your AWS secret key, or a session secret key. If blank, the default credential set will be used.
  • 404 | *
  • token - string - Optional - An AWS session token.
405 | * @return void 406 | */ 407 | public static function factory(array $options = array()) 408 | { 409 | if (version_compare(PHP_VERSION, '5.3.0', '<')) 410 | { 411 | throw new Exception('PHP 5.3 or newer is required to instantiate a new class with CLASS::factory().'); 412 | } 413 | 414 | $self = get_called_class(); 415 | return new $self($options); 416 | } 417 | 418 | 419 | /*%******************************************************************************************%*/ 420 | // MAGIC METHODS 421 | 422 | /** 423 | * A magic method that allows `camelCase` method names to be translated into `snake_case` names. 424 | * 425 | * @param string $name (Required) The name of the method. 426 | * @param array $arguments (Required) The arguments passed to the method. 427 | * @return mixed The results of the intended method. 428 | */ 429 | public function __call($name, $arguments) 430 | { 431 | // Convert camelCase method calls to snake_case. 432 | $method_name = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $name)); 433 | 434 | if (method_exists($this, $method_name)) 435 | { 436 | return call_user_func_array(array($this, $method_name), $arguments); 437 | } 438 | 439 | throw new CFRuntime_Exception('The method ' . $name . '() is undefined. Attempted to map to ' . $method_name . '() which is also undefined. Error occurred'); 440 | } 441 | 442 | 443 | /*%******************************************************************************************%*/ 444 | // SET CUSTOM SETTINGS 445 | 446 | /** 447 | * Set the proxy settings to use. 448 | * 449 | * @param string $proxy (Required) Accepts proxy credentials in the following format: `proxy://user:pass@hostname:port` 450 | * @return $this A reference to the current instance. 451 | */ 452 | public function set_proxy($proxy) 453 | { 454 | $this->proxy = $proxy; 455 | return $this; 456 | } 457 | 458 | /** 459 | * Set the hostname to connect to. This is useful for alternate services that are API-compatible with 460 | * AWS, but run from a different hostname. 461 | * 462 | * @param string $hostname (Required) The alternate hostname to use in place of the default one. Useful for mock or test applications living on different hostnames. 463 | * @param integer $port_number (Optional) The alternate port number to use in place of the default one. Useful for mock or test applications living on different port numbers. 464 | * @return $this A reference to the current instance. 465 | */ 466 | public function set_hostname($hostname, $port_number = null) 467 | { 468 | if ($this->override_hostname) 469 | { 470 | $this->hostname = $hostname; 471 | 472 | if ($port_number) 473 | { 474 | $this->port_number = $port_number; 475 | $this->hostname .= ':' . (string) $this->port_number; 476 | } 477 | } 478 | 479 | return $this; 480 | } 481 | 482 | /** 483 | * Set the resource prefix to use. This method is useful for alternate services that are API-compatible 484 | * with AWS. 485 | * 486 | * @param string $prefix (Required) An alternate prefix to prepend to the resource path. Useful for mock or test applications. 487 | * @return $this A reference to the current instance. 488 | */ 489 | public function set_resource_prefix($prefix) 490 | { 491 | $this->resource_prefix = $prefix; 492 | return $this; 493 | } 494 | 495 | /** 496 | * Disables any subsequent use of the method. 497 | * 498 | * @param boolean $override (Optional) Whether or not subsequent calls to should be obeyed. A `false` value disables the further effectiveness of . Defaults to `true`. 499 | * @return $this A reference to the current instance. 500 | */ 501 | public function allow_hostname_override($override = true) 502 | { 503 | $this->override_hostname = $override; 504 | return $this; 505 | } 506 | 507 | /** 508 | * Disables SSL/HTTPS connections for hosts that don't support them. Some services, however, still 509 | * require SSL support. 510 | * 511 | * This method will throw a user warning when invoked, which can be hidden by changing your 512 | * settings. 513 | * 514 | * @return $this A reference to the current instance. 515 | */ 516 | public function disable_ssl() 517 | { 518 | trigger_error('Disabling SSL connections is potentially unsafe and highly discouraged.', E_USER_WARNING); 519 | $this->use_ssl = false; 520 | return $this; 521 | } 522 | 523 | /** 524 | * Disables the verification of the SSL Certificate Authority. Doing so can enable an attacker to carry 525 | * out a man-in-the-middle attack. 526 | * 527 | * https://secure.wikimedia.org/wikipedia/en/wiki/Man-in-the-middle_attack 528 | * 529 | * This method will throw a user warning when invoked, which can be hidden by changing your 530 | * settings. 531 | * 532 | * @return $this A reference to the current instance. 533 | */ 534 | public function disable_ssl_verification($ssl_verification = false) 535 | { 536 | trigger_error('Disabling the verification of SSL certificates can lead to man-in-the-middle attacks. It is potentially unsafe and highly discouraged.', E_USER_WARNING); 537 | $this->ssl_verification = $ssl_verification; 538 | return $this; 539 | } 540 | 541 | /** 542 | * Enables HTTP request/response header logging to `STDERR`. 543 | * 544 | * @param boolean $enabled (Optional) Whether or not to enable debug mode. Defaults to `true`. 545 | * @return $this A reference to the current instance. 546 | */ 547 | public function enable_debug_mode($enabled = true) 548 | { 549 | $this->debug_mode = $enabled; 550 | return $this; 551 | } 552 | 553 | /** 554 | * Sets the maximum number of times to retry failed requests. 555 | * 556 | * @param integer $retries (Optional) The maximum number of times to retry failed requests. Defaults to `3`. 557 | * @return $this A reference to the current instance. 558 | */ 559 | public function set_max_retries($retries = 3) 560 | { 561 | $this->max_retries = $retries; 562 | return $this; 563 | } 564 | 565 | /** 566 | * Set the caching configuration to use for response caching. 567 | * 568 | * @param string $location (Required)

The location to store the cache object in. This may vary by cache method.

  • File - The local file system paths such as ./cache (relative) or /tmp/cache/ (absolute). The location must be server-writable.
  • APC - Pass in apc to use this lightweight cache. You must have the APC extension installed.
  • XCache - Pass in xcache to use this lightweight cache. You must have the XCache extension installed.
  • Memcached - Pass in an indexed array of associative arrays. Each associative array should have a host and a port value representing a Memcached server to connect to.
  • PDO - A URL-style string (e.g. pdo.mysql://user:pass@localhost/cache) or a standard DSN-style string (e.g. pdo.sqlite:/sqlite/cache.db). MUST be prefixed with pdo.. See CachePDO and PDO for more details.
569 | * @param boolean $gzip (Optional) Whether or not data should be gzipped before being stored. A value of `true` will compress the contents before caching them. A value of `false` will leave the contents uncompressed. Defaults to `true`. 570 | * @return $this A reference to the current instance. 571 | */ 572 | public function set_cache_config($location, $gzip = true) 573 | { 574 | // If location is empty, don't do anything. 575 | if (empty($location)) 576 | { 577 | return $this; 578 | } 579 | 580 | // If we have an array, we're probably passing in Memcached servers and ports. 581 | if (is_array($location)) 582 | { 583 | $this->cache_class = 'CacheMC'; 584 | } 585 | else 586 | { 587 | // I would expect locations like `/tmp/cache`, `pdo.mysql://user:pass@hostname:port`, `pdo.sqlite:memory:`, and `apc`. 588 | $type = strtolower(substr($location, 0, 3)); 589 | switch ($type) 590 | { 591 | case 'apc': 592 | $this->cache_class = 'CacheAPC'; 593 | break; 594 | 595 | case 'xca': // First three letters of `xcache` 596 | $this->cache_class = 'CacheXCache'; 597 | break; 598 | 599 | case 'pdo': 600 | $this->cache_class = 'CachePDO'; 601 | $location = substr($location, 4); 602 | break; 603 | 604 | default: 605 | $this->cache_class = 'CacheFile'; 606 | break; 607 | } 608 | } 609 | 610 | // Set the remaining cache information. 611 | $this->cache_location = $location; 612 | $this->cache_compress = $gzip; 613 | 614 | return $this; 615 | } 616 | 617 | /** 618 | * Register a callback function to execute whenever a data stream is read from using 619 | * . 620 | * 621 | * The user-defined callback function should accept three arguments: 622 | * 623 | *
    624 | *
  • $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
  • 625 | *
  • $file_handle - resource - Required - The file handle resource that represents the file on the local file system.
  • 626 | *
  • $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
  • 627 | *
628 | * 629 | * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
    630 | *
  • The name of a global function to execute, passed as a string.
  • 631 | *
  • A method to execute, passed as array('ClassName', 'MethodName').
  • 632 | *
  • An anonymous function (PHP 5.3+).
633 | * @return $this A reference to the current instance. 634 | */ 635 | public function register_streaming_read_callback($callback) 636 | { 637 | $this->registered_streaming_read_callback = $callback; 638 | return $this; 639 | } 640 | 641 | /** 642 | * Register a callback function to execute whenever a data stream is written to using 643 | * . 644 | * 645 | * The user-defined callback function should accept two arguments: 646 | * 647 | *
    648 | *
  • $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
  • 649 | *
  • $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
  • 650 | *
651 | * 652 | * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
    653 | *
  • The name of a global function to execute, passed as a string.
  • 654 | *
  • A method to execute, passed as array('ClassName', 'MethodName').
  • 655 | *
  • An anonymous function (PHP 5.3+).
656 | * @return $this A reference to the current instance. 657 | */ 658 | public function register_streaming_write_callback($callback) 659 | { 660 | $this->registered_streaming_write_callback = $callback; 661 | return $this; 662 | } 663 | 664 | /** 665 | * Fetches and caches STS credentials. This is meant to be used by the constructor, and is not to be 666 | * manually invoked. 667 | * 668 | * @param CacheCore $cache (Required) The a reference to the cache object that is being used to handle the caching. 669 | * @param array $options (Required) The options that were passed into the constructor. 670 | * @return mixed The data to be cached, or NULL. 671 | */ 672 | public function cache_sts_credentials($cache, $options) 673 | { 674 | $token = new AmazonSTS($options); 675 | $response = $token->get_session_token(); 676 | 677 | if ($response->isOK()) 678 | { 679 | // Update the expiration 680 | $expiration_time = strtotime((string) $response->body->GetSessionTokenResult->Credentials->Expiration); 681 | $expiration_duration = round(($expiration_time - time()) * 0.85); 682 | $cache->expire_in($expiration_duration); 683 | 684 | // Return the important data 685 | $credentials = $response->body->GetSessionTokenResult->Credentials; 686 | 687 | return array( 688 | 'key' => (string) $credentials->AccessKeyId, 689 | 'secret' => (string) $credentials->SecretAccessKey, 690 | 'token' => (string) $credentials->SessionToken, 691 | 'expires' => (string) $credentials->Expiration, 692 | ); 693 | } 694 | 695 | // @codeCoverageIgnoreStart 696 | throw new STS_Exception('Temporary credentials from the AWS Security ' 697 | . 'Token Service could not be retrieved using the provided long ' 698 | . 'term credentials. It\'s possible that the provided long term ' 699 | . 'credentials were invalid.'); 700 | // @codeCoverageIgnoreEnd 701 | } 702 | 703 | /** 704 | * Fetches and caches EC2 instance profile credentials. This is meant to be used by the constructor, and is not to 705 | * be manually invoked. 706 | * 707 | * @param CacheCore $cache (Required) The a reference to the cache object that is being used to handle the caching. 708 | * @param array $options (Required) The options that were passed into the constructor. 709 | * @return mixed The data to be cached, or NULL. 710 | */ 711 | public function cache_instance_profile_credentials($cache, $options) 712 | { 713 | $instance_profile_url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/'; 714 | $connect_timeout = isset($options['instance_profile_timeout']) ? $options['instance_profile_timeout'] : 2; 715 | 716 | try 717 | { 718 | // Make a call to the EC2 Metadata Service to find the available instance profile 719 | $request = new RequestCore($instance_profile_url); 720 | $request->set_curlopts(array(CURLOPT_CONNECTTIMEOUT => $connect_timeout)); 721 | $response = $request->send_request(true); 722 | 723 | if ($response->isOK()) 724 | { 725 | // Get the instance profile name 726 | $profile = (string) $response->body; 727 | 728 | // Make a call to the EC2 Metadata Service to get the instance profile credentials 729 | $request = new RequestCore($instance_profile_url . $profile); 730 | $request->set_curlopts(array(CURLOPT_CONNECTTIMEOUT => $connect_timeout)); 731 | $response = $request->send_request(true); 732 | 733 | if ($response->isOK()) 734 | { 735 | // Get the credentials 736 | $credentials = json_decode($response->body, true); 737 | 738 | if ($credentials['Code'] === 'Success') 739 | { 740 | // Determine the expiration time 741 | $expiration_time = strtotime((string) $credentials['Expiration']); 742 | $expiration_duration = round(($expiration_time - time()) * 0.85); 743 | $cache->expire_in($expiration_duration); 744 | 745 | // Return the credential information 746 | return array( 747 | 'key' => $credentials['AccessKeyId'], 748 | 'secret' => $credentials['SecretAccessKey'], 749 | 'token' => $credentials['Token'], 750 | 'expires' => $credentials['Expiration'], 751 | ); 752 | } 753 | } 754 | } 755 | } 756 | catch (cURL_Exception $e) 757 | { 758 | // The EC2 Metadata Service does not exist or had timed out. 759 | // An exception will be thrown on the next line. 760 | } 761 | 762 | // @codeCoverageIgnoreStart 763 | throw new CFCredentials_Exception('No credentials were provided. The SDK attempted to retrieve Instance ' 764 | . 'Profile credentials from the EC2 Instance Metadata Service, but failed to do so. Instance profile ' 765 | . 'credentials are only accessible on EC2 instances configured with a specific IAM role.'); 766 | // @codeCoverageIgnoreEnd 767 | } 768 | 769 | 770 | /*%******************************************************************************************%*/ 771 | // SET CUSTOM CLASSES 772 | 773 | /** 774 | * Set a custom class for this functionality. Use this method when extending/overriding existing classes 775 | * with new functionality. 776 | * 777 | * The replacement class must extend from . 778 | * 779 | * @param string $class (Optional) The name of the new class to use for this functionality. 780 | * @return $this A reference to the current instance. 781 | */ 782 | public function set_utilities_class($class = 'CFUtilities') 783 | { 784 | $this->utilities_class = $class; 785 | $this->util = new $this->utilities_class(); 786 | return $this; 787 | } 788 | 789 | /** 790 | * Set a custom class for this functionality. Use this method when extending/overriding existing classes 791 | * with new functionality. 792 | * 793 | * The replacement class must extend from . 794 | * 795 | * @param string $class (Optional) The name of the new class to use for this functionality. 796 | * @param $this A reference to the current instance. 797 | */ 798 | public function set_request_class($class = 'CFRequest') 799 | { 800 | $this->request_class = $class; 801 | return $this; 802 | } 803 | 804 | /** 805 | * Set a custom class for this functionality. Use this method when extending/overriding existing classes 806 | * with new functionality. 807 | * 808 | * The replacement class must extend from . 809 | * 810 | * @param string $class (Optional) The name of the new class to use for this functionality. 811 | * @return $this A reference to the current instance. 812 | */ 813 | public function set_response_class($class = 'CFResponse') 814 | { 815 | $this->response_class = $class; 816 | return $this; 817 | } 818 | 819 | /** 820 | * Set a custom class for this functionality. Use this method when extending/overriding existing classes 821 | * with new functionality. 822 | * 823 | * The replacement class must extend from . 824 | * 825 | * @param string $class (Optional) The name of the new class to use for this functionality. 826 | * @return $this A reference to the current instance. 827 | */ 828 | public function set_parser_class($class = 'CFSimpleXML') 829 | { 830 | $this->parser_class = $class; 831 | return $this; 832 | } 833 | 834 | /** 835 | * Set a custom class for this functionality. Use this method when extending/overriding existing classes 836 | * with new functionality. 837 | * 838 | * The replacement class must extend from . 839 | * 840 | * @param string $class (Optional) The name of the new class to use for this functionality. 841 | * @return $this A reference to the current instance. 842 | */ 843 | public function set_batch_class($class = 'CFBatchRequest') 844 | { 845 | $this->batch_class = $class; 846 | return $this; 847 | } 848 | 849 | 850 | /*%******************************************************************************************%*/ 851 | // AUTHENTICATION 852 | 853 | /** 854 | * Default, shared method for authenticating a connection to AWS. 855 | * 856 | * @param string $operation (Required) Indicates the operation to perform. 857 | * @param array $payload (Required) An associative array of parameters for authenticating. See the individual methods for allowed keys. 858 | * @return CFResponse Object containing a parsed HTTP response. 859 | */ 860 | public function authenticate($operation, $payload) 861 | { 862 | $original_payload = $payload; 863 | $method_arguments = func_get_args(); 864 | $curlopts = array(); 865 | $return_curl_handle = false; 866 | 867 | if (substr($operation, 0, strlen($this->operation_prefix)) !== $this->operation_prefix) 868 | { 869 | $operation = $this->operation_prefix . $operation; 870 | } 871 | 872 | // Extract the custom CURLOPT settings from the payload 873 | if (is_array($payload) && isset($payload['curlopts'])) 874 | { 875 | $curlopts = $payload['curlopts']; 876 | unset($payload['curlopts']); 877 | } 878 | 879 | // Determine whether the response or curl handle should be returned 880 | if (is_array($payload) && isset($payload['returnCurlHandle'])) 881 | { 882 | $return_curl_handle = isset($payload['returnCurlHandle']) ? $payload['returnCurlHandle'] : false; 883 | unset($payload['returnCurlHandle']); 884 | } 885 | 886 | // Use the caching flow to determine if we need to do a round-trip to the server. 887 | if ($this->use_cache_flow) 888 | { 889 | // Generate an identifier specific to this particular set of arguments. 890 | $cache_id = $this->key . '_' . get_class($this) . '_' . $operation . '_' . sha1(serialize($method_arguments)); 891 | 892 | // Instantiate the appropriate caching object. 893 | $this->cache_object = new $this->cache_class($cache_id, $this->cache_location, $this->cache_expires, $this->cache_compress); 894 | 895 | if ($this->delete_cache) 896 | { 897 | $this->use_cache_flow = false; 898 | $this->delete_cache = false; 899 | return $this->cache_object->delete(); 900 | } 901 | 902 | // Invoke the cache callback function to determine whether to pull data from the cache or make a fresh request. 903 | $data = $this->cache_object->response_manager(array($this, 'cache_callback'), $method_arguments); 904 | 905 | // Parse the XML body 906 | $data = $this->parse_callback($data); 907 | 908 | // End! 909 | return $data; 910 | } 911 | 912 | /*%******************************************************************************************%*/ 913 | 914 | // Signer 915 | $signer = new $this->auth_class($this->hostname, $operation, $payload, $this->credentials); 916 | $signer->key = $this->key; 917 | $signer->secret_key = $this->secret_key; 918 | $signer->auth_token = $this->auth_token; 919 | $signer->api_version = $this->api_version; 920 | $signer->utilities_class = $this->utilities_class; 921 | $signer->request_class = $this->request_class; 922 | $signer->response_class = $this->response_class; 923 | $signer->use_ssl = $this->use_ssl; 924 | $signer->proxy = $this->proxy; 925 | $signer->util = $this->util; 926 | $signer->registered_streaming_read_callback = $this->registered_streaming_read_callback; 927 | $signer->registered_streaming_write_callback = $this->registered_streaming_write_callback; 928 | $request = $signer->authenticate(); 929 | 930 | // Update RequestCore settings 931 | $request->request_class = $this->request_class; 932 | $request->response_class = $this->response_class; 933 | $request->ssl_verification = $this->ssl_verification; 934 | 935 | /*%******************************************************************************************%*/ 936 | 937 | // Debug mode 938 | if ($this->debug_mode) 939 | { 940 | $request->debug_mode = $this->debug_mode; 941 | } 942 | 943 | // Set custom CURLOPT settings 944 | if (count($curlopts)) 945 | { 946 | $request->set_curlopts($curlopts); 947 | } 948 | 949 | // Manage the (newer) batch request API or the (older) returnCurlHandle setting. 950 | if ($this->use_batch_flow) 951 | { 952 | $handle = $request->prep_request(); 953 | $this->batch_object->add($handle); 954 | $this->use_batch_flow = false; 955 | 956 | return $handle; 957 | } 958 | elseif ($return_curl_handle) 959 | { 960 | return $request->prep_request(); 961 | } 962 | 963 | // Send! 964 | $request->send_request(); 965 | 966 | // Prepare the response. 967 | $headers = $request->get_response_header(); 968 | $headers['x-aws-stringtosign'] = $signer->string_to_sign; 969 | 970 | if (isset($signer->canonical_request)) 971 | { 972 | $headers['x-aws-canonicalrequest'] = $signer->canonical_request; 973 | } 974 | 975 | $headers['x-aws-request-headers'] = $request->request_headers; 976 | $headers['x-aws-body'] = $signer->querystring; 977 | 978 | $data = new $this->response_class($headers, ($this->parse_the_response === true) ? $this->parse_callback($request->get_response_body()) : $request->get_response_body(), $request->get_response_code()); 979 | 980 | $response_body = (string) $request->get_response_body(); 981 | 982 | // Was it Amazon's fault the request failed? Retry the request until we reach $max_retries. 983 | if ( 984 | (integer) $request->get_response_code() === 500 || // Internal Error (presumably transient) 985 | (integer) $request->get_response_code() === 503) // Service Unavailable (presumably transient) 986 | { 987 | if ($this->redirects <= $this->max_retries) 988 | { 989 | // Exponential backoff 990 | $delay = (integer) (pow(4, $this->redirects) * 100000); 991 | usleep($delay); 992 | $this->redirects++; 993 | $data = $this->authenticate($operation, $original_payload); 994 | } 995 | } 996 | 997 | // DynamoDB has additional, custom logic for retrying requests 998 | else 999 | { 1000 | // If the request to DynamoDB was throttled, we need to retry 1001 | $need_to_retry_dynamodb_request = ( 1002 | (integer) $request->get_response_code() === 400 && 1003 | stripos($response_body, 'com.amazonaws.dynamodb.') !== false && 1004 | stripos($response_body, 'ProvisionedThroughputExceededException') !== false 1005 | ); 1006 | 1007 | // If the CRC32 of the response does not match the expected value, we need to retry 1008 | $response_headers = $request->get_response_header(); 1009 | if (!$need_to_retry_dynamodb_request && isset($response_headers['x-amz-crc32'])) 1010 | { 1011 | $crc32_expected = $response_headers['x-amz-crc32']; 1012 | $crc32_actual = hexdec(hash('crc32b', $response_body)); 1013 | $need_to_retry_dynamodb_request = ($crc32_expected != $crc32_actual); 1014 | } 1015 | 1016 | // Perform retry if necessary using a more aggressive exponential backoff 1017 | if ($need_to_retry_dynamodb_request) 1018 | { 1019 | if ($this->redirects === 0) 1020 | { 1021 | $this->redirects++; 1022 | $data = $this->authenticate($operation, $original_payload); 1023 | } 1024 | elseif ($this->redirects <= max($this->max_retries, 10)) 1025 | { 1026 | // Exponential backoff 1027 | $delay = (integer) (pow(2, ($this->redirects - 1)) * 50000); 1028 | usleep($delay); 1029 | $this->redirects++; 1030 | $data = $this->authenticate($operation, $original_payload); 1031 | } 1032 | } 1033 | } 1034 | 1035 | $this->redirects = 0; 1036 | return $data; 1037 | } 1038 | 1039 | 1040 | /*%******************************************************************************************%*/ 1041 | // BATCH REQUEST LAYER 1042 | 1043 | /** 1044 | * Specifies that the intended request should be queued for a later batch request. 1045 | * 1046 | * @param CFBatchRequest $queue (Optional) The instance to use for managing batch requests. If not available, it generates a new instance of . 1047 | * @return $this A reference to the current instance. 1048 | */ 1049 | public function batch(CFBatchRequest &$queue = null) 1050 | { 1051 | if ($queue) 1052 | { 1053 | $this->batch_object = $queue; 1054 | } 1055 | elseif ($this->internal_batch_object) 1056 | { 1057 | $this->batch_object = &$this->internal_batch_object; 1058 | } 1059 | else 1060 | { 1061 | $this->internal_batch_object = new $this->batch_class(); 1062 | $this->batch_object = &$this->internal_batch_object; 1063 | } 1064 | 1065 | $this->use_batch_flow = true; 1066 | 1067 | return $this; 1068 | } 1069 | 1070 | /** 1071 | * Executes the batch request queue by sending all queued requests. 1072 | * 1073 | * @param boolean $clear_after_send (Optional) Whether or not to clear the batch queue after sending a request. Defaults to `true`. Set this to `false` if you are caching batch responses and want to retrieve results later. 1074 | * @return array An array of objects. 1075 | */ 1076 | public function send($clear_after_send = true) 1077 | { 1078 | if ($this->use_batch_flow) 1079 | { 1080 | // When we send the request, disable batch flow. 1081 | $this->use_batch_flow = false; 1082 | 1083 | // If we're not caching, simply send the request. 1084 | if (!$this->use_cache_flow) 1085 | { 1086 | $response = $this->batch_object->send(); 1087 | $parsed_data = array_map(array($this, 'parse_callback'), $response); 1088 | $parsed_data = new CFArray($parsed_data); 1089 | 1090 | // Clear the queue 1091 | if ($clear_after_send) 1092 | { 1093 | $this->batch_object->queue = array(); 1094 | } 1095 | 1096 | return $parsed_data; 1097 | } 1098 | 1099 | // Generate an identifier specific to this particular set of arguments. 1100 | $cache_id = $this->key . '_' . get_class($this) . '_' . sha1(serialize($this->batch_object)); 1101 | 1102 | // Instantiate the appropriate caching object. 1103 | $this->cache_object = new $this->cache_class($cache_id, $this->cache_location, $this->cache_expires, $this->cache_compress); 1104 | 1105 | if ($this->delete_cache) 1106 | { 1107 | $this->use_cache_flow = false; 1108 | $this->delete_cache = false; 1109 | return $this->cache_object->delete(); 1110 | } 1111 | 1112 | // Invoke the cache callback function to determine whether to pull data from the cache or make a fresh request. 1113 | $data_set = $this->cache_object->response_manager(array($this, 'cache_callback_batch'), array($this->batch_object)); 1114 | $parsed_data = array_map(array($this, 'parse_callback'), $data_set); 1115 | $parsed_data = new CFArray($parsed_data); 1116 | 1117 | // Clear the queue 1118 | if ($clear_after_send) 1119 | { 1120 | $this->batch_object->queue = array(); 1121 | } 1122 | 1123 | // End! 1124 | return $parsed_data; 1125 | } 1126 | 1127 | // Load the class 1128 | $null = new CFBatchRequest(); 1129 | unset($null); 1130 | 1131 | throw new CFBatchRequest_Exception('You must use $object->batch()->send()'); 1132 | } 1133 | 1134 | /** 1135 | * Parses a response body into a PHP object if appropriate. 1136 | * 1137 | * @param CFResponse|string $response (Required) The object to parse, or an XML string that would otherwise be a response body. 1138 | * @param string $content_type (Optional) The content-type to use when determining how to parse the content. 1139 | * @return CFResponse|string A parsed object, or parsed XML. 1140 | */ 1141 | public function parse_callback($response, $headers = null) 1142 | { 1143 | // Bail out 1144 | if (!$this->parse_the_response) return $response; 1145 | 1146 | // Shorten this so we have a (mostly) single code path 1147 | if (isset($response->body)) 1148 | { 1149 | if (is_string($response->body)) 1150 | { 1151 | $body = $response->body; 1152 | } 1153 | else 1154 | { 1155 | return $response; 1156 | } 1157 | } 1158 | elseif (is_string($response)) 1159 | { 1160 | $body = $response; 1161 | } 1162 | else 1163 | { 1164 | return $response; 1165 | } 1166 | 1167 | // Decompress gzipped content 1168 | if (isset($headers['content-encoding'])) 1169 | { 1170 | switch (strtolower(trim($headers['content-encoding'], "\x09\x0A\x0D\x20"))) 1171 | { 1172 | case 'gzip': 1173 | case 'x-gzip': 1174 | $decoder = new CFGzipDecode($body); 1175 | if ($decoder->parse()) 1176 | { 1177 | $body = $decoder->data; 1178 | } 1179 | break; 1180 | 1181 | case 'deflate': 1182 | if (($uncompressed = gzuncompress($body)) !== false) 1183 | { 1184 | $body = $uncompressed; 1185 | } 1186 | elseif (($uncompressed = gzinflate($body)) !== false) 1187 | { 1188 | $body = $uncompressed; 1189 | } 1190 | break; 1191 | } 1192 | } 1193 | 1194 | // Look for XML cues 1195 | if ( 1196 | (isset($headers['content-type']) && ($headers['content-type'] === 'text/xml' || $headers['content-type'] === 'application/xml')) || // We know it's XML 1197 | (!isset($headers['content-type']) && (stripos($body, '') === 0) || preg_match('/^<(\w*) xmlns="http(s?):\/\/(\w*).amazon(aws)?.com/im', $body)) // Sniff for XML 1198 | ) 1199 | { 1200 | // Strip the default XML namespace to simplify XPath expressions 1201 | $body = str_replace("xmlns=", "ns=", $body); 1202 | 1203 | try { 1204 | // Parse the XML body 1205 | $body = new $this->parser_class($body); 1206 | } 1207 | catch (Exception $e) 1208 | { 1209 | throw new Parser_Exception($e->getMessage()); 1210 | } 1211 | } 1212 | // Look for JSON cues 1213 | elseif ( 1214 | (isset($headers['content-type']) && ($headers['content-type'] === 'application/json') || $headers['content-type'] === 'application/x-amz-json-1.0') || // We know it's JSON 1215 | (!isset($headers['content-type']) && $this->util->is_json($body)) // Sniff for JSON 1216 | ) 1217 | { 1218 | // Normalize JSON to a CFSimpleXML object 1219 | $body = CFJSON::to_xml($body, $this->parser_class); 1220 | } 1221 | 1222 | // Put the parsed data back where it goes 1223 | if (isset($response->body)) 1224 | { 1225 | $response->body = $body; 1226 | } 1227 | else 1228 | { 1229 | $response = $body; 1230 | } 1231 | 1232 | return $response; 1233 | } 1234 | 1235 | 1236 | /*%******************************************************************************************%*/ 1237 | // CACHING LAYER 1238 | 1239 | /** 1240 | * Specifies that the resulting object should be cached according to the settings from 1241 | * . 1242 | * 1243 | * @param string|integer $expires (Required) The time the cache is to expire. Accepts a number of seconds as an integer, or an amount of time, as a string, that is understood by (e.g. "1 hour"). 1244 | * @return $this A reference to the current instance. 1245 | */ 1246 | public function cache($expires) 1247 | { 1248 | // Die if they haven't used set_cache_config(). 1249 | if (!$this->cache_class) 1250 | { 1251 | throw new CFRuntime_Exception('Must call set_cache_config() before using cache()'); 1252 | } 1253 | 1254 | if (is_string($expires)) 1255 | { 1256 | $expires = strtotime($expires); 1257 | $this->cache_expires = $expires - time(); 1258 | } 1259 | elseif (is_int($expires)) 1260 | { 1261 | $this->cache_expires = $expires; 1262 | } 1263 | 1264 | $this->use_cache_flow = true; 1265 | 1266 | return $this; 1267 | } 1268 | 1269 | /** 1270 | * The callback function that is executed when the cache doesn't exist or has expired. The response of 1271 | * this method is cached. Accepts identical parameters as the method. Never call this 1272 | * method directly -- it is used internally by the caching system. 1273 | * 1274 | * @param string $operation (Required) Indicates the operation to perform. 1275 | * @param array $payload (Required) An associative array of parameters for authenticating. See the individual methods for allowed keys. 1276 | * @return CFResponse A parsed HTTP response. 1277 | */ 1278 | public function cache_callback($operation, $payload) 1279 | { 1280 | // Disable the cache flow since it's already been handled. 1281 | $this->use_cache_flow = false; 1282 | 1283 | // Make the request 1284 | $response = $this->authenticate($operation, $payload); 1285 | 1286 | // If this is an XML document, convert it back to a string. 1287 | if (isset($response->body) && ($response->body instanceof SimpleXMLElement)) 1288 | { 1289 | $response->body = $response->body->asXML(); 1290 | } 1291 | 1292 | return $response; 1293 | } 1294 | 1295 | /** 1296 | * Used for caching the results of a batch request. Never call this method directly; it is used 1297 | * internally by the caching system. 1298 | * 1299 | * @param CFBatchRequest $batch (Required) The batch request object to send. 1300 | * @return CFResponse A parsed HTTP response. 1301 | */ 1302 | public function cache_callback_batch(CFBatchRequest $batch) 1303 | { 1304 | return $batch->send(); 1305 | } 1306 | 1307 | /** 1308 | * Deletes a cached object using the specified cache storage type. 1309 | * 1310 | * @return boolean A value of `true` if cached object exists and is successfully deleted, otherwise `false`. 1311 | */ 1312 | public function delete_cache() 1313 | { 1314 | $this->use_cache_flow = true; 1315 | $this->delete_cache = true; 1316 | 1317 | return $this; 1318 | } 1319 | } 1320 | 1321 | 1322 | /** 1323 | * Contains the functionality for auto-loading service classes. 1324 | */ 1325 | class CFLoader 1326 | { 1327 | /*%******************************************************************************************%*/ 1328 | // AUTO-LOADER 1329 | 1330 | /** 1331 | * Automatically load classes that aren't included. 1332 | * 1333 | * @param string $class (Required) The classname to load. 1334 | * @return boolean Whether or not the file was successfully loaded. 1335 | */ 1336 | public static function autoloader($class) 1337 | { 1338 | $path = dirname(__FILE__) . DIRECTORY_SEPARATOR; 1339 | 1340 | // Amazon SDK classes 1341 | if (strstr($class, 'Amazon')) 1342 | { 1343 | if (file_exists($require_this = $path . 'services' . DIRECTORY_SEPARATOR . str_ireplace('Amazon', '', strtolower($class)) . '.class.php')) 1344 | { 1345 | require_once $require_this; 1346 | return true; 1347 | } 1348 | 1349 | return false; 1350 | } 1351 | 1352 | // Utility classes 1353 | elseif (strstr($class, 'CF')) 1354 | { 1355 | if (file_exists($require_this = $path . 'utilities' . DIRECTORY_SEPARATOR . str_ireplace('CF', '', strtolower($class)) . '.class.php')) 1356 | { 1357 | require_once $require_this; 1358 | return true; 1359 | } 1360 | 1361 | return false; 1362 | } 1363 | 1364 | // Load CacheCore 1365 | elseif (strstr($class, 'Cache')) 1366 | { 1367 | if (file_exists($require_this = $path . 'lib' . DIRECTORY_SEPARATOR . 'cachecore' . DIRECTORY_SEPARATOR . strtolower($class) . '.class.php')) 1368 | { 1369 | require_once $require_this; 1370 | return true; 1371 | } 1372 | 1373 | return false; 1374 | } 1375 | 1376 | // Load RequestCore 1377 | elseif (strstr($class, 'RequestCore') || strstr($class, 'ResponseCore')) 1378 | { 1379 | if (file_exists($require_this = $path . 'lib' . DIRECTORY_SEPARATOR . 'requestcore' . DIRECTORY_SEPARATOR . 'requestcore.class.php')) 1380 | { 1381 | require_once $require_this; 1382 | return true; 1383 | } 1384 | 1385 | return false; 1386 | } 1387 | 1388 | // Load Transmogrifier 1389 | elseif (strstr($class, 'Transmogrifier')) 1390 | { 1391 | if (file_exists($require_this = $path . 'lib' . DIRECTORY_SEPARATOR . 'dom' . DIRECTORY_SEPARATOR . 'Transmogrifier.php')) 1392 | { 1393 | require_once $require_this; 1394 | return true; 1395 | } 1396 | 1397 | return false; 1398 | } 1399 | 1400 | // Load Authentication Signers 1401 | elseif (strstr($class, 'Auth')) 1402 | { 1403 | if (file_exists($require_this = $path . 'authentication' . DIRECTORY_SEPARATOR . str_replace('auth', 'signature_', strtolower($class)) . '.class.php')) 1404 | { 1405 | require_once $require_this; 1406 | return true; 1407 | } 1408 | 1409 | return false; 1410 | } 1411 | 1412 | // Load Signer interface 1413 | elseif ($class === 'Signer') 1414 | { 1415 | if (!interface_exists('Signable', false) && 1416 | file_exists($require_this = $path . 'authentication' . DIRECTORY_SEPARATOR . 'signable.interface.php')) 1417 | { 1418 | require_once $require_this; 1419 | } 1420 | 1421 | if (file_exists($require_this = $path . 'authentication' . DIRECTORY_SEPARATOR . 'signer.abstract.php')) 1422 | { 1423 | require_once $require_this; 1424 | return true; 1425 | } 1426 | 1427 | return false; 1428 | } 1429 | 1430 | // Load Symfony YAML classes 1431 | elseif (strstr($class, 'sfYaml')) 1432 | { 1433 | if (file_exists($require_this = $path . 'lib' . DIRECTORY_SEPARATOR . 'yaml' . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'sfYaml.php')) 1434 | { 1435 | require_once $require_this; 1436 | return true; 1437 | } 1438 | 1439 | return false; 1440 | } 1441 | 1442 | return false; 1443 | } 1444 | } 1445 | 1446 | // Register the autoloader. 1447 | spl_autoload_register(array('CFLoader', 'autoloader')); 1448 | 1449 | 1450 | /*%******************************************************************************************%*/ 1451 | // CONFIGURATION 1452 | 1453 | // If config auto-discovery is explicitly disabled, stop here 1454 | if (defined('AWS_DISABLE_CONFIG_AUTO_DISCOVERY')) return; 1455 | 1456 | // Look for include file in the same directory (e.g. `./config.inc.php`). 1457 | if (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'config.inc.php')) 1458 | { 1459 | include_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'config.inc.php'; 1460 | } 1461 | // Fallback to `~/.aws/sdk/config.inc.php` 1462 | else 1463 | { 1464 | if (!isset($_ENV['HOME']) && isset($_SERVER['HOME'])) 1465 | { 1466 | $_ENV['HOME'] = $_SERVER['HOME']; 1467 | } 1468 | elseif (!isset($_ENV['HOME']) && !isset($_SERVER['HOME'])) 1469 | { 1470 | $os = strtolower(PHP_OS); 1471 | if (in_array($os, array('windows', 'winnt', 'win32'))) 1472 | { 1473 | $_ENV['HOME'] = false; 1474 | } 1475 | else 1476 | { 1477 | $dir = exec('(cd ~ && pwd) 2>&1', $out, $exit); 1478 | if ($exit === 0) 1479 | { 1480 | $_ENV['HOME'] = trim($dir); 1481 | } 1482 | else 1483 | { 1484 | error_log('Failed to determine HOME directory after trying "' . $dir . '" (exit code ' . $exit . ')'); 1485 | $_ENV['HOME'] = false; 1486 | } 1487 | } 1488 | 1489 | if (!$_ENV['HOME']) 1490 | { 1491 | switch ($os) 1492 | { 1493 | case 'darwin': 1494 | $_ENV['HOME'] = '/Users/' . get_current_user(); 1495 | break; 1496 | 1497 | case 'windows': 1498 | case 'winnt': 1499 | case 'win32': 1500 | $_ENV['HOME'] = 'c:' . DIRECTORY_SEPARATOR . 'Documents and Settings' . DIRECTORY_SEPARATOR . get_current_user(); 1501 | break; 1502 | 1503 | default: 1504 | $_ENV['HOME'] = '/home/' . get_current_user(); 1505 | break; 1506 | } 1507 | } 1508 | } 1509 | 1510 | $path = DIRECTORY_SEPARATOR . '.aws' . DIRECTORY_SEPARATOR . 'sdk' . DIRECTORY_SEPARATOR . 'config.inc.php'; 1511 | if (isset($_ENV['HOME']) && file_exists($_ENV['HOME'] . $path)) 1512 | { 1513 | include_once $_ENV['HOME'] . $path; 1514 | } 1515 | 1516 | unset($os, $dir, $out, $exit, $path); 1517 | } 1518 | --------------------------------------------------------------------------------
SNBucket NameSource URLIPPOCVULNERABLE
". $row['ID'] . "". $row['BUCKETNAME'] . "". $row['URL'] ."". $row['IP'] ."". $row['POC'] ."".$row['VULNERABLE'] ."