/** * Constructor, used if you're not calling the class statically * * @param string $accessKey Access key * @param string $secretKey Secret key * @param boolean $useSSL Whether or not to use SSL * @return void */ public function __construct($accessKey = null, $secretKey = null, $useSSL = true) { if ($accessKey !== null && $secretKey !== null) { self::setAuth($accessKey, $secretKey); } self::$useSSL = $useSSL; }
static function get_s3() { if (!self::$_s3) { require_once MODPATH . "aws_s3/lib/s3.php"; S3::setAuth(module::get_var("aws_s3", "access_key"), module::get_var("aws_s3", "secret_key")); S3::$useSSL = module::get_var("aws_s3", "use_ssl", false); } return self::$_s3; }
/** * List your invalidation batches for invalidateDistribution() in a CloudFront distribution * * http://docs.amazonwebservices.com/AmazonCloudFront/latest/APIReference/ListInvalidation.html * returned array looks like this: * Array * ( * [I31TWB0CN9V6XD] => InProgress * [IT3TFE31M0IHZ] => Completed * [I12HK7MPO1UQDA] => Completed * [I1IA7R6JKTC3L2] => Completed * ) * * @param string $distributionId Distribution ID from listDistributions() * @return array */ public static function getDistributionInvalidationList($distributionId) { if (!extension_loaded('openssl')) { self::__triggerError(sprintf("S3::getDistributionInvalidationList(): [%s] %s", "CloudFront functionality requires SSL"), __FILE__, __LINE__); return false; } $useSSL = self::$useSSL; self::$useSSL = true; // CloudFront requires SSL $rest = new S3Request('GET', '', '2010-11-01/distribution/' . $distributionId . '/invalidation', 'cloudfront.amazonaws.com'); $rest = self::__getCloudFrontResponse($rest); self::$useSSL = $useSSL; if ($rest->error === false && $rest->code !== 200) { $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); } if ($rest->error !== false) { trigger_error(sprintf("S3::getDistributionInvalidationList('{$distributionId}'): [%s]", $rest->error['code'], $rest->error['message']), E_USER_WARNING); return false; } elseif ($rest->body instanceof SimpleXMLElement && isset($rest->body->InvalidationSummary)) { $list = array(); foreach ($rest->body->InvalidationSummary as $summary) { $list[(string) $summary->Id] = (string) $summary->Status; } return $list; } return array(); }
/** * Get a list of CloudFront distributions * * @return array */ public static function listDistributions() { self::$useSSL = true; // CloudFront requires SSL $rest = new S3Request('GET', '', '2008-06-30/distribution', 'cloudfront.amazonaws.com'); $rest = self::__getCloudFrontResponse($rest); if ($rest->error === false && $rest->code !== 200) { $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); } if ($rest->error !== false) { trigger_error(sprintf("S3::listDistributions(): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING); return false; } elseif ($rest->body instanceof SimpleXMLElement && isset($rest->body->DistributionSummary)) { $list = array(); if (isset($rest->body->Marker, $rest->body->MaxItems, $rest->body->IsTruncated)) { //$info['marker'] = (string)$rest->body->Marker; //$info['maxItems'] = (int)$rest->body->MaxItems; //$info['isTruncated'] = (string)$rest->body->IsTruncated == 'true' ? true : false; } foreach ($rest->body->DistributionSummary as $summary) { $list[(string) $summary->Id] = self::__parseCloudFrontDistributionConfig($summary); } return $list; } return array(); }
/** * Invalidate objects in a CloudFront distribution * * Thanks to Martin Lindkvist for S3::invalidateDistribution() * * @param string $distributionId Distribution ID from listDistributions() * @param array $paths Array of object paths to invalidate * @return boolean */ public static function invalidateDistribution($distributionId, $paths) { if (!extension_loaded('openssl')) { self::__triggerError(sprintf("S3::invalidateDistribution(): [%s] %s", "CloudFront functionality requires SSL"), __FILE__, __LINE__); return false; } $useSSL = self::$useSSL; self::$useSSL = true; // CloudFront requires SSL $rest = new S3Request('POST', '', '2010-08-01/distribution/' . $distributionId . '/invalidation', 'cloudfront.amazonaws.com'); $rest->data = self::__getCloudFrontInvalidationBatchXML($paths, (string) microtime(true)); $rest->size = strlen($rest->data); $rest = self::__getCloudFrontResponse($rest); self::$useSSL = $useSSL; if ($rest->error === false && $rest->code !== 201) { $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); } if ($rest->error !== false) { trigger_error(sprintf("S3::invalidate('{$distributionId}',{$paths}): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING); return false; } return true; }
/** * Get the S3 response * * @return object | false */ public function getResponse() { $query = ''; S3::$useSSL = false; if (sizeof($this->parameters) > 0) { $query = substr($this->uri, -1) !== '?' ? '?' : '&'; foreach ($this->parameters as $var => $value) { if ($value == null || $value == '') { $query .= $var . '&'; } else { $query .= $var . '=' . rawurlencode($value) . '&'; } } $query = substr($query, 0, -1); $this->uri .= $query; if (array_key_exists('acl', $this->parameters) || array_key_exists('location', $this->parameters) || array_key_exists('torrent', $this->parameters) || array_key_exists('logging', $this->parameters)) { $this->resource .= $query; } } $url = (S3::$useSSL && extension_loaded('openssl') ? 'https://' : 'http://') . $this->headers['Host'] . $this->uri; //var_dump($this->bucket, $this->uri, $this->resource, $url); // Basic setup $curl = curl_init(); curl_setopt($curl, CURLOPT_USERAGENT, 'S3/php'); if (S3::$useSSL) { curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1); } curl_setopt($curl, CURLOPT_URL, $url); // Headers $headers = array(); $amz = array(); foreach ($this->amzHeaders as $header => $value) { if (strlen($value) > 0) { $headers[] = $header . ': ' . $value; } } foreach ($this->headers as $header => $value) { if (strlen($value) > 0) { $headers[] = $header . ': ' . $value; } } // Collect AMZ headers for signature foreach ($this->amzHeaders as $header => $value) { if (strlen($value) > 0) { $amz[] = strtolower($header) . ':' . $value; } } // AMZ headers must be sorted if (sizeof($amz) > 0) { sort($amz); $amz = "\n" . implode("\n", $amz); } else { $amz = ''; } // Authorization string (CloudFront stringToSign should only contain a date) $headers[] = 'Authorization: ' . S3::__getSignature($this->headers['Host'] == 'cloudfront.amazonaws.com' ? $this->headers['Date'] : $this->verb . "\n" . $this->headers['Content-MD5'] . "\n" . $this->headers['Content-Type'] . "\n" . $this->headers['Date'] . $amz . "\n" . $this->resource); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); curl_setopt($curl, CURLOPT_HEADER, false); curl_setopt($curl, CURLOPT_RETURNTRANSFER, false); curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback')); curl_setopt($curl, CURLOPT_HEADERFUNCTION, array(&$this, '__responseHeaderCallback')); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // Request types switch ($this->verb) { case 'GET': break; case 'PUT': case 'POST': // POST only used for CloudFront if ($this->fp !== false) { curl_setopt($curl, CURLOPT_PUT, true); curl_setopt($curl, CURLOPT_INFILE, $this->fp); if ($this->size >= 0) { curl_setopt($curl, CURLOPT_INFILESIZE, $this->size); } } elseif ($this->data !== false) { curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb); curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data); if ($this->size >= 0) { curl_setopt($curl, CURLOPT_BUFFERSIZE, $this->size); } } else { curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb); } break; case 'HEAD': curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD'); curl_setopt($curl, CURLOPT_NOBODY, true); break; case 'DELETE': curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE'); break; default: break; } // Execute, grab errors if (curl_exec($curl)) { $this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE); } else { $this->response->error = array('code' => curl_errno($curl), 'message' => curl_error($curl), 'resource' => $this->resource); } @curl_close($curl); // Parse body into XML if ($this->response->error === false && isset($this->response->headers['type']) && $this->response->headers['type'] == 'application/xml' && isset($this->response->body)) { $this->response->body = simplexml_load_string($this->response->body); // Grab S3 errors if (!in_array($this->response->code, array(200, 204)) && isset($this->response->body->Code, $this->response->body->Message)) { $this->response->error = array('code' => (string) $this->response->body->Code, 'message' => (string) $this->response->body->Message); if (isset($this->response->body->Resource)) { $this->response->error['resource'] = (string) $this->response->body->Resource; } unset($this->response->body); } } // Clean up file resources if ($this->fp !== false && is_resource($this->fp)) { fclose($this->fp); } return $this->response; }
/** * Invalidates files in a CloudFront distribution * * @return array */ public static function getInvalidationList($distributionId) { self::$useSSL = true; // CloudFront requires SSL $rest = new S3Request('GET', '', '2010-08-01/distribution/' . $distributionId . '/invalidation', 'cloudfront.amazonaws.com'); $rest = self::__getCloudFrontResponse($rest); if ($rest->error === false && $rest->code !== 200) { $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); } if ($rest->error !== false) { trigger_error(sprintf("S3::getInvalidationList(): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING); return false; } return $rest; }
function test_s3($accesskey, $secretkey, $bucket, $directory = '', $ssl) { if (empty($accesskey) || empty($secretkey) || empty($bucket)) { return 'Missing one or more required fields.'; } require_once dirname(__FILE__) . '/lib/s3/s3.php'; $s3 = new S3($accesskey, $secretkey); if ($ssl != '1') { S3::$useSSL = false; } if ($s3->getBucketLocation($bucket) === false) { // Easy way to see if bucket already exists. $s3->putBucket($bucket, S3::ACL_PUBLIC_READ); } if (!empty($directory)) { $directory = $directory . '/'; } if ($s3->putObject('Upload test for BackupBuddy for Amazon S3', $bucket, $directory . 'backupbuddy.txt', S3::ACL_PRIVATE)) { // Success... just delete temp test file later... } else { return 'Unable to upload. Verify your keys, bucket name, and account permissions.'; } if (!S3::deleteObject($bucket, $directory . '/backupbuddy.txt')) { return 'Partial success. Could not delete temp file.'; } return true; // Success! }
/** * Creates invalidation bath * * @static * @param integer $distributionId * @param array $paths * @return array|bool */ public static function createInvalidation($distributionId, $paths) { self::$useSSL = true; // CloudFront requires SSL $rest = new S3Request('POST', '', '2010-11-01/distribution/' . $distributionId . '/invalidation', 'cloudfront.amazonaws.com'); $rest->data = self::__getCloudFrontInvalidationBath($paths); $rest->size = strlen($rest->data); $rest->setHeader('Content-Type', 'application/xml'); $rest = self::__getCloudFrontResponse($rest); if ($rest->error === false && $rest->code !== 201) { $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status'); } if ($rest->error !== false) { trigger_error(sprintf("S3::createInvalidation(%d, '%s'): [%s] %s", $distributionId, implode(', ', $paths), $rest->error['code'], $rest->error['message']), E_USER_WARNING); return false; } elseif ($rest->body instanceof SimpleXMLElement) { return self::__parseCloudFrontInvalidation($rest->body); } return false; }
function cron_aws($aws_accesskey, $aws_secretkey, $aws_bucket, $aws_directory, $file, $delete_after_int = 0) { $details = ''; $details .= "AWS Access Key: " . $aws_accesskey . "\n"; if ($this->_debug) { $details .= "AWS Secret Key: " . $aws_secretkey . "\n"; } else { $details .= "AWS Secret Key: *hidden*\n"; } $details .= "AWS Bucket: " . $aws_bucket . "\n"; $details .= "AWS Directory: " . $aws_directory . "\n"; $details .= "Local File & Path: " . $this->_options['backup_directory'] . '/' . basename($file) . "\n"; $details .= "Filename: " . basename($file) . "\n"; $this->log('Starting Amazon S3 cron. Details: ' . $details); require_once dirname(__FILE__) . '/lib/s3/s3.php'; $s3 = new S3($aws_accesskey, $aws_secretkey); if ($this->_options['aws_ssl'] != '1') { S3::$useSSL = false; } $this->log('About to put bucket to Amazon S3 cron.'); $s3->putBucket($aws_bucket, S3::ACL_PUBLIC_READ); $this->log('About to put object (the file) to Amazon S3 cron.'); if ($s3->putObject(S3::inputFile($file), $aws_bucket, $aws_directory . '/' . basename($file), S3::ACL_PRIVATE)) { // success $this->log('SUCCESS sending to Amazon S3!'); } else { $this->mail_notice('ERROR #9002! Failed sending file to Amazon S3. Details:' . "\n\n" . $details); $this->log('FAILURE sending to Amazon S3! Details: ' . $details, 'error'); } if ($delete_after_int == 1) { $this->log('Deleting backup file after Amazon S3 cron.'); unlink($file); $this->log('Done deleting backup file after Amazon S3 cron.'); } }
function test_s3($accesskey, $secretkey, $bucket, $directory = '', $ssl) { if (empty($accesskey) || empty($secretkey) || empty($bucket)) { return __('Missing one or more required fields.', 'it-l10n-backupbuddy'); } $bucket_requirements = __("Your bucket name must meet certain criteria. It must fulfill the following: \n\n Characters may be lowercase letters, numbers, periods (.), and dashes (-). \n Must start with a number or letter. \n Must be between 3 and 63 characters long. \n Must not be formatted as an IP address (e.g., 192.168.5.4). \n Should not contain underscores (_). \n Should be between 3 and 63 characters long. \n Should not end with a dash. \n Cannot contain two, adjacent periods. \n Cannot contain dashes next to periods.", 'it-l10n-backupbuddy'); if (preg_match("/^[a-z0-9][a-z0-9\\-\\.]*(?<!-)\$/i", $bucket) == 0) { // Starts with a-z or 0-9; middle is a-z, 0-9, -, or .; cannot end in a dash. return __('Your bucket contains a period next to a dash.', 'it-l10n-backupbuddy') . ' ' . $bucket_requirements; } if (strlen($bucket) < 3 || strlen($bucket) > 63) { // Must be between 3 and 63 characters long return __('Your bucket must be between 3 and 63 characters long.', 'it-l10n-backupbuddy') . ' ' . $bucket_requirements; } if (strstr($bucket, '.-') !== false || strstr($bucket, '-.') !== false || strstr($bucket, '..') !== false) { // Bucket names cannot contain dashes next to periods (e.g., "my-.bucket.com" and "my.-bucket" are invalid) return __('Your bucket contains a period next to a dash.', 'it-l10n-backupbuddy') . ' ' . $bucket_requirements; } require_once dirname(__FILE__) . '/lib/s3/s3.php'; $s3 = new S3($accesskey, $secretkey); if ($ssl != '1') { S3::$useSSL = false; } if ($s3->getBucketLocation($bucket) === false) { // Easy way to see if bucket already exists. $s3->putBucket($bucket, S3::ACL_PRIVATE); } if (!empty($directory)) { $directory = $directory . '/'; } if ($s3->putObject(__('Upload test for BackupBuddy for Amazon S3', 'it-l10n-backupbuddy'), $bucket, $directory . 'backupbuddy.txt', S3::ACL_PRIVATE)) { // Success... just delete temp test file later... } else { return __('Unable to upload. Verify your keys, bucket name, and account permissions.', 'it-l10n-backupbuddy'); } if (!S3::deleteObject($bucket, $directory . 'backupbuddy.txt')) { return __('Partial success. Could not delete temp file.', 'it-l10n-backupbuddy'); } return true; // Success! }
static function validate_access_details($access_key, $secret_key, $bucket_name) { require_once MODPATH . "aws_s3/lib/s3.php"; S3::setAuth($access_key, $secret_key); S3::$useSSL = false; $success_test = S3::putObjectString((string) time(), $bucket_name, ".s3_test"); if ($success_test) { S3::deleteObject($bucket_name, ".s3_test"); } return $success_test; }