diff --git a/application/config/application.php b/application/config/application.php index 99360e8..19795f5 100644 --- a/application/config/application.php +++ b/application/config/application.php @@ -28,7 +28,7 @@ $config['archive_path'] = 'static/archives/'; # Where to send system alerts -$config['system_alert_email'] = 'cron@oconf.org'; +$config['system_alert_email'] = 'ohcrap@getsparks.org'; # The place to email when shit goes wrong $config['support_email'] = 'ohcrap@getsparks.org'; diff --git a/application/config/config.php b/application/config/config.php index c9d46e9..63b1991 100644 --- a/application/config/config.php +++ b/application/config/config.php @@ -6,6 +6,9 @@ # Use prod settings? (Super-caching, minifying, etc) $config['is_production'] = FALSE; +# Environment-specific for SES. Required for mailing. +$config['ses_secret_key'] = ''; +$config['ses_access_key'] = ''; /* |-------------------------------------------------------------------------- | Base Site URL diff --git a/application/helpers/mailer_helper.php b/application/helpers/mailer_helper.php new file mode 100644 index 0000000..41df068 --- /dev/null +++ b/application/helpers/mailer_helper.php @@ -0,0 +1,73 @@ +load->view('email/spark_rejected', array('title' => $subject, + 'teaser' => 'Puts up a brick! Your spark submission couldn\'t be verified', + 'body' => nl2br($message)), + true); + + self::sendEmail($to, $subject, $content, $message, array('cc' => $sys_email)); + } + + /** + * Send a generic email without a fancy footer and header + * @param string $to + * @param string $subject + * @param string $body + * @param string $teaser Optional. Appears as a teaser in some email clients + */ + public static function sendEmail($to, $subject, $content, $alt = false, $options = array()) + { + $CI = &get_instance(); + $CI->load->spark('amazon-ses/0.3.0'); + + # Main recipient + if(is_array($to)) + { + foreach($to as $addr) + $CI->amazon_ses->to($addr); + } + else + { + $CI->amazon_ses->to($to); + } + + # CCs + if(isset($options['cc'])) + { + $cc = $options['cc']; + if(is_array($cc)) + { + foreach($cc as $addr) + $CI->amazon_ses->cc($addr); + } + else + { + $CI->amazon_ses->cc($cc); + } + } + + $CI->amazon_ses->subject($subject); + $CI->amazon_ses->message($content); + + if($alt) + $CI->amazon_ses->message_alt($alt); + + $CI->amazon_ses->send(); + } +} diff --git a/application/models/spark.php b/application/models/spark.php index 324756c..7ad7911 100755 --- a/application/models/spark.php +++ b/application/models/spark.php @@ -390,21 +390,23 @@ public function setVersionStatus($version, $deactivated = FALSE) */ public function removeTagAndNotify($tag, $errors) { - $this->load->helper('email'); + $this->load->helper('mailer'); $contrib = $this->getContributor(); $sys_email = config_item('system_alert_email'); $message = "Hey there, + This is an automated message to tell you that tag '$tag' of $this->name couldn't be verified ($this->base_location). We've removed that version from our system at getsparks. Once you get -things figured out on your end, you can re-add the version :). +things figured out on your end, you can re-add the version :) + Here are some specifics: \n\n"; foreach($errors as $error) $message .= "$error\n"; - send_email("{$contrib->email},{$sys_email}", "{$this->name} {$tag} Removed.", $message); + MailerHelper::sendSparkRejection($contrib->email, "{$this->name} {$tag}", $message); $this->db->where('spark_id', $this->id); $this->db->where('tag', $tag); diff --git a/application/views/email/global/_footer.php b/application/views/email/global/_footer.php new file mode 100644 index 0000000..5f3cf75 --- /dev/null +++ b/application/views/email/global/_footer.php @@ -0,0 +1,26 @@ + + + + + + + + +
+ + + + +
+ +
+
+ Copyright © 2011 GetSparks.org, All rights reserved. +
+
+
+ + + diff --git a/application/views/email/global/_header.php b/application/views/email/global/_header.php new file mode 100644 index 0000000..a2c0382 --- /dev/null +++ b/application/views/email/global/_header.php @@ -0,0 +1,39 @@ + + +
+
+ + +
+ + + + + + +
+
+
+
+
+ Code less, drink more. +
+
+
+ + +
+ + + + + GetSparks + GetSparks Notification +
+ +
+ + +
+
+

\ No newline at end of file diff --git a/application/views/email/spark_rejected.php b/application/views/email/spark_rejected.php new file mode 100644 index 0000000..a7aa0df --- /dev/null +++ b/application/views/email/spark_rejected.php @@ -0,0 +1,5 @@ +load->view('email/global/_header', array('teaser' => $teaser, 'title' => $title)) ?> + + + +load->view('email/global/_footer', array()) ?> \ No newline at end of file diff --git a/certs/cert-5BCYACB2LWU32QMPCR7A5RSRMA7OIYS7.pem b/certs/cert-5BCYACB2LWU32QMPCR7A5RSRMA7OIYS7.pem new file mode 100644 index 0000000..657f81a --- /dev/null +++ b/certs/cert-5BCYACB2LWU32QMPCR7A5RSRMA7OIYS7.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICdjCCAd+gAwIBAgIFZ89N7LQwDQYJKoZIhvcNAQEFBQAwUzELMAkGA1UEBhMC +VVMxEzARBgNVBAoTCkFtYXpvbi5jb20xDDAKBgNVBAsTA0FXUzEhMB8GA1UEAxMY +QVdTIExpbWl0ZWQtQXNzdXJhbmNlIENBMB4XDTExMTIzMTE1MzI1MFoXDTEyMTIz +MDE1MzI1MFowUjELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkFtYXpvbi5jb20xFzAV +BgNVBAsTDkFXUy1EZXZlbG9wZXJzMRUwEwYDVQQDEww3eTF1eGt5dWNhYzUwgZ8w +DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM3gSj4cZeCyMJgVM9E5bosVMxOfF8N9 +mYwmWR6+v4aA4FoWGimY7Yfu+zLxL0T40JKjJzfWrr/Ekt5fs6T/xI9TI71mQwo0 +O0WFKhsQO1dgHPiZHxt1IoY5jmUFrjDM2DzU352l+mjmd2ZMsq6huXtcHSAXeJvz +77Ets4gF8QTXAgMBAAGjVzBVMA4GA1UdDwEB/wQEAwIFoDAWBgNVHSUBAf8EDDAK +BggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRNspaK2hyWOYJ7F8U6 +y+6wCZ2fTDANBgkqhkiG9w0BAQUFAAOBgQBPxVOQllyx2CL636Ap6klvSc5dPvpk +uZwuj08wuuSRHbIgwfvJmKzPRbDAO9DKd19vsjR+pfmzq8r/6LywCetSKHy6mHRU +Z2an5Cmdekjh26vAbJctFtjITDoJG28MI4uCHBi8fkuYgX/sjEAXBG2+ZKP54cQu +iKL2CJkNBWgGog== +-----END CERTIFICATE----- diff --git a/certs/index.html b/certs/index.html new file mode 100644 index 0000000..e69de29 diff --git a/sparks/amazon-ses/0.3.0/.gitignore b/sparks/amazon-ses/0.3.0/.gitignore new file mode 100644 index 0000000..9074e23 --- /dev/null +++ b/sparks/amazon-ses/0.3.0/.gitignore @@ -0,0 +1 @@ +config/amazon_ses_real.php \ No newline at end of file diff --git a/sparks/amazon-ses/0.3.0/CHANGELOG.md b/sparks/amazon-ses/0.3.0/CHANGELOG.md new file mode 100644 index 0000000..155c4b8 --- /dev/null +++ b/sparks/amazon-ses/0.3.0/CHANGELOG.md @@ -0,0 +1,8 @@ +Changelog +========= +This log includes all changes to the public API of this library. Check the project's commit history for a more detailed look and for changes that impact the internals of this library. + +v0.3 +---- +* Added support for a vanity 'from' name. This can be set using the second parameter in the 'from' method or setting the 'amazon_ses_from_name' config parameter. +* Added an extra check to overcome conflicting certificates. Thanks Stephen Frank. \ No newline at end of file diff --git a/sparks/amazon-ses/0.3.0/LICENSE.md b/sparks/amazon-ses/0.3.0/LICENSE.md new file mode 100644 index 0000000..1bc3c75 --- /dev/null +++ b/sparks/amazon-ses/0.3.0/LICENSE.md @@ -0,0 +1,19 @@ +Copyright (c) 2011 Joël Cox and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/sparks/amazon-ses/0.3.0/README.md b/sparks/amazon-ses/0.3.0/README.md new file mode 100644 index 0000000..d4f84a4 --- /dev/null +++ b/sparks/amazon-ses/0.3.0/README.md @@ -0,0 +1,97 @@ +CodeIgniter Amazon SES +====================== +A CodeIgniter library to interact with Amazon Web Services (AWS) Simple Email Service (SES). This library was designed with the standard CodeIgniter email class in mind. As a result, most methods look the same, ensuring a minimal learning curve. + +NOTE: this code is still under heavy development and currently provides only the very basics of the AWS SES API (don't you like acronyms?), sending email. + +Requirements +------------ +1. PHP 5.1+ +2. [CodeIgniter 2.0+](http://codeigniter.com) +3. libcurl with OpenSSL support +4. Phil Sturgeon's CodeIgniter [cURL library](http://github.com/philsturgeon/codeigniter-curl) +5. A bundle of public root certificates (e.g. http://curl.haxx.se/ca/cacert.pem) +6. An [Amazon Web Services account](http://aws.amazon.com) + +Spark +------------- +This library is also released as a [Spark](http://getsparks.org). If you use this library in any other way, **don't copy the autoload.php to your config directory**. + +Documentation +------------- + +### Configuration +This library expects a configuration file to function correctly. A template for this file is provided with the library. + +### Verify email address +Before you can send your first message, Amazon SES requires that you verify your email address. This is to confirm that you own the email address, and to prevent others from using it. + +Request to verify your email address as a sender. + + $this->amazon_ses->verify_address('from@example.com'); + +Check whether a email address is verified as a sender. + + $this->amazon_ses->address_is_verified('from@example.com'); + +### Recipients + +Set the "To" address(es) for a message. + + $this->amazon_ses->to('to1@example.com'); + +Set the "CC" address(es) (carbon copy) for a message. + + $this->amazon_ses->cc('cc1@example.com, cc2@example.com'); + +Set the "BCC" address(es) (blind carbon copy) for a message. + + $this->amazon_ses->bcc(array('bcc1@example.com', 'bcc2@example.com', 'bcc3@example.com')); + +These three methods expect valid e-mail addresses as a string, array or comma separated list. + +###Message + +Set the sender address. You can also set this in your config file. The second parameter - the vanity name of the sender - is optional. + + $this->amazon_ses->from('do_reply@example.com', 'Email monkey'); + +Set the subject for a message. + + $this->amazon_ses->subject('Open me!'); + +Set the message to be sent. + + $this->amazon_ses->message('Use HTML'); + +Set the alternative message (plain-text) to be sent. When not specified, an alternative message is generated by using PHP's strip_tags() function. + + $this->amazon_ses->message_alt('No HTML?!'); + +Sends the message. Returns true on success. + + $this->amazon_ses->send(); + +NOTE: All methods above are chainable, which means you can do the following + + $this->amazon_ses->to('email@example.com')->subject('Yo!')->message('Sup dawg')->send(); + +###Misc + +Sends the message in debug mode. In debug mode, the send() methods returns the actual API response instead of a boolean. Call this method before calling the send method. + + $this->amazon_ses->debug(TRUE); + +Preserves recipient after the message has been successfully send. When you call this method, all recipients will be preserved during the objects life. This makes it possible to sent an additional message without re-specifying the recipients. + + $this->amazon_ses->destroy(); + +Contributing +------------ +I am a firm believer of social coding, so if when you find a bug, please fork my code on [GitHub](http://github.com/joelcox/codeigniter-amazon-ses) and squash it. I will be happy to merge it back in to the code base (and add you to the "Thanks to" section). If you're not too comfortable using Git or messing with the inner workings of this library, please [open a new issue](http://github.com/joelcox/codeigniter-amazon-ses/issues). + +Thanks to +--------- +* [Phil Sturgeon](http://philsturgeon.co.uk), for creating the CodeIgniter [cURL library](http://github.com/philsturgeon/codeigniter-curl) and thus taking care of all the cURL hassle. +* [Ben Hartard](http://github.com/bhartard), for adding the email verification method. +* [Stephen Frank](https://github.com/stephenfrank), for sorting out SSL conflict issues. \ No newline at end of file diff --git a/sparks/amazon-ses/0.3.0/config/amazon_ses.php b/sparks/amazon-ses/0.3.0/config/amazon_ses.php new file mode 100644 index 0000000..4337b46 --- /dev/null +++ b/sparks/amazon-ses/0.3.0/config/amazon_ses.php @@ -0,0 +1,21 @@ +load->spark('amazon-ses/dev'); + $this->load->library('unit_test'); + + // Make sure we're running in strict test mode + $this->unit->use_strict(TRUE); + + // Check if the config is loaded correctly + $this->unit->run($this->amazon_ses->from, 'is_string', 'Configuration file loaded', 'Since most config variables are protected, we only test $from and assume other config variables are in the same state.'); + + // Set from address + $this->amazon_ses->from('test@example.com'); + $this->unit->run($this->amazon_ses->from, 'test@example.com', 'Set from address', '-'); + + // Set invalid from address + $this->amazon_ses->from('test2example.com'); + $this->unit->run($this->amazon_ses->from, 'test@example.com', 'Set invalid from address', 'Because we provided an invalid address, the previously set address is still set.'); + + // Set to + $receipients = 'test@example.com'; + $this->amazon_ses->to($receipients); + $this->unit->run($this->amazon_ses->recipients['to'][0], 'test@example.com', 'Set to address (single)', '-'); + + // Set invalid to + $receipients = 'test2example.com'; + $this->amazon_ses->to($receipients); + $this->unit->run($this->amazon_ses->recipients['to'][1], 'is_null', 'Set invalid to address (single)', '-'); + + // Set to in comma list + $receipients = 'test1@example.com, test2@example.com'; + $this->amazon_ses->to($receipients); + $this->unit->run($this->amazon_ses->recipients['to'][1], 'test1@example.com', 'Set to address (comma separeted) (1)', '-'); + $this->unit->run($this->amazon_ses->recipients['to'][2], 'test2@example.com', 'Set to address (comma separeted) (2)', '-'); + + // Set to in array + $receipients = array('test3@example.com', 'test4@example.com'); + $this->amazon_ses->to($receipients); + $this->unit->run($this->amazon_ses->recipients['to'][3], 'test3@example.com', 'Set to address (array) (3)', '-'); + $this->unit->run($this->amazon_ses->recipients['to'][4], 'test4@example.com', 'Set to address (array) (4)', '-'); + + // Set subject + $this->amazon_ses->subject('Subject'); + $this->unit->run($this->amazon_ses->subject, 'Subject', 'Set message subject', '-'); + + // Display all results + echo $this->unit->report(); + + } + +} \ No newline at end of file diff --git a/sparks/amazon-ses/0.3.0/libraries/Amazon_ses.php b/sparks/amazon-ses/0.3.0/libraries/Amazon_ses.php new file mode 100644 index 0000000..afd42f5 --- /dev/null +++ b/sparks/amazon-ses/0.3.0/libraries/Amazon_ses.php @@ -0,0 +1,470 @@ +_ci =& get_instance(); + + // Load all config items + $this->_ci->load->config('amazon_ses'); + $this->_access_key = $this->_ci->config->item('amazon_ses_access_key'); + $this->_secret_key = $this->_ci->config->item('amazon_ses_secret_key'); + $this->_cert_path = $this->_ci->config->item('amazon_ses_cert_path'); + $this->from = $this->_ci->config->item('amazon_ses_from'); + $this->from_name = $this->_ci->config->item('amazon_ses_from_name'); + $this->charset = $this->_ci->config->item('amazon_ses_charset'); + + // Check whether reply_to is not set + if ($this->_ci->config->item('reply_to') === FALSE) + { + $this->reply_to = $this->_ci->config->item('amazon_ses_from'); + } + else + { + $this->reply_to = $this->_ci->config->item('amazon_ses_reply_to'); + } + + // Is our certificate path valid? + if ( ! file_exists($this->_cert_path)) + { + show_error('CA root certificates not found. Please download a bundle of public root certificates and/or specify its location in config/amazon_ses.php'); + } + + // Load Phil's cURL library as a Spark or the normal way + if (method_exists($this->_ci->load, 'spark')) + { + $this->_ci->load->spark('curl/1.0.0'); + } + + $this->_ci->load->library('curl'); + } + + /** + * Sets the from address + * @param string email address the message is from + * @param string vanity name from which the message is sent + * @return mixed + */ + public function from($from, $name = FALSE) + { + + $this->_ci->load->helper('email'); + + if ($name) + { + $this->from_name = $name; + } + + if (valid_email($from)) + { + $this->from = $from; + return $this; + } + else + { + log_message('debug', 'From address is not valid'); + return FALSE; + } + } + + /** + * Sets the to address + * @param string to email address + * @return mixed + */ + public function to($to) + { + $this->_add_address($to, 'to'); + return $this; + } + + /** + * Sets the cc address + * @param string cc email address + * @return mixed + */ + public function cc($cc) + { + $this->_add_address($cc, 'cc'); + return $this; + } + + /** + * Sets the bcc address + * @param string bcc email address + * @return mixed + */ + public function bcc($bcc) + { + $this->_add_address($bcc, 'bcc'); + return $this; + } + + /** + * Sets the email subject + * @param string the subject + * @return mixed + */ + public function subject($subject) + { + $this->subject = $subject; + return $this; + } + + /** + * Sets the message + * @param string the message to be sent + * @return mixed + */ + public function message($message) + { + $this->message = $message; + return $this; + } + + /** + * Sets the alternative message (plain-text) for when HTML email is not supported by email client + * @param string the alternative message to be sent + * @return mixed + */ + public function message_alt($message_alt) + { + $this->message_alt = $message_alt; + return $this; + } + + /** + * Sends off the email + * @param bool whether to empty the recipients array on success + * @return bool + */ + public function send($destroy = TRUE) + { + + // Create the message query string + $query_string = $this->_format_query_string(); + + // Pass it to the Amazon API + $response = $this->_api_request($query_string); + + // Destroy recipients if set + if ($destroy === TRUE) + { + unset($this->recipients); + } + + return $response; + + } + + /** + * Verifies a from address as a valid sender + * @link http://docs.amazonwebservices.com/ses/latest/GettingStartedGuide/index.html?VerifyEmailAddress.html + * @param string email address to verify as a sender + * @return bool + * @author Ben Hartard + */ + public function verify_address($address) + { + + // Prep our query string + $query_string = array( + 'Action' => 'VerifyEmailAddress', + 'EmailAddress' => $address + ); + + // Hand it off to Amazon + return $this->_api_request($query_string); + + } + + /** + * Checks whether the supplied email address is verified + * @param string email address to be checked + * @return bool + */ + public function address_is_verified($address) + { + // Prep our query string + $query_string = array( + 'Action' => 'ListVerifiedEmailAddresses' + ); + + // Get our list with verified addresses + $response = $this->_api_request($query_string, TRUE); + + // Just return the text response when we're in debug mode + if ($this->debug === TRUE) + { + return $response; + } + + // We don't want to introduce another dependency (a XML parser) + // so we just check if the address is present in the response + // instead of returning an array with all addresses + if (strpos($response, $address) === FALSE) + { + return FALSE; + } + else + { + return TRUE; + } + + } + + /** + * Sets debug mode + * Makes send return the actual API response instead of a bool + * @return void + */ + public function debug($bool) + { + $this->debug = (bool) $bool; + } + + private function _add_address($address, $type) + { + + $this->_ci->load->helper('email'); + + // Take care of arrays and comma delimitered lists + if ( ! $this->_format_addresses($address, $type)) + { + $this->_ci->load->helper('email'); + + if (valid_email($address)) + { + $this->recipients[$type][] = $address; + } + else + { + log_message('debug', ucfirst($type) . ' e-mail address is not valid'); + return FALSE; + } + + } + + } + + /** + * Formats arrays and comma delimertered lists + * @param mixed the list with addresses + * @param string recipient type (i.e. to, cc, bcc) + */ + private function _format_addresses($addresses, $type) + { + // Make sure we're dealing with a proper type + if (in_array($type, array('to', 'cc', 'bcc'), TRUE) === FALSE) + { + log_message('debug', 'Unknow type queue.'); + return FALSE; + } + + // Check if the input is an array + if (is_array($addresses)) + { + foreach ($addresses as $address) + { + $this->{$type}($address); + } + + return TRUE; + } + // Check if we're dealing with a comma seperated list + elseif (strpos($addresses, ', ') !== FALSE) + { + + // Write each element + $addresses = explode(', ', $addresses); + + foreach ($addresses as $address) + { + $this->{$type}($address); + } + + return TRUE; + + } + else + { + + return FALSE; + + } + } + + /** + * Generates the query string for email + * @return array + */ + private function _format_query_string() + { + $query_string = array( + 'Action' => 'SendEmail', + 'Source' => ($this->from_name ? $this->from_name . ' <' . $this->from . '>' : $this->from), + 'Message.Subject.Data' => $this->subject, + 'Message.Body.Text.Data' => (empty($this->message_alt) ? strip_tags($this->message) : $this->message_alt), + 'Message.Body.Html.Data' => $this->message + ); + + // Add all recipients to array + if (isset($this->recipients['to'])) + { + for ($i = 0; $i < count($this->recipients['to']); $i++) + { + $query_string['Destination.ToAddresses.member.' . ($i + 1)] = $this->recipients['to'][$i]; + } + } + + if (isset($this->recipients['cc'])) + { + for ($i = 0; $i < count($this->recipients['cc']); $i++) + { + $query_string['Destination.CcAddresses.member.' . ($i + 1)] = $this->recipients['cc'][$i]; + } + } + + if (isset($this->recipients['bcc'])) + { + for ($i = 0; $i < count($this->recipients['bcc']); $i++) + { + $query_string['Destination.BccAddresses.member.' . ($i + 1)] = $this->recipients['bcc'][$i]; + } + } + + // Add character encoding if set + if ( ! empty($this->charset)) + { + $query_string['Message.Body.Html.Charset'] = $this->charset; + $query_string['Message.Body.Text.Charset'] = $this->charset; + $query_string['Message.Subject.Charset'] = $this->charset; + } + + return $query_string; + + } + + /** + * Generates the X-Amzn headers + * @return string headers including signed signature + */ + private function _set_headers() + { + $date = date(DATE_RSS); + $signature = $this->_sign_signature($date); + + $this->_ci->curl->http_header('Content-Type', 'application/x-www-form-urlencoded'); + $this->_ci->curl->http_header('Date', $date); + $this->_ci->curl->http_header('X-Amzn-Authorization', 'AWS3-HTTPS AWSAccessKeyId=' . $this->_access_key . ', Algorithm=HmacSHA256, Signature=' . $signature); + + } + + /** + * Calculate signature + * @param string date used in the header + * @return string RFC 2104-compliant HMAC hash + */ + private function _sign_signature($date) + { + + $hash = hash_hmac('sha256', $date, $this->_secret_key, TRUE); + + return base64_encode($hash); + } + + /** + * Generates API endpoint + * @return string URL to the SES endpoint for the region + */ + private function _endpoint() + { + return 'https://email.' . $this->region . '.amazonaws.com'; + } + + /** + * Send a request to the Amazon SES API using Phil's cURL lib + * @param arra query parameters that have to be added + * @param bool return the actual response + * @return mixed + */ + private function _api_request($query_string, $return = FALSE) + { + + // Set the endpoint + $this->_ci->curl->create($this->_endpoint()); + + $this->_ci->curl->post($query_string); + $this->_set_headers(); + + // Make sure we connect over HTTPS and verify + if( ! isset($_SERVER['HTTPS'])) + { + $this->_ci->curl->ssl(TRUE, 2, $this->_cert_path); + } + + // Show headers when in debug mode + if($this->debug === TRUE) + { + $this->_ci->curl->option(CURLOPT_FAILONERROR, FALSE); + $this->_ci->curl->option(CURLINFO_HEADER_OUT, TRUE); + } + + $response = $this->_ci->curl->execute(); + + // Return the actual response when in debug or if requested specifically + if($this->debug === TRUE OR $return === TRUE) + { + return $response; + } + + // Check if everything went okay + if ($response === FALSE) + { + log_message('debug', 'API request failed.'); + return FALSE; + } + else + { + return TRUE; + } + + } + +} \ No newline at end of file diff --git a/sparks/amazon-ses/0.3.0/spark.info b/sparks/amazon-ses/0.3.0/spark.info new file mode 100644 index 0000000..b84862a --- /dev/null +++ b/sparks/amazon-ses/0.3.0/spark.info @@ -0,0 +1,7 @@ +# Spark spec +name: amazon-ses +version: 0.2.2 +compatibility: 2.0.0 +dependencies: + curl: 1.0.0 +tags: ["email", "amazon", "ses", "aws", "cloud", "service"] \ No newline at end of file diff --git a/sparks/curl/1.0.0/.hgtags b/sparks/curl/1.0.0/.hgtags new file mode 100644 index 0000000..3ae7268 --- /dev/null +++ b/sparks/curl/1.0.0/.hgtags @@ -0,0 +1 @@ +899c0e325057c5c168463b593571a16662a98059 1.0 diff --git a/sparks/curl/1.0.0/README.markdown b/sparks/curl/1.0.0/README.markdown new file mode 100644 index 0000000..568fa3b --- /dev/null +++ b/sparks/curl/1.0.0/README.markdown @@ -0,0 +1,24 @@ +CodeIgniter-cURL +================ + +CodeIgniter-cURL is a CodeIgniter library which makes it easy to do simple cURL requests +and makes more complicated cURL requests easier too. + + +Requirements +------------ + +1. PHP 5.1+ +2. CodeIgniter 1.7.x - 2.0-dev +3. PHP 5 (configured with cURL enabled) +4. libcurl + +Usage +----- + + echo $this->curl->simple_get('http://example.com/'); + echo $this->curl->simple_post('curl_test/message', array('message'=>'Sup buddy')); + +For more up to date usage and in-depth examples check the CodeIgniter wiki page: + +http://codeigniter.com/wiki/Curl_library/ \ No newline at end of file diff --git a/sparks/curl/1.0.0/libraries/Curl.php b/sparks/curl/1.0.0/libraries/Curl.php new file mode 100644 index 0000000..f7f6125 --- /dev/null +++ b/sparks/curl/1.0.0/libraries/Curl.php @@ -0,0 +1,357 @@ +_ci = & get_instance(); + log_message('debug', 'cURL Class Initialized'); + + if (!$this->is_enabled()) + { + log_message('error', 'cURL Class - PHP was not built with cURL enabled. Rebuild PHP with --with-curl to use cURL.'); + } + + $url AND $this->create($url); + } + + function __call($method, $arguments) + { + if (in_array($method, array('simple_get', 'simple_post', 'simple_put', 'simple_delete'))) + { + // Take off the "simple_" and past get/post/put/delete to _simple_call + $verb = str_replace('simple_', '', $method); + array_unshift($arguments, $verb); + return call_user_func_array(array($this, '_simple_call'), $arguments); + } + } + + /* ================================================================================= + * SIMPLE METHODS + * Using these methods you can make a quick and easy cURL call with one line. + * ================================================================================= */ + + // Return a get request results + public function _simple_call($method, $url, $params = array(), $options = array()) + { + // If a URL is provided, create new session + $this->create($url); + + $this->{$method}($params, $options); + + // Add in the specific options provided + $this->options($options); + + return $this->execute(); + } + + public function simple_ftp_get($url, $file_path, $username = '', $password = '') + { + // If there is no ftp:// or any protocol entered, add ftp:// + if (!preg_match('!^(ftp|sftp)://! i', $url)) + { + $url = 'ftp://' . $url; + } + + // Use an FTP login + if ($username != '') + { + $auth_string = $username; + + if ($password != '') + { + $auth_string .= ':' . $password; + } + + // Add the user auth string after the protocol + $url = str_replace('://', '://' . $auth_string . '@', $url); + } + + // Add the filepath + $url .= $file_path; + + $this->option(CURLOPT_BINARYTRANSFER, TRUE); + $this->option(CURLOPT_VERBOSE, TRUE); + + return $this->execute(); + } + + /* ================================================================================= + * ADVANCED METHODS + * Use these methods to build up more complex queries + * ================================================================================= */ + + public function post($params = array(), $options = array()) + { + // If its an array (instead of a query string) then format it correctly + if (is_array($params)) + { + $params = http_build_query($params, NULL, '&'); + } + + // Add in the specific options provided + $this->options($options); + + $this->http_method('post'); + + $this->option(CURLOPT_POST, TRUE); + $this->option(CURLOPT_POSTFIELDS, $params); + } + + public function put($params = array(), $options = array()) + { + // If its an array (instead of a query string) then format it correctly + if (is_array($params)) + { + $params = http_build_query($params, NULL, '&'); + } + + // Add in the specific options provided + $this->options($options); + + $this->http_method('put'); + $this->option(CURLOPT_POSTFIELDS, $params); + + // Override method, I think this overrides $_POST with PUT data but... we'll see eh? + $this->option(CURLOPT_HTTPHEADER, array('X-HTTP-Method-Override: PUT')); + } + + public function delete($params, $options = array()) + { + // If its an array (instead of a query string) then format it correctly + if (is_array($params)) + { + $params = http_build_query($params, NULL, '&'); + } + + // Add in the specific options provided + $this->options($options); + + $this->http_method('delete'); + + $this->option(CURLOPT_POSTFIELDS, $params); + } + + public function set_cookies($params = array()) + { + if (is_array($params)) + { + $params = http_build_query($params, NULL, '&'); + } + + $this->option(CURLOPT_COOKIE, $params); + return $this; + } + + public function http_header($header, $content = NULL) + { + $this->headers[] = $content ? $header . ': ' . $content : $header; + } + + public function http_method($method) + { + $this->options[CURLOPT_CUSTOMREQUEST] = strtoupper($method); + return $this; + } + + public function http_login($username = '', $password = '', $type = 'any') + { + $this->option(CURLOPT_HTTPAUTH, constant('CURLAUTH_' . strtoupper($type))); + $this->option(CURLOPT_USERPWD, $username . ':' . $password); + return $this; + } + + public function proxy($url = '', $port = 80) + { + $this->option(CURLOPT_HTTPPROXYTUNNEL, TRUE); + $this->option(CURLOPT_PROXY, $url . ':' . $port); + return $this; + } + + public function proxy_login($username = '', $password = '') + { + $this->option(CURLOPT_PROXYUSERPWD, $username . ':' . $password); + return $this; + } + + public function ssl($verify_peer = TRUE, $verify_host = 2, $path_to_cert = NULL) + { + if ($verify_peer) + { + $this->option(CURLOPT_SSL_VERIFYPEER, TRUE); + $this->option(CURLOPT_SSL_VERIFYHOST, $verify_host); + $this->option(CURLOPT_CAINFO, $path_to_cert); + } + else + { + $this->option(CURLOPT_SSL_VERIFYPEER, FALSE); + } + return $this; + } + + public function options($options = array()) + { + // Merge options in with the rest - done as array_merge() does not overwrite numeric keys + foreach ($options as $option_code => $option_value) + { + $this->option($option_code, $option_value); + } + + // Set all options provided + curl_setopt_array($this->session, $this->options); + + return $this; + } + + public function option($code, $value) + { + if (is_string($code) && !is_numeric($code)) + { + $code = constant('CURLOPT_' . strtoupper($code)); + } + + $this->options[$code] = $value; + return $this; + } + + // Start a session from a URL + public function create($url) + { + // Reset the class + $this->set_defaults(); + + // If no a protocol in URL, assume its a CI link + if (!preg_match('!^\w+://! i', $url)) + { + $this->_ci->load->helper('url'); + $url = site_url($url); + } + + $this->url = $url; + $this->session = curl_init($this->url); + + return $this; + } + + // End a session and return the results + public function execute() + { + // Set two default options, and merge any extra ones in + if (!isset($this->options[CURLOPT_TIMEOUT])) + $this->options[CURLOPT_TIMEOUT] = 30; + if (!isset($this->options[CURLOPT_RETURNTRANSFER])) + $this->options[CURLOPT_RETURNTRANSFER] = TRUE; + if (!isset($this->options[CURLOPT_FAILONERROR])) + $this->options[CURLOPT_FAILONERROR] = TRUE; + + // Only set follow location if not running securely + if (!ini_get('safe_mode') && !ini_get('open_basedir')) + { + // Ok, follow location is not set already so lets set it to true + if (!isset($this->options[CURLOPT_FOLLOWLOCATION])) + { + $this->options[CURLOPT_FOLLOWLOCATION] = TRUE; + } + } + + if (!empty($this->headers)) + { + $this->option(CURLOPT_HTTPHEADER, $this->headers); + } + + $this->options(); + + // Execute the request & and hide all output + $this->response = curl_exec($this->session); + $this->info = curl_getinfo($this->session); + + // Request failed + if ($this->response === FALSE) + { + $this->error_code = curl_errno($this->session); + $this->error_string = curl_error($this->session); + + curl_close($this->session); + $this->session = NULL; + return FALSE; + } + + // Request successful + else + { + curl_close($this->session); + $this->session = NULL; + return $this->response; + } + } + + public function is_enabled() + { + return function_exists('curl_init'); + } + + public function debug() + { + echo "=============================================
\n"; + echo "

CURL Test

\n"; + echo "=============================================
\n"; + echo "

Response

\n"; + echo "" . nl2br(htmlentities($this->response)) . "
\n\n"; + + if ($this->error_string) + { + echo "=============================================
\n"; + echo "

Errors

"; + echo "Code: " . $this->error_code . "
\n"; + echo "Message: " . $this->error_string . "
\n"; + } + + echo "=============================================
\n"; + echo "

Info

"; + echo "
";
+		print_r($this->info);
+		echo "
"; + } + + public function debug_request() + { + return array( + 'url' => $this->url + ); + } + + private function set_defaults() + { + $this->response = ''; + $this->info = array(); + $this->options = array(); + $this->error_code = 0; + $this->error_string = ''; + } + +} + +/* End of file Curl.php */ +/* Location: ./application/libraries/Curl.php */ \ No newline at end of file